Merge branch 'master' of https://github.com/okamstudio/godot
Conflicts: modules/gdscript/gd_tokenizer.cpp scene/resources/shader_graph.h
This commit is contained in:
commit
2c2894ceb6
151 changed files with 12123 additions and 954 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -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
|
||||
|
@ -258,3 +261,4 @@ Desktop.ini
|
|||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
logo.h
|
||||
*.autosave
|
||||
|
|
|
@ -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
|
||||
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(){
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -1778,6 +1778,11 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
|
|||
f->store_32(VERSION_MINOR);
|
||||
f->store_32(FORMAT_VERSION);
|
||||
|
||||
if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
|
||||
f->close();
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
//f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed
|
||||
save_unicode_string(p_resource->get_type());
|
||||
uint64_t md_at = f->get_pos();
|
||||
|
@ -1910,6 +1915,11 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
|
|||
|
||||
f->store_buffer((const uint8_t*)"RSRC",4); //magic at end
|
||||
|
||||
if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
|
||||
f->close();
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
f->close();
|
||||
|
||||
|
||||
|
|
|
@ -2592,6 +2592,11 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
|
|||
}
|
||||
|
||||
exit_tag("resource_file");
|
||||
if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
|
||||
f->close();
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
f->close();
|
||||
//memdelete(f);
|
||||
|
||||
|
|
56
core/list.h
56
core/list.h
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -121,7 +121,7 @@ void CameraMatrix::set_orthogonal(float p_size, float p_aspect, float p_znear, f
|
|||
|
||||
|
||||
void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, float p_top, float p_near, float p_far) {
|
||||
|
||||
#if 0
|
||||
///@TODO, give a check to this. I'm not sure if it's working.
|
||||
set_identity();
|
||||
|
||||
|
@ -133,10 +133,27 @@ void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, floa
|
|||
matrix[2][3]=-(2*p_far*p_near) / (p_far-p_near);
|
||||
matrix[3][2]=-1;
|
||||
matrix[3][3]=0;
|
||||
#else
|
||||
float *te = &matrix[0][0];
|
||||
float x = 2 * p_near / ( p_right - p_left );
|
||||
float y = 2 * p_near / ( p_top - p_bottom );
|
||||
|
||||
float a = ( p_right + p_left ) / ( p_right - p_left );
|
||||
float b = ( p_top + p_bottom ) / ( p_top - p_bottom );
|
||||
float c = - ( p_far + p_near ) / ( p_far - p_near );
|
||||
float d = - 2 * p_far * p_near / ( p_far - p_near );
|
||||
|
||||
te[0] = x; te[4] = 0; te[8] = a; te[12] = 0;
|
||||
te[1] = 0; te[5] = y; te[9] = b; te[13] = 0;
|
||||
te[2] = 0; te[6] = 0; te[10] = c; te[14] = d;
|
||||
te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
float CameraMatrix::get_z_far() const {
|
||||
|
||||
const float * matrix = (const float*)this->matrix;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -159,8 +159,8 @@ struct Vector2 {
|
|||
|
||||
operator String() const { return String::num(x)+","+String::num(y); }
|
||||
|
||||
inline Vector2(float p_x,float p_y) { x=p_x; y=p_y; }
|
||||
inline Vector2() { x=0; y=0; }
|
||||
_FORCE_INLINE_ Vector2(float p_x,float p_y) { x=p_x; y=p_y; }
|
||||
_FORCE_INLINE_ Vector2() { x=0; y=0; }
|
||||
};
|
||||
|
||||
_FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2& p_vec) const {
|
||||
|
@ -198,6 +198,8 @@ Vector2 Vector2::linear_interpolate(const Vector2& p_a, const Vector2& p_b,float
|
|||
typedef Vector2 Size2;
|
||||
typedef Vector2 Point2;
|
||||
|
||||
struct Matrix32;
|
||||
|
||||
|
||||
struct Rect2 {
|
||||
|
||||
|
@ -224,6 +226,8 @@ struct Rect2 {
|
|||
return true;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool intersects_transformed(const Matrix32& p_xform, const Rect2& p_rect) const;
|
||||
|
||||
bool intersects_segment(const Point2& p_from, const Point2& p_to, Point2* r_pos=NULL, Point2* r_normal=NULL) const;
|
||||
|
||||
inline bool encloses(const Rect2& p_rect) const {
|
||||
|
@ -597,6 +601,160 @@ struct Matrix32 {
|
|||
|
||||
};
|
||||
|
||||
bool Rect2::intersects_transformed(const Matrix32& p_xform, const Rect2& p_rect) const {
|
||||
|
||||
//SAT intersection between local and transformed rect2
|
||||
|
||||
Vector2 xf_points[4]={
|
||||
p_xform.xform(p_rect.pos),
|
||||
p_xform.xform(Vector2(p_rect.pos.x+p_rect.size.x,p_rect.pos.y)),
|
||||
p_xform.xform(Vector2(p_rect.pos.x,p_rect.pos.y+p_rect.size.y)),
|
||||
p_xform.xform(Vector2(p_rect.pos.x+p_rect.size.x,p_rect.pos.y+p_rect.size.y)),
|
||||
};
|
||||
|
||||
real_t low_limit;
|
||||
|
||||
//base rect2 first (faster)
|
||||
|
||||
if (xf_points[0].y>pos.y)
|
||||
goto next1;
|
||||
if (xf_points[1].y>pos.y)
|
||||
goto next1;
|
||||
if (xf_points[2].y>pos.y)
|
||||
goto next1;
|
||||
if (xf_points[3].y>pos.y)
|
||||
goto next1;
|
||||
|
||||
return false;
|
||||
|
||||
next1:
|
||||
|
||||
low_limit=pos.y+size.y;
|
||||
|
||||
if (xf_points[0].y<low_limit)
|
||||
goto next2;
|
||||
if (xf_points[1].y<low_limit)
|
||||
goto next2;
|
||||
if (xf_points[2].y<low_limit)
|
||||
goto next2;
|
||||
if (xf_points[3].y<low_limit)
|
||||
goto next2;
|
||||
|
||||
return false;
|
||||
|
||||
next2:
|
||||
|
||||
if (xf_points[0].x>pos.x)
|
||||
goto next3;
|
||||
if (xf_points[1].x>pos.x)
|
||||
goto next3;
|
||||
if (xf_points[2].x>pos.x)
|
||||
goto next3;
|
||||
if (xf_points[3].x>pos.x)
|
||||
goto next3;
|
||||
|
||||
return false;
|
||||
|
||||
next3:
|
||||
|
||||
low_limit=pos.x+size.x;
|
||||
|
||||
if (xf_points[0].x<low_limit)
|
||||
goto next4;
|
||||
if (xf_points[1].x<low_limit)
|
||||
goto next4;
|
||||
if (xf_points[2].x<low_limit)
|
||||
goto next4;
|
||||
if (xf_points[3].x<low_limit)
|
||||
goto next4;
|
||||
|
||||
return false;
|
||||
|
||||
next4:
|
||||
|
||||
Vector2 xf_points2[4]={
|
||||
pos,
|
||||
Vector2(pos.x+size.x,pos.y),
|
||||
Vector2(pos.x,pos.y+size.y),
|
||||
Vector2(pos.x+size.x,pos.y+size.y),
|
||||
};
|
||||
|
||||
real_t maxa=p_xform.elements[0].dot(xf_points2[0]);
|
||||
real_t mina=maxa;
|
||||
|
||||
real_t dp = p_xform.elements[0].dot(xf_points2[1]);
|
||||
maxa=MAX(dp,maxa);
|
||||
mina=MIN(dp,mina);
|
||||
|
||||
dp = p_xform.elements[0].dot(xf_points2[2]);
|
||||
maxa=MAX(dp,maxa);
|
||||
mina=MIN(dp,mina);
|
||||
|
||||
dp = p_xform.elements[0].dot(xf_points2[3]);
|
||||
maxa=MAX(dp,maxa);
|
||||
mina=MIN(dp,mina);
|
||||
|
||||
real_t maxb=p_xform.elements[0].dot(xf_points[0]);
|
||||
real_t minb=maxb;
|
||||
|
||||
dp = p_xform.elements[0].dot(xf_points[1]);
|
||||
maxb=MAX(dp,maxb);
|
||||
minb=MIN(dp,minb);
|
||||
|
||||
dp = p_xform.elements[0].dot(xf_points[2]);
|
||||
maxb=MAX(dp,maxb);
|
||||
minb=MIN(dp,minb);
|
||||
|
||||
dp = p_xform.elements[0].dot(xf_points[3]);
|
||||
maxb=MAX(dp,maxb);
|
||||
minb=MIN(dp,minb);
|
||||
|
||||
|
||||
if ( mina > maxb )
|
||||
return false;
|
||||
if ( minb > maxa )
|
||||
return false;
|
||||
|
||||
maxa=p_xform.elements[1].dot(xf_points2[0]);
|
||||
mina=maxa;
|
||||
|
||||
dp = p_xform.elements[1].dot(xf_points2[1]);
|
||||
maxa=MAX(dp,maxa);
|
||||
mina=MIN(dp,mina);
|
||||
|
||||
dp = p_xform.elements[1].dot(xf_points2[2]);
|
||||
maxa=MAX(dp,maxa);
|
||||
mina=MIN(dp,mina);
|
||||
|
||||
dp = p_xform.elements[1].dot(xf_points2[3]);
|
||||
maxa=MAX(dp,maxa);
|
||||
mina=MIN(dp,mina);
|
||||
|
||||
maxb=p_xform.elements[1].dot(xf_points[0]);
|
||||
minb=maxb;
|
||||
|
||||
dp = p_xform.elements[1].dot(xf_points[1]);
|
||||
maxb=MAX(dp,maxb);
|
||||
minb=MIN(dp,minb);
|
||||
|
||||
dp = p_xform.elements[1].dot(xf_points[2]);
|
||||
maxb=MAX(dp,maxb);
|
||||
minb=MIN(dp,minb);
|
||||
|
||||
dp = p_xform.elements[1].dot(xf_points[3]);
|
||||
maxb=MAX(dp,maxb);
|
||||
minb=MIN(dp,minb);
|
||||
|
||||
|
||||
if ( mina > maxb )
|
||||
return false;
|
||||
if ( minb > maxa )
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
Vector2 Matrix32::basis_xform(const Vector2& v) const {
|
||||
|
||||
|
|
1550
core/math/triangulator.cpp
Normal file
1550
core/math/triangulator.cpp
Normal file
File diff suppressed because it is too large
Load diff
306
core/math/triangulator.h
Normal file
306
core/math/triangulator.h
Normal file
|
@ -0,0 +1,306 @@
|
|||
//Copyright (C) 2011 by Ivan Fratric
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in
|
||||
//all copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
//THE SOFTWARE.
|
||||
|
||||
#ifndef TRIANGULATOR_H
|
||||
#define TRIANGULATOR_H
|
||||
|
||||
#include "math_2d.h"
|
||||
#include "list.h"
|
||||
#include "set.h"
|
||||
//2D point structure
|
||||
|
||||
|
||||
#define TRIANGULATOR_CCW 1
|
||||
#define TRIANGULATOR_CW -1
|
||||
//Polygon implemented as an array of points with a 'hole' flag
|
||||
class TriangulatorPoly {
|
||||
protected:
|
||||
|
||||
|
||||
|
||||
Vector2 *points;
|
||||
long numpoints;
|
||||
bool hole;
|
||||
|
||||
public:
|
||||
|
||||
//constructors/destructors
|
||||
TriangulatorPoly();
|
||||
~TriangulatorPoly();
|
||||
|
||||
TriangulatorPoly(const TriangulatorPoly &src);
|
||||
TriangulatorPoly& operator=(const TriangulatorPoly &src);
|
||||
|
||||
//getters and setters
|
||||
long GetNumPoints() {
|
||||
return numpoints;
|
||||
}
|
||||
|
||||
bool IsHole() {
|
||||
return hole;
|
||||
}
|
||||
|
||||
void SetHole(bool hole) {
|
||||
this->hole = hole;
|
||||
}
|
||||
|
||||
Vector2 &GetPoint(long i) {
|
||||
return points[i];
|
||||
}
|
||||
|
||||
Vector2 *GetPoints() {
|
||||
return points;
|
||||
}
|
||||
|
||||
Vector2& operator[] (int i) {
|
||||
return points[i];
|
||||
}
|
||||
|
||||
//clears the polygon points
|
||||
void Clear();
|
||||
|
||||
//inits the polygon with numpoints vertices
|
||||
void Init(long numpoints);
|
||||
|
||||
//creates a triangle with points p1,p2,p3
|
||||
void Triangle(Vector2 &p1, Vector2 &p2, Vector2 &p3);
|
||||
|
||||
//inverts the orfer of vertices
|
||||
void Invert();
|
||||
|
||||
//returns the orientation of the polygon
|
||||
//possible values:
|
||||
// Triangulator_CCW : polygon vertices are in counter-clockwise order
|
||||
// Triangulator_CW : polygon vertices are in clockwise order
|
||||
// 0 : the polygon has no (measurable) area
|
||||
int GetOrientation();
|
||||
|
||||
//sets the polygon orientation
|
||||
//orientation can be
|
||||
// Triangulator_CCW : sets vertices in counter-clockwise order
|
||||
// Triangulator_CW : sets vertices in clockwise order
|
||||
void SetOrientation(int orientation);
|
||||
};
|
||||
|
||||
class TriangulatorPartition {
|
||||
protected:
|
||||
struct PartitionVertex {
|
||||
bool isActive;
|
||||
bool isConvex;
|
||||
bool isEar;
|
||||
|
||||
Vector2 p;
|
||||
real_t angle;
|
||||
PartitionVertex *previous;
|
||||
PartitionVertex *next;
|
||||
};
|
||||
|
||||
struct MonotoneVertex {
|
||||
Vector2 p;
|
||||
long previous;
|
||||
long next;
|
||||
};
|
||||
|
||||
struct VertexSorter{
|
||||
mutable MonotoneVertex *vertices;
|
||||
bool operator() (long index1, long index2) const;
|
||||
};
|
||||
|
||||
struct Diagonal {
|
||||
long index1;
|
||||
long index2;
|
||||
};
|
||||
|
||||
//dynamic programming state for minimum-weight triangulation
|
||||
struct DPState {
|
||||
bool visible;
|
||||
real_t weight;
|
||||
long bestvertex;
|
||||
};
|
||||
|
||||
//dynamic programming state for convex partitioning
|
||||
struct DPState2 {
|
||||
bool visible;
|
||||
long weight;
|
||||
List<Diagonal> pairs;
|
||||
};
|
||||
|
||||
//edge that intersects the scanline
|
||||
struct ScanLineEdge {
|
||||
mutable long index;
|
||||
Vector2 p1;
|
||||
Vector2 p2;
|
||||
|
||||
//determines if the edge is to the left of another edge
|
||||
bool operator< (const ScanLineEdge & other) const;
|
||||
|
||||
bool IsConvex(const Vector2& p1, const Vector2& p2, const Vector2& p3) const;
|
||||
};
|
||||
|
||||
//standard helper functions
|
||||
bool IsConvex(Vector2& p1, Vector2& p2, Vector2& p3);
|
||||
bool IsReflex(Vector2& p1, Vector2& p2, Vector2& p3);
|
||||
bool IsInside(Vector2& p1, Vector2& p2, Vector2& p3, Vector2 &p);
|
||||
|
||||
bool InCone(Vector2 &p1, Vector2 &p2, Vector2 &p3, Vector2 &p);
|
||||
bool InCone(PartitionVertex *v, Vector2 &p);
|
||||
|
||||
int Intersects(Vector2 &p11, Vector2 &p12, Vector2 &p21, Vector2 &p22);
|
||||
|
||||
Vector2 Normalize(const Vector2 &p);
|
||||
real_t Distance(const Vector2 &p1, const Vector2 &p2);
|
||||
|
||||
//helper functions for Triangulate_EC
|
||||
void UpdateVertexReflexity(PartitionVertex *v);
|
||||
void UpdateVertex(PartitionVertex *v,PartitionVertex *vertices, long numvertices);
|
||||
|
||||
//helper functions for ConvexPartition_OPT
|
||||
void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates);
|
||||
void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
|
||||
void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates);
|
||||
|
||||
//helper functions for MonotonePartition
|
||||
bool Below(Vector2 &p1, Vector2 &p2);
|
||||
void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2,
|
||||
char *vertextypes, Set<ScanLineEdge>::Element **edgeTreeIterators,
|
||||
Set<ScanLineEdge> *edgeTree, long *helpers);
|
||||
|
||||
//triangulates a monotone polygon, used in Triangulate_MONO
|
||||
int TriangulateMonotone(TriangulatorPoly *inPoly, List<TriangulatorPoly> *triangles);
|
||||
|
||||
public:
|
||||
|
||||
//simple heuristic procedure for removing holes from a list of polygons
|
||||
//works by creating a diagonal from the rightmost hole vertex to some visible vertex
|
||||
//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// inpolys : a list of polygons that can contain holes
|
||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||
// vertices of all hole polys have to be in clockwise order
|
||||
// outpolys : a list of polygons without holes
|
||||
//returns 1 on success, 0 on failure
|
||||
int RemoveHoles(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *outpolys);
|
||||
|
||||
//triangulates a polygon by ear clipping
|
||||
//time complexity O(n^2), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// poly : an input polygon to be triangulated
|
||||
// vertices have to be in counter-clockwise order
|
||||
// triangles : a list of triangles (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int Triangulate_EC(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);
|
||||
|
||||
//triangulates a list of polygons that may contain holes by ear clipping algorithm
|
||||
//first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon
|
||||
//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// inpolys : a list of polygons to be triangulated (can contain holes)
|
||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||
// vertices of all hole polys have to be in clockwise order
|
||||
// triangles : a list of triangles (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int Triangulate_EC(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles);
|
||||
|
||||
//creates an optimal polygon triangulation in terms of minimal edge length
|
||||
//time complexity: O(n^3), n is the number of vertices
|
||||
//space complexity: O(n^2)
|
||||
//params:
|
||||
// poly : an input polygon to be triangulated
|
||||
// vertices have to be in counter-clockwise order
|
||||
// triangles : a list of triangles (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int Triangulate_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);
|
||||
|
||||
//triangulates a polygons by firstly partitioning it into monotone polygons
|
||||
//time complexity: O(n*log(n)), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// poly : an input polygon to be triangulated
|
||||
// vertices have to be in counter-clockwise order
|
||||
// triangles : a list of triangles (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int Triangulate_MONO(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles);
|
||||
|
||||
//triangulates a list of polygons by firstly partitioning them into monotone polygons
|
||||
//time complexity: O(n*log(n)), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// inpolys : a list of polygons to be triangulated (can contain holes)
|
||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||
// vertices of all hole polys have to be in clockwise order
|
||||
// triangles : a list of triangles (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int Triangulate_MONO(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles);
|
||||
|
||||
//creates a monotone partition of a list of polygons that can contain holes
|
||||
//time complexity: O(n*log(n)), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// inpolys : a list of polygons to be triangulated (can contain holes)
|
||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||
// vertices of all hole polys have to be in clockwise order
|
||||
// monotonePolys : a list of monotone polygons (result)
|
||||
//returns 1 on success, 0 on failure
|
||||
int MonotonePartition(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *monotonePolys);
|
||||
|
||||
//partitions a polygon into convex polygons by using Hertel-Mehlhorn algorithm
|
||||
//the algorithm gives at most four times the number of parts as the optimal algorithm
|
||||
//however, in practice it works much better than that and often gives optimal partition
|
||||
//uses triangulation obtained by ear clipping as intermediate result
|
||||
//time complexity O(n^2), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// poly : an input polygon to be partitioned
|
||||
// vertices have to be in counter-clockwise order
|
||||
// parts : resulting list of convex polygons
|
||||
//returns 1 on success, 0 on failure
|
||||
int ConvexPartition_HM(TriangulatorPoly *poly, List<TriangulatorPoly> *parts);
|
||||
|
||||
//partitions a list of polygons into convex parts by using Hertel-Mehlhorn algorithm
|
||||
//the algorithm gives at most four times the number of parts as the optimal algorithm
|
||||
//however, in practice it works much better than that and often gives optimal partition
|
||||
//uses triangulation obtained by ear clipping as intermediate result
|
||||
//time complexity O(n^2), n is the number of vertices
|
||||
//space complexity: O(n)
|
||||
//params:
|
||||
// inpolys : an input list of polygons to be partitioned
|
||||
// vertices of all non-hole polys have to be in counter-clockwise order
|
||||
// vertices of all hole polys have to be in clockwise order
|
||||
// parts : resulting list of convex polygons
|
||||
//returns 1 on success, 0 on failure
|
||||
int ConvexPartition_HM(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *parts);
|
||||
|
||||
//optimal convex partitioning (in terms of number of resulting convex polygons)
|
||||
//using the Keil-Snoeyink algorithm
|
||||
//M. Keil, J. Snoeyink, "On the time bound for convex decomposition of simple polygons", 1998
|
||||
//time complexity O(n^3), n is the number of vertices
|
||||
//space complexity: O(n^3)
|
||||
// poly : an input polygon to be partitioned
|
||||
// vertices have to be in counter-clockwise order
|
||||
// parts : resulting list of convex polygons
|
||||
//returns 1 on success, 0 on failure
|
||||
int ConvexPartition_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *parts);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -62,6 +62,8 @@ void Input::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("set_mouse_mode","mode"),&Input::set_mouse_mode);
|
||||
ObjectTypeDB::bind_method(_MD("get_mouse_mode"),&Input::get_mouse_mode);
|
||||
ObjectTypeDB::bind_method(_MD("warp_mouse_pos","to"),&Input::warp_mouse_pos);
|
||||
ObjectTypeDB::bind_method(_MD("action_press"),&Input::action_press);
|
||||
ObjectTypeDB::bind_method(_MD("action_release"),&Input::action_release);
|
||||
|
||||
BIND_CONSTANT( MOUSE_MODE_VISIBLE );
|
||||
BIND_CONSTANT( MOUSE_MODE_HIDDEN );
|
||||
|
|
|
@ -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);
|
||||
|
|
37
core/set.h
37
core/set.h
|
@ -249,6 +249,37 @@ private:
|
|||
return (node!=_data._nil)?node:NULL;
|
||||
}
|
||||
|
||||
Element *_lower_bound(const T& p_value) const {
|
||||
|
||||
Element *node = _data._root->left;
|
||||
Element *prev = NULL;
|
||||
C less;
|
||||
|
||||
while(node!=_data._nil) {
|
||||
prev=node;
|
||||
|
||||
if (less(p_value,node->value))
|
||||
node=node->left;
|
||||
else if (less(node->value,p_value))
|
||||
node=node->right;
|
||||
else
|
||||
break; // found
|
||||
}
|
||||
|
||||
if (node==_data._nil) {
|
||||
if (prev==NULL)
|
||||
return NULL;
|
||||
if (less(prev->value,p_value)) {
|
||||
|
||||
prev=prev->_next;
|
||||
}
|
||||
|
||||
return prev;
|
||||
|
||||
} else
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
Element *_insert(const T& p_value, bool& r_exists) {
|
||||
|
||||
|
@ -582,6 +613,12 @@ public:
|
|||
|
||||
return e;
|
||||
}
|
||||
|
||||
Element *lower_bound(const T& p_value) const {
|
||||
|
||||
return _lower_bound(p_value);
|
||||
}
|
||||
|
||||
|
||||
inline int size() const { return _data.size_cache; }
|
||||
int calculate_depth() const {
|
||||
|
|
296
core/ustring.cpp
296
core/ustring.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -2631,8 +2631,13 @@ Variant Variant::call(const StringName& p_method,VARIANT_ARG_DECLARE) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void Variant::construct_from_string(const String& p_string,Variant& r_value,ObjectConstruct p_obj_construct,void *p_construct_ud) {
|
||||
|
||||
String Variant::get_construct_string() const {
|
||||
r_value=Variant();
|
||||
}
|
||||
|
||||
|
||||
String Variant::get_construct_string(ObjectDeConstruct p_obj_deconstruct,void *p_deconstruct_ud) const {
|
||||
|
||||
switch( type ) {
|
||||
|
||||
|
@ -2640,7 +2645,7 @@ String Variant::get_construct_string() const {
|
|||
case BOOL: return _data._bool ? "true" : "false";
|
||||
case INT: return String::num(_data._int);
|
||||
case REAL: return String::num(_data._real);
|
||||
case STRING: return "\""+*reinterpret_cast<const String*>(_data._mem)+"\"";
|
||||
case STRING: return "\""+reinterpret_cast<const String*>(_data._mem)->c_escape()+"\"";
|
||||
case VECTOR2: return "Vector2("+operator Vector2()+")";
|
||||
case RECT2: return "Rect2("+operator Rect2()+")";
|
||||
case MATRIX32: return "Matrix32("+operator Matrix32()+")";
|
||||
|
@ -2651,7 +2656,7 @@ String Variant::get_construct_string() const {
|
|||
case QUAT: return "Quat("+operator Quat()+")";
|
||||
case MATRIX3: return "Matrix3("+operator Matrix3()+")";
|
||||
case TRANSFORM: return "Transform("+operator Transform()+")";
|
||||
case NODE_PATH: return "@\""+operator NodePath()+"\"";
|
||||
case NODE_PATH: return "@\""+String(operator NodePath()).c_escape()+"\"";
|
||||
case INPUT_EVENT: return "InputEvent()";
|
||||
case COLOR: return "Color("+String::num( operator Color().r)+","+String::num( operator Color().g)+","+String::num( operator Color().b)+","+String::num( operator Color().a)+")" ;
|
||||
case DICTIONARY: {
|
||||
|
@ -2667,8 +2672,8 @@ String Variant::get_construct_string() const {
|
|||
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
|
||||
|
||||
_VariantStrPair sp;
|
||||
sp.key=E->get().get_construct_string();
|
||||
sp.value=d[E->get()].get_construct_string();
|
||||
sp.key=E->get().get_construct_string(p_obj_deconstruct,p_deconstruct_ud);
|
||||
sp.value=d[E->get()].get_construct_string(p_obj_deconstruct,p_deconstruct_ud);
|
||||
pairs.push_back(sp);
|
||||
}
|
||||
|
||||
|
@ -2686,50 +2691,50 @@ String Variant::get_construct_string() const {
|
|||
case VECTOR3_ARRAY: {
|
||||
|
||||
DVector<Vector3> vec = operator DVector<Vector3>();
|
||||
String str="[";
|
||||
String str="Vector3Array([";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str+=Variant( vec[i] ).get_construct_string();
|
||||
}
|
||||
return str+"]";
|
||||
return str+"])";
|
||||
} break;
|
||||
case STRING_ARRAY: {
|
||||
|
||||
DVector<String> vec = operator DVector<String>();
|
||||
String str="[";
|
||||
String str="StringArray([";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str=str+=Variant( vec[i] ).get_construct_string();
|
||||
}
|
||||
return str+"]";
|
||||
return str+"])";
|
||||
} break;
|
||||
case INT_ARRAY: {
|
||||
|
||||
DVector<int> vec = operator DVector<int>();
|
||||
String str="[";
|
||||
String str="IntArray([";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str=str+itos(vec[i]);
|
||||
}
|
||||
return str+"]";
|
||||
return str+"])";
|
||||
} break;
|
||||
case REAL_ARRAY: {
|
||||
|
||||
DVector<real_t> vec = operator DVector<real_t>();
|
||||
String str="[";
|
||||
String str="FloatArray([";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str=str+rtos(vec[i]);
|
||||
}
|
||||
return str+"]";
|
||||
return str+"])";
|
||||
} break;
|
||||
case ARRAY: {
|
||||
|
||||
|
@ -2738,16 +2743,20 @@ String Variant::get_construct_string() const {
|
|||
for (int i=0; i<arr.size(); i++) {
|
||||
if (i)
|
||||
str+=", ";
|
||||
str += arr[i].get_construct_string();
|
||||
str += arr[i].get_construct_string(p_obj_deconstruct,p_deconstruct_ud);
|
||||
};
|
||||
return str+"]";
|
||||
|
||||
} break;
|
||||
case OBJECT: {
|
||||
|
||||
if (_get_obj().obj)
|
||||
return _get_obj().obj->get_type()+".new()";
|
||||
else
|
||||
if (_get_obj().obj) {
|
||||
if (p_obj_deconstruct) {
|
||||
return "Object(\""+p_obj_deconstruct(Variant(*this),p_deconstruct_ud).c_escape()+")";
|
||||
} else {
|
||||
return _get_obj().obj->get_type()+".new()";
|
||||
}
|
||||
} else
|
||||
return "null";
|
||||
|
||||
} break;
|
||||
|
|
|
@ -419,7 +419,11 @@ public:
|
|||
static bool has_numeric_constant(Variant::Type p_type, const StringName& p_value);
|
||||
static int get_numeric_constant_value(Variant::Type p_type, const StringName& p_value);
|
||||
|
||||
String get_construct_string() const;
|
||||
typedef String (*ObjectDeConstruct)(const Variant& p_object,void *ud);
|
||||
typedef void (*ObjectConstruct)(const String& p_text,void *ud,Variant& r_value);
|
||||
|
||||
String get_construct_string(ObjectDeConstruct p_obj_deconstruct=NULL,void *p_deconstruct_ud=NULL) const;
|
||||
static void construct_from_string(const String& p_string,Variant& r_value,ObjectConstruct p_obj_construct=NULL,void *p_construct_ud=NULL);
|
||||
|
||||
void operator=(const Variant& p_variant); // only this is enough for all the other types
|
||||
Variant(const Variant& p_variant);
|
||||
|
|
|
@ -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());
|
||||
|
|
433
core/variant_construct_string.cpp
Normal file
433
core/variant_construct_string.cpp
Normal file
|
@ -0,0 +1,433 @@
|
|||
|
||||
#include "variant.h"
|
||||
|
||||
class VariantConstruct {
|
||||
|
||||
enum TokenType {
|
||||
TK_CURLY_BRACKET_OPEN,
|
||||
TK_CURLY_BRACKET_CLOSE,
|
||||
TK_BRACKET_OPEN,
|
||||
TK_BRACKET_CLOSE,
|
||||
TK_IDENTIFIER,
|
||||
TK_STRING,
|
||||
TK_NUMBER,
|
||||
TK_COLON,
|
||||
TK_COMMA,
|
||||
TK_EOF,
|
||||
TK_MAX
|
||||
};
|
||||
|
||||
enum Expecting {
|
||||
|
||||
EXPECT_OBJECT,
|
||||
EXPECT_OBJECT_KEY,
|
||||
EXPECT_COLON,
|
||||
EXPECT_OBJECT_VALUE,
|
||||
};
|
||||
|
||||
struct Token {
|
||||
|
||||
TokenType type;
|
||||
Variant value;
|
||||
};
|
||||
|
||||
static const char * tk_name[TK_MAX];
|
||||
|
||||
static String _print_var(const Variant& p_var);
|
||||
|
||||
static Error _get_token(const CharType *p_str,int &index, int p_len,Token& r_token,int &line,String &r_err_str);
|
||||
static Error _parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud);
|
||||
static Error _parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud);
|
||||
static Error _parse_dict(Dictionary &object,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud);
|
||||
|
||||
public:
|
||||
|
||||
static Error parse(const String& p_string,Variant& r_ret,String &r_err_str,int &r_err_line,Variant::ObjectConstruct* p_construct,void* p_ud);
|
||||
};
|
||||
|
||||
|
||||
const char * VariantConstruct::tk_name[TK_MAX] = {
|
||||
"'{'",
|
||||
"'}'",
|
||||
"'['",
|
||||
"']'",
|
||||
"identifier",
|
||||
"string",
|
||||
"number",
|
||||
"':'",
|
||||
"','",
|
||||
"EOF",
|
||||
};
|
||||
|
||||
|
||||
|
||||
Error VariantConstruct::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_token,int &line,String &r_err_str) {
|
||||
|
||||
while (true) {
|
||||
switch(p_str[idx]) {
|
||||
|
||||
case '\n': {
|
||||
|
||||
line++;
|
||||
idx++;
|
||||
break;
|
||||
};
|
||||
case 0: {
|
||||
r_token.type=TK_EOF;
|
||||
return OK;
|
||||
} break;
|
||||
case '{': {
|
||||
|
||||
r_token.type=TK_CURLY_BRACKET_OPEN;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case '}': {
|
||||
|
||||
r_token.type=TK_CURLY_BRACKET_CLOSE;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case '[': {
|
||||
|
||||
r_token.type=TK_BRACKET_OPEN;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case ']': {
|
||||
|
||||
r_token.type=TK_BRACKET_CLOSE;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case ':': {
|
||||
|
||||
r_token.type=TK_COLON;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case ',': {
|
||||
|
||||
r_token.type=TK_COMMA;
|
||||
idx++;
|
||||
return OK;
|
||||
};
|
||||
case '"': {
|
||||
|
||||
idx++;
|
||||
String str;
|
||||
while(true) {
|
||||
if (p_str[idx]==0) {
|
||||
r_err_str="Unterminated String";
|
||||
return ERR_PARSE_ERROR;
|
||||
} else if (p_str[idx]=='"') {
|
||||
idx++;
|
||||
break;
|
||||
} else if (p_str[idx]=='\\') {
|
||||
//escaped characters...
|
||||
idx++;
|
||||
CharType next = p_str[idx];
|
||||
if (next==0) {
|
||||
r_err_str="Unterminated String";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
CharType res=0;
|
||||
|
||||
switch(next) {
|
||||
|
||||
case 'b': res=8; break;
|
||||
case 't': res=9; break;
|
||||
case 'n': res=10; break;
|
||||
case 'f': res=12; break;
|
||||
case 'r': res=13; break;
|
||||
case '\"': res='\"'; break;
|
||||
case '\\': res='\\'; break;
|
||||
case '/': res='/'; break; //wtf
|
||||
case 'u': {
|
||||
//hexnumbarh - oct is deprecated
|
||||
|
||||
|
||||
for(int j=0;j<4;j++) {
|
||||
CharType c = p_str[idx+j+1];
|
||||
if (c==0) {
|
||||
r_err_str="Unterminated String";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) {
|
||||
|
||||
r_err_str="Malformed hex constant in string";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
CharType v;
|
||||
if (c>='0' && c<='9') {
|
||||
v=c-'0';
|
||||
} else if (c>='a' && c<='f') {
|
||||
v=c-'a';
|
||||
v+=10;
|
||||
} else if (c>='A' && c<='F') {
|
||||
v=c-'A';
|
||||
v+=10;
|
||||
} else {
|
||||
ERR_PRINT("BUG");
|
||||
v=0;
|
||||
}
|
||||
|
||||
res<<=4;
|
||||
res|=v;
|
||||
|
||||
|
||||
}
|
||||
idx+=4; //will add at the end anyway
|
||||
|
||||
|
||||
} break;
|
||||
default: {
|
||||
|
||||
r_err_str="Invalid escape sequence";
|
||||
return ERR_PARSE_ERROR;
|
||||
} break;
|
||||
}
|
||||
|
||||
str+=res;
|
||||
|
||||
} else {
|
||||
if (p_str[idx]=='\n')
|
||||
line++;
|
||||
str+=p_str[idx];
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
r_token.type=TK_STRING;
|
||||
r_token.value=str;
|
||||
return OK;
|
||||
|
||||
} break;
|
||||
default: {
|
||||
|
||||
if (p_str[idx]<=32) {
|
||||
idx++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) {
|
||||
//a number
|
||||
const CharType *rptr;
|
||||
double number = String::to_double(&p_str[idx],&rptr);
|
||||
idx+=(rptr - &p_str[idx]);
|
||||
r_token.type=TK_NUMBER;
|
||||
r_token.value=number;
|
||||
return OK;
|
||||
|
||||
} else if ((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {
|
||||
|
||||
String id;
|
||||
|
||||
while((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {
|
||||
|
||||
id+=p_str[idx];
|
||||
idx++;
|
||||
}
|
||||
|
||||
r_token.type=TK_IDENTIFIER;
|
||||
r_token.value=id;
|
||||
return OK;
|
||||
} else {
|
||||
r_err_str="Unexpected character.";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Error VariantConstruct::_parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) {
|
||||
|
||||
|
||||
if (token.type==TK_CURLY_BRACKET_OPEN) {
|
||||
|
||||
Dictionary d;
|
||||
Error err = _parse_dict(d,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
|
||||
if (err)
|
||||
return err;
|
||||
value=d;
|
||||
return OK;
|
||||
} else if (token.type==TK_BRACKET_OPEN) {
|
||||
|
||||
Array a;
|
||||
Error err = _parse_array(a,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
|
||||
if (err)
|
||||
return err;
|
||||
value=a;
|
||||
return OK;
|
||||
|
||||
} else if (token.type==TK_IDENTIFIER) {
|
||||
|
||||
String id = token.value;
|
||||
if (id=="true")
|
||||
value=true;
|
||||
else if (id=="false")
|
||||
value=false;
|
||||
else if (id=="null")
|
||||
value=Variant();
|
||||
else {
|
||||
r_err_str="Expected 'true','false' or 'null', got '"+id+"'.";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
return OK;
|
||||
|
||||
} else if (token.type==TK_NUMBER) {
|
||||
|
||||
value=token.value;
|
||||
return OK;
|
||||
} else if (token.type==TK_STRING) {
|
||||
|
||||
value=token.value;
|
||||
return OK;
|
||||
} else {
|
||||
r_err_str="Expected value, got "+String(tk_name[token.type])+".";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
Error VariantConstruct::_parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) {
|
||||
|
||||
Token token;
|
||||
bool need_comma=false;
|
||||
|
||||
|
||||
while(index<p_len) {
|
||||
|
||||
Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
|
||||
if (err!=OK)
|
||||
return err;
|
||||
|
||||
if (token.type==TK_BRACKET_CLOSE) {
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (need_comma) {
|
||||
|
||||
if (token.type!=TK_COMMA) {
|
||||
|
||||
r_err_str="Expected ','";
|
||||
return ERR_PARSE_ERROR;
|
||||
} else {
|
||||
need_comma=false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Variant v;
|
||||
err = _parse_value(v,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
array.push_back(v);
|
||||
need_comma=true;
|
||||
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
}
|
||||
|
||||
Error VariantConstruct::_parse_dict(Dictionary &dict,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) {
|
||||
|
||||
bool at_key=true;
|
||||
Variant key;
|
||||
Token token;
|
||||
bool need_comma=false;
|
||||
|
||||
|
||||
while(index<p_len) {
|
||||
|
||||
|
||||
if (at_key) {
|
||||
|
||||
Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
|
||||
if (err!=OK)
|
||||
return err;
|
||||
|
||||
if (token.type==TK_CURLY_BRACKET_CLOSE) {
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (need_comma) {
|
||||
|
||||
if (token.type!=TK_COMMA) {
|
||||
|
||||
r_err_str="Expected '}' or ','";
|
||||
return ERR_PARSE_ERROR;
|
||||
} else {
|
||||
need_comma=false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
err = _parse_value(key,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
|
||||
|
||||
|
||||
if (err!=OK)
|
||||
return err;
|
||||
|
||||
err = _get_token(p_str,index,p_len,token,line,r_err_str);
|
||||
|
||||
if (err!=OK)
|
||||
return err;
|
||||
|
||||
if (token.type!=TK_COLON) {
|
||||
|
||||
r_err_str="Expected ':'";
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
at_key=false;
|
||||
} else {
|
||||
|
||||
|
||||
Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
|
||||
if (err!=OK)
|
||||
return err;
|
||||
|
||||
Variant v;
|
||||
err = _parse_value(v,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud);
|
||||
if (err)
|
||||
return err;
|
||||
dict[key]=v;
|
||||
need_comma=true;
|
||||
at_key=true;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
Error VariantConstruct::parse(const String& p_string,Variant& r_ret,String &r_err_str,int &r_err_line,Variant::ObjectConstruct* p_construct,void* p_ud) {
|
||||
|
||||
|
||||
const CharType *str = p_string.ptr();
|
||||
int idx = 0;
|
||||
int len = p_string.length();
|
||||
Token token;
|
||||
r_err_line=0;
|
||||
String aux_key;
|
||||
|
||||
Error err = _get_token(str,idx,len,token,r_err_line,r_err_str);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return _parse_value(r_ret,token,str,idx,len,r_err_line,r_err_str,p_construct,p_ud);
|
||||
}
|
||||
|
||||
|
|
@ -552,6 +552,9 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
|
|||
if (p_b.type==MATRIX32) {
|
||||
_RETURN( *p_a._data._matrix32 * *p_b._data._matrix32 );
|
||||
};
|
||||
if (p_b.type==VECTOR2) {
|
||||
_RETURN( p_a._data._matrix32->xform( *(const Vector2*)p_b._data._mem) );
|
||||
};
|
||||
r_valid=false;
|
||||
return;
|
||||
} break;
|
||||
|
@ -736,6 +739,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;
|
||||
|
@ -1687,6 +1704,19 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (ie.type == InputEvent::ACTION) {
|
||||
|
||||
if (str =="action") {
|
||||
valid=true;
|
||||
ie.action.action=p_value;
|
||||
return;
|
||||
}
|
||||
else if (str == "pressed") {
|
||||
valid=true;
|
||||
ie.action.pressed=p_value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
case DICTIONARY: {
|
||||
|
@ -2365,6 +2395,17 @@ Variant Variant::get(const Variant& p_index, bool *r_valid) const {
|
|||
return Vector2(ie.screen_drag.speed_x,ie.screen_drag.speed_y);
|
||||
}
|
||||
}
|
||||
if (ie.type == InputEvent::ACTION) {
|
||||
|
||||
if (str =="action") {
|
||||
valid=true;
|
||||
return ie.action.action;
|
||||
}
|
||||
else if (str == "pressed") {
|
||||
valid=true;
|
||||
ie.action.pressed;
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
case DICTIONARY: {
|
||||
|
|
|
@ -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
BIN
demos/2d/navpoly/agent.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
4
demos/2d/navpoly/engine.cfg
Normal file
4
demos/2d/navpoly/engine.cfg
Normal file
|
@ -0,0 +1,4 @@
|
|||
[application]
|
||||
|
||||
name="Navigation Polygon (2D)"
|
||||
main_scene="res://navigation.scn"
|
63
demos/2d/navpoly/navigation.gd
Normal file
63
demos/2d/navpoly/navigation.gd
Normal file
|
@ -0,0 +1,63 @@
|
|||
|
||||
extends Navigation2D
|
||||
|
||||
# member variables here, example:
|
||||
# var a=2
|
||||
# var b="textvar"
|
||||
var begin=Vector2()
|
||||
var end=Vector2()
|
||||
var path=[]
|
||||
|
||||
const SPEED=200.0
|
||||
|
||||
func _process(delta):
|
||||
|
||||
|
||||
if (path.size()>1):
|
||||
|
||||
var to_walk = delta*SPEED
|
||||
while(to_walk>0 and path.size()>=2):
|
||||
var pfrom = path[path.size()-1]
|
||||
var pto = path[path.size()-2]
|
||||
var d = pfrom.distance_to(pto)
|
||||
if (d<=to_walk):
|
||||
path.remove(path.size()-1)
|
||||
to_walk-=d
|
||||
else:
|
||||
path[path.size()-1] = pfrom.linear_interpolate(pto,to_walk/d)
|
||||
to_walk=0
|
||||
|
||||
var atpos = path[path.size()-1]
|
||||
get_node("agent").set_pos(atpos)
|
||||
|
||||
if (path.size()<2):
|
||||
path=[]
|
||||
set_process(false)
|
||||
|
||||
else:
|
||||
set_process(false)
|
||||
|
||||
|
||||
|
||||
func _update_path():
|
||||
|
||||
var p = get_simple_path(begin,end,true)
|
||||
path=Array(p) # Vector2array to complex to use, convert to regular array
|
||||
path.invert()
|
||||
|
||||
set_process(true)
|
||||
|
||||
|
||||
func _input(ev):
|
||||
if (ev.type==InputEvent.MOUSE_BUTTON and ev.pressed and ev.button_index==1):
|
||||
begin=get_node("agent").get_pos()
|
||||
#mouse to local navigatio cooards
|
||||
end=ev.pos - get_pos()
|
||||
_update_path()
|
||||
|
||||
func _ready():
|
||||
# Initialization here
|
||||
set_process_input(true)
|
||||
pass
|
||||
|
||||
|
BIN
demos/2d/navpoly/navigation.scn
Normal file
BIN
demos/2d/navpoly/navigation.scn
Normal file
Binary file not shown.
BIN
demos/2d/navpoly/navigation2.scn
Normal file
BIN
demos/2d/navpoly/navigation2.scn
Normal file
Binary file not shown.
BIN
demos/2d/navpoly/path.png
Normal file
BIN
demos/2d/navpoly/path.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 302 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.8 KiB |
|
@ -1,134 +1,191 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<resource_file type="TileSet" subresource_count="12" version="0.99" version_name="Godot Engine v0.99.3037-pre-beta">
|
||||
<resource_file type="TileSet" subresource_count="14" version="1.0" version_name="Godot Engine v1.0.stable.custom_build">
|
||||
<ext_resource path="res://tiles_demo.png" type="Texture"></ext_resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://0">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 8, 64, 8, 64, 64, 0, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://1">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 8, 56, 8, 56, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, -24, 32, -24, 32, 32, -32, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://2">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, 32, -32, -24, 24, -24, 24, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://3">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, 32, -32, -32, 24, -32, 24, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://4">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="5"> 0, 64, 0, 0, 56, 0, 64, 8, 64, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -64, 32, -64, -32, -8, -32, -8, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://5">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 8, 64, 8, 64, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="5"> -32, 32, -32, -32, 24, -32, 32, -24, 32, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://6">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 8, 64, 8, 64, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, 32, -32, -24, 32, -24, 32, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://7">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 0, 64, 0, 64, 64, 0, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, 32, -32, -24, 32, -24, 32, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://8">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 8, 64, 72, 64, 128, 0, 128 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, -32, 32, -32, 32, 32, -32, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://9">
|
||||
<string name="resource/name"> "" </string>
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> 0, 64, 0, 0, 56, 0, 56, 64 </vector2_array>
|
||||
<resource name="script/script"></resource>
|
||||
<vector2_array name="points" len="4"> -32, -56, 32, 8, 32, 64, -32, 64 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://10">
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> -32, 32, -32, -32, 24, -32, 24, 32 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://11">
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> -32, -24, 32, -24, 32, 24, -32, 24 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<resource type="ConvexPolygonShape2D" path="local://12">
|
||||
<real name="custom_solver_bias"> 0 </real>
|
||||
<vector2_array name="points" len="4"> -32, -24, 24, -24, 24, 24, -32, 24 </vector2_array>
|
||||
|
||||
</resource>
|
||||
<main_resource>
|
||||
<string name="resource/name"> "" </string>
|
||||
<string name="0/name"> "floor" </string>
|
||||
<resource name="0/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="0/offset"> 0, 0 </vector2>
|
||||
<vector2 name="0/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="0/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="0/region"> 0, 0, 64, 64 </rect2>
|
||||
<resource name="0/shape" resource_type="ConvexPolygonShape2D" path="local://0"> </resource>
|
||||
<array name="0/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://1"> </resource>
|
||||
</array>
|
||||
<string name="1/name"> "edge" </string>
|
||||
<resource name="1/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="1/offset"> 0, 0 </vector2>
|
||||
<vector2 name="1/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="1/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="1/region"> 64, 0, 64, 64 </rect2>
|
||||
<resource name="1/shape" resource_type="ConvexPolygonShape2D" path="local://1"> </resource>
|
||||
<array name="1/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://2"> </resource>
|
||||
</array>
|
||||
<string name="2/name"> "wall" </string>
|
||||
<resource name="2/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="2/offset"> 0, 0 </vector2>
|
||||
<vector2 name="2/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="2/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="2/region"> 64, 64, 64, 64 </rect2>
|
||||
<resource name="2/shape" resource_type="ConvexPolygonShape2D" path="local://2"> </resource>
|
||||
<array name="2/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://3"> </resource>
|
||||
</array>
|
||||
<string name="3/name"> "wall_deco" </string>
|
||||
<resource name="3/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="3/offset"> 0, 0 </vector2>
|
||||
<vector2 name="3/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="3/shape_offset"> 64, 32 </vector2>
|
||||
<rect2 name="3/region"> 320, 128, 128, 64 </rect2>
|
||||
<resource name="3/shape" resource_type="ConvexPolygonShape2D" path="local://3"> </resource>
|
||||
<array name="3/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://4"> </resource>
|
||||
</array>
|
||||
<string name="4/name"> "corner" </string>
|
||||
<resource name="4/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="4/offset"> 0, 0 </vector2>
|
||||
<vector2 name="4/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="4/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="4/region"> 64, 128, 64, 64 </rect2>
|
||||
<resource name="4/shape" resource_type="ConvexPolygonShape2D" path="local://4"> </resource>
|
||||
<array name="4/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://5"> </resource>
|
||||
</array>
|
||||
<string name="5/name"> "flowers" </string>
|
||||
<resource name="5/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="5/offset"> 0, 0 </vector2>
|
||||
<vector2 name="5/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="5/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="5/region"> 192, 192, 64, 64 </rect2>
|
||||
<resource name="5/shape" resource_type="ConvexPolygonShape2D" path="local://5"> </resource>
|
||||
<array name="5/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://6"> </resource>
|
||||
</array>
|
||||
<string name="6/name"> "tree_base" </string>
|
||||
<resource name="6/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="6/offset"> 0, 0 </vector2>
|
||||
<vector2 name="6/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="6/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="6/region"> 256, 192, 64, 64 </rect2>
|
||||
<resource name="6/shape" resource_type="ConvexPolygonShape2D" path="local://6"> </resource>
|
||||
<array name="6/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://7"> </resource>
|
||||
</array>
|
||||
<string name="7/name"> "tree_mid" </string>
|
||||
<resource name="7/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="7/offset"> 0, 0 </vector2>
|
||||
<vector2 name="7/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="7/shape_offset"> 0, 0 </vector2>
|
||||
<rect2 name="7/region"> 256, 128, 64, 64 </rect2>
|
||||
<resource name="7/shape"></resource> <string name="8/name"> "tree_mid 2" </string>
|
||||
<array name="7/shapes" len="0" shared="false">
|
||||
</array>
|
||||
<string name="8/name"> "tree_mid 2" </string>
|
||||
<resource name="8/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="8/offset"> 0, 0 </vector2>
|
||||
<vector2 name="8/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="8/shape_offset"> 0, 0 </vector2>
|
||||
<rect2 name="8/region"> 256, 64, 64, 64 </rect2>
|
||||
<resource name="8/shape"></resource> <string name="9/name"> "tree_top" </string>
|
||||
<array name="8/shapes" len="0" shared="false">
|
||||
</array>
|
||||
<string name="9/name"> "tree_top" </string>
|
||||
<resource name="9/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="9/offset"> 0, 0 </vector2>
|
||||
<vector2 name="9/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="9/shape_offset"> 0, 0 </vector2>
|
||||
<rect2 name="9/region"> 256, 0, 64, 64 </rect2>
|
||||
<resource name="9/shape"></resource> <string name="10/name"> "solid" </string>
|
||||
<array name="9/shapes" len="0" shared="false">
|
||||
</array>
|
||||
<string name="10/name"> "solid" </string>
|
||||
<resource name="10/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="10/offset"> 0, 0 </vector2>
|
||||
<vector2 name="10/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="10/shape_offset"> 0, 0 </vector2>
|
||||
<rect2 name="10/region"> 0, 64, 64, 64 </rect2>
|
||||
<resource name="10/shape"></resource> <string name="11/name"> "ceiling" </string>
|
||||
<array name="10/shapes" len="0" shared="false">
|
||||
</array>
|
||||
<string name="11/name"> "ceiling" </string>
|
||||
<resource name="11/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="11/offset"> 0, 0 </vector2>
|
||||
<vector2 name="11/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="11/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="11/region"> 384, 64, 64, 64 </rect2>
|
||||
<resource name="11/shape" resource_type="ConvexPolygonShape2D" path="local://7"> </resource>
|
||||
<array name="11/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://8"> </resource>
|
||||
</array>
|
||||
<string name="12/name"> "ramp" </string>
|
||||
<resource name="12/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="12/offset"> 0, 0 </vector2>
|
||||
<vector2 name="12/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="12/shape_offset"> 32, 64 </vector2>
|
||||
<rect2 name="12/region"> 128, 128, 64, 128 </rect2>
|
||||
<resource name="12/shape" resource_type="ConvexPolygonShape2D" path="local://8"> </resource>
|
||||
<array name="12/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://9"> </resource>
|
||||
</array>
|
||||
<string name="13/name"> "ceiling2wall" </string>
|
||||
<resource name="13/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="13/offset"> 0, 0 </vector2>
|
||||
<vector2 name="13/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="13/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="13/region"> 448, 64, 64, 64 </rect2>
|
||||
<resource name="13/shape" resource_type="ConvexPolygonShape2D" path="local://9"> </resource>
|
||||
<resource name="script/script"></resource>
|
||||
<array name="13/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://10"> </resource>
|
||||
</array>
|
||||
<string name="14/name"> "platform_floor" </string>
|
||||
<resource name="14/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="14/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="14/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="14/region"> 128, 0, 64, 64 </rect2>
|
||||
<array name="14/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://11"> </resource>
|
||||
</array>
|
||||
<string name="15/name"> "platform_edge" </string>
|
||||
<resource name="15/texture" resource_type="Texture" path="res://tiles_demo.png"> </resource>
|
||||
<vector2 name="15/tex_offset"> 0, 0 </vector2>
|
||||
<vector2 name="15/shape_offset"> 32, 32 </vector2>
|
||||
<rect2 name="15/region"> 192, 0, 64, 64 </rect2>
|
||||
<array name="15/shapes" len="1" shared="false">
|
||||
<resource resource_type="Shape2D" path="local://12"> </resource>
|
||||
</array>
|
||||
|
||||
</main_resource>
|
||||
</resource_file>
|
File diff suppressed because one or more lines are too long
|
@ -1,4 +0,0 @@
|
|||
::res://::1421147952
|
||||
icon.png::ImageTexture::1420046079::
|
||||
new_scene_poly_with_holes.scn::PackedScene::1421147952::
|
||||
polygonpathfinder.gd::GDScript::1421146502::
|
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -10,7 +10,6 @@ SConscript('alsa/SCsub');
|
|||
SConscript('pulseaudio/SCsub');
|
||||
SConscript('windows/SCsub');
|
||||
SConscript('gles2/SCsub');
|
||||
SConscript('gles1/SCsub');
|
||||
SConscript('gl_context/SCsub');
|
||||
SConscript('openssl/SCsub');
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -51,6 +51,7 @@
|
|||
|
||||
#include "drivers/gles2/shaders/material.glsl.h"
|
||||
#include "drivers/gles2/shaders/canvas.glsl.h"
|
||||
#include "drivers/gles2/shaders/canvas_shadow.glsl.h"
|
||||
#include "drivers/gles2/shaders/blur.glsl.h"
|
||||
#include "drivers/gles2/shaders/copy.glsl.h"
|
||||
#include "drivers/gles2/shader_compiler_gles2.h"
|
||||
|
@ -65,7 +66,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,
|
||||
};
|
||||
|
||||
|
@ -816,6 +817,7 @@ class RasterizerGLES2 : public Rasterizer {
|
|||
bool current_depth_mask;
|
||||
VS::MaterialBlendMode current_blend_mode;
|
||||
bool use_fast_texture_filter;
|
||||
int max_texture_size;
|
||||
|
||||
bool fragment_lighting;
|
||||
RID shadow_material;
|
||||
|
@ -827,15 +829,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 +873,8 @@ class RasterizerGLES2 : public Rasterizer {
|
|||
};
|
||||
|
||||
|
||||
Element _elements[MAX_ELEMENTS];
|
||||
Element *elements[MAX_ELEMENTS];
|
||||
Element *_elements;
|
||||
Element **elements;
|
||||
int element_count;
|
||||
|
||||
void clear() {
|
||||
|
@ -1004,17 +1009,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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1113,6 +1129,7 @@ class RasterizerGLES2 : public Rasterizer {
|
|||
bool active;
|
||||
|
||||
int blur_size;
|
||||
|
||||
struct Blur {
|
||||
|
||||
GLuint fbo;
|
||||
|
@ -1145,6 +1162,7 @@ class RasterizerGLES2 : public Rasterizer {
|
|||
void _process_glow_and_bloom();
|
||||
//void _update_blur_buffer();
|
||||
|
||||
|
||||
/*********/
|
||||
/* FRAME */
|
||||
/*********/
|
||||
|
@ -1163,6 +1181,45 @@ class RasterizerGLES2 : public Rasterizer {
|
|||
} _rinfo;
|
||||
|
||||
|
||||
/*******************/
|
||||
/* CANVAS OCCLUDER */
|
||||
/*******************/
|
||||
|
||||
|
||||
struct CanvasOccluder {
|
||||
|
||||
GLuint vertex_id; // 0 means, unconfigured
|
||||
GLuint index_id; // 0 means, unconfigured
|
||||
DVector<Vector2> lines;
|
||||
int len;
|
||||
};
|
||||
|
||||
RID_Owner<CanvasOccluder> canvas_occluder_owner;
|
||||
|
||||
/***********************/
|
||||
/* CANVAS LIGHT SHADOW */
|
||||
/***********************/
|
||||
|
||||
|
||||
struct CanvasLightShadow {
|
||||
|
||||
int size;
|
||||
int height;
|
||||
GLuint fbo;
|
||||
GLuint rbo;
|
||||
GLuint depth;
|
||||
GLuint rgba; //for older devices
|
||||
|
||||
GLuint blur;
|
||||
|
||||
};
|
||||
|
||||
RID_Owner<CanvasLightShadow> canvas_light_shadow_owner;
|
||||
|
||||
RID canvas_shadow_blur;
|
||||
|
||||
/* ETC */
|
||||
|
||||
RenderTarget *current_rt;
|
||||
bool current_rt_transparent;
|
||||
bool current_rt_vflip;
|
||||
|
@ -1172,11 +1229,15 @@ class RasterizerGLES2 : public Rasterizer {
|
|||
GLuint white_tex;
|
||||
RID canvas_tex;
|
||||
float canvas_opacity;
|
||||
Color canvas_modulate;
|
||||
bool canvas_use_modulate;
|
||||
bool uses_texpixel_size;
|
||||
bool rebind_texpixel_size;
|
||||
Transform canvas_transform;
|
||||
RID canvas_last_shader;
|
||||
CanvasItemMaterial *canvas_last_material;
|
||||
bool canvas_texscreen_used;
|
||||
Vector2 normal_flip;
|
||||
_FORCE_INLINE_ void _canvas_normal_set_flip(const Vector2& p_flip);
|
||||
|
||||
|
||||
_FORCE_INLINE_ Texture* _bind_canvas_texture(const RID& p_texture);
|
||||
|
@ -1208,17 +1269,19 @@ class RasterizerGLES2 : public Rasterizer {
|
|||
VS::ScenarioDebugMode current_debug;
|
||||
RID overdraw_material;
|
||||
|
||||
|
||||
mutable MaterialShaderGLES2 material_shader;
|
||||
mutable CanvasShaderGLES2 canvas_shader;
|
||||
BlurShaderGLES2 blur_shader;
|
||||
CopyShaderGLES2 copy_shader;
|
||||
mutable CanvasShadowShaderGLES2 canvas_shadow_shader;
|
||||
|
||||
mutable ShaderCompilerGLES2 shader_precompiler;
|
||||
|
||||
void _draw_primitive(int p_points, const Vector3 *p_vertices, const Vector3 *p_normals, const Color* p_colors, const Vector3 *p_uvs,const Plane *p_tangents=NULL,int p_instanced=1);
|
||||
_FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color* p_colors, const Vector2 *p_uvs);
|
||||
_FORCE_INLINE_ void _draw_gui_primitive2(int p_points, const Vector2 *p_vertices, const Color* p_colors, const Vector2 *p_uvs, const Vector2 *p_uvs2);
|
||||
void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip=false, bool p_v_flip=false );
|
||||
void _draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip=false, bool p_v_flip=false, bool p_transpose=false );
|
||||
void _draw_quad(const Rect2& p_rect);
|
||||
void _copy_screen_quad();
|
||||
void _copy_to_texscreen();
|
||||
|
@ -1233,6 +1296,10 @@ class RasterizerGLES2 : public Rasterizer {
|
|||
GLuint tc0_id_cache;
|
||||
GLuint tc0_idx;
|
||||
|
||||
template<bool use_normalmap>
|
||||
_FORCE_INLINE_ void _canvas_item_render_commands(CanvasItem *p_item,CanvasItem *current_clip,bool &reclip);
|
||||
_FORCE_INLINE_ void _canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* p_shader);
|
||||
_FORCE_INLINE_ void _canvas_item_setup_shader_uniforms(CanvasItemMaterial *material,Shader* p_shader);
|
||||
public:
|
||||
|
||||
/* TEXTURE API */
|
||||
|
@ -1548,7 +1615,18 @@ public:
|
|||
virtual void canvas_draw_polygon(int p_vertex_count, const int* p_indices, const Vector2* p_vertices, const Vector2* p_uvs, const Color* p_colors,const RID& p_texture,bool p_singlecolor);
|
||||
virtual void canvas_set_transform(const Matrix32& p_transform);
|
||||
|
||||
virtual void canvas_render_items(CanvasItem *p_item_list);
|
||||
virtual void canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light);
|
||||
virtual void canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow);
|
||||
|
||||
/* CANVAS LIGHT SHADOW */
|
||||
|
||||
//buffer
|
||||
virtual RID canvas_light_shadow_buffer_create(int p_width);
|
||||
virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Matrix32& p_light_xform, int p_light_mask,float p_near, float p_far, CanvasLightOccluderInstance* p_occluders, CameraMatrix *p_xform_cache);
|
||||
|
||||
//occluder
|
||||
virtual RID canvas_light_occluder_create();
|
||||
virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines);
|
||||
|
||||
/* ENVIRONMENT */
|
||||
|
||||
|
@ -1587,6 +1665,8 @@ public:
|
|||
virtual bool is_environment(const RID& p_rid) const;
|
||||
virtual bool is_shader(const RID& p_rid) const;
|
||||
|
||||
virtual bool is_canvas_light_occluder(const RID& p_rid) const;
|
||||
|
||||
virtual void free(const RID& p_rid);
|
||||
|
||||
virtual void init();
|
||||
|
|
|
@ -226,6 +226,9 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
|
|||
if (vnode->name==vname_var2_interp) {
|
||||
flags->use_var2_interp=true;
|
||||
}
|
||||
if (vnode->name==vname_world_vec) {
|
||||
uses_worldvec=true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -258,6 +261,11 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
|
|||
uses_light=true;
|
||||
}
|
||||
|
||||
if (vnode->name==vname_normal) {
|
||||
uses_normal=true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (vnode->name==vname_time) {
|
||||
|
@ -307,13 +315,13 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
|
|||
|
||||
String mul_l=dump_node_code(onode->arguments[0],p_level,true);
|
||||
String mul_r=dump_node_code(onode->arguments[1],p_level);
|
||||
code=mul_l+"=(vec4("+mul_l+",1.0,1.0)*("+mul_r+")).xy";
|
||||
code=mul_l+"=(vec4("+mul_l+",0.0,1.0)*("+mul_r+")).xy";
|
||||
break;
|
||||
} else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT4 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) {
|
||||
|
||||
String mul_l=dump_node_code(onode->arguments[0],p_level,true);
|
||||
String mul_r=dump_node_code(onode->arguments[1],p_level);
|
||||
code=mul_l+"=(("+mul_l+")*vec4("+mul_r+",1.0,1.0)).xy";
|
||||
code=mul_l+"=(("+mul_l+")*vec4("+mul_r+",0.0,1.0)).xy";
|
||||
break;
|
||||
} else if (onode->arguments[0]->get_datatype()==SL::TYPE_VEC2 && onode->arguments[1]->get_datatype()==SL::TYPE_MAT3) {
|
||||
String mul_l=dump_node_code(onode->arguments[0],p_level,true);
|
||||
|
@ -343,11 +351,11 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
|
|||
break;
|
||||
} else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT4 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) {
|
||||
|
||||
code="("+dump_node_code(onode->arguments[0],p_level)+"*vec4("+dump_node_code(onode->arguments[1],p_level)+",1.0,1.0)).xyz";
|
||||
code="("+dump_node_code(onode->arguments[0],p_level)+"*vec4("+dump_node_code(onode->arguments[1],p_level)+",0.0,1.0)).xy";
|
||||
break;
|
||||
} else if (onode->arguments[0]->get_datatype()==SL::TYPE_VEC2 && onode->arguments[1]->get_datatype()==SL::TYPE_MAT4) {
|
||||
|
||||
code="(vec4("+dump_node_code(onode->arguments[0],p_level)+",1.0,1.0)*"+dump_node_code(onode->arguments[1],p_level)+").xyz";
|
||||
code="(vec4("+dump_node_code(onode->arguments[0],p_level)+",0.0,1.0)*"+dump_node_code(onode->arguments[1],p_level)+").xy";
|
||||
break;
|
||||
} else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT3 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) {
|
||||
|
||||
|
@ -599,6 +607,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
|
|||
uses_normalmap=false;
|
||||
uses_normal=false;
|
||||
uses_texpixel_size=false;
|
||||
uses_worldvec=false;
|
||||
vertex_code_writes_vertex=false;
|
||||
uniforms=r_uniforms;
|
||||
flags=&r_flags;
|
||||
|
@ -632,8 +641,9 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
|
|||
r_flags.uses_light=uses_light;
|
||||
r_flags.uses_time=uses_time;
|
||||
r_flags.uses_normalmap=uses_normalmap;
|
||||
r_flags.uses_normal=uses_normalmap;
|
||||
r_flags.uses_normal=uses_normal;
|
||||
r_flags.uses_texpixel_size=uses_texpixel_size;
|
||||
r_flags.uses_worldvec=uses_worldvec;
|
||||
r_code_line=code;
|
||||
r_globals_line=global_code;
|
||||
|
||||
|
@ -774,6 +784,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
|
|||
|
||||
mode_replace_table[3]["SRC_VERTEX"]="src_vtx";
|
||||
mode_replace_table[3]["VERTEX"]="outvec.xy";
|
||||
mode_replace_table[3]["WORLD_VERTEX"]="outvec.xy";
|
||||
mode_replace_table[3]["UV"]="uv_interp";
|
||||
mode_replace_table[3]["COLOR"]="color_interp";
|
||||
mode_replace_table[3]["VAR1"]="var1_interp";
|
||||
|
@ -830,5 +841,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
|
|||
vname_normalmap="NORMALMAP";
|
||||
vname_normal="NORMAL";
|
||||
vname_texpixel_size="TEXTURE_PIXEL_SIZE";
|
||||
vname_world_vec="WORLD_VERTEX";
|
||||
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ private:
|
|||
bool uses_normalmap;
|
||||
bool uses_normal;
|
||||
bool uses_texpixel_size;
|
||||
bool uses_worldvec;
|
||||
bool vertex_code_writes_vertex;
|
||||
Flags *flags;
|
||||
|
||||
|
@ -72,6 +73,7 @@ private:
|
|||
StringName vname_normalmap;
|
||||
StringName vname_normal;
|
||||
StringName vname_texpixel_size;
|
||||
StringName vname_world_vec;
|
||||
|
||||
Map<StringName,ShaderLanguage::Uniform> *uniforms;
|
||||
|
||||
|
@ -107,6 +109,7 @@ public:
|
|||
bool uses_time;
|
||||
bool uses_normal;
|
||||
bool uses_texpixel_size;
|
||||
bool uses_worldvec;
|
||||
};
|
||||
|
||||
Error compile(const String& p_code, ShaderLanguage::ShaderType p_type, String& r_code_line, String& r_globals_line, Flags& r_flags, Map<StringName,ShaderLanguage::Uniform> *r_uniforms=NULL);
|
||||
|
|
|
@ -3,6 +3,7 @@ Import('env')
|
|||
if env['BUILDERS'].has_key('GLSL120GLES'):
|
||||
env.GLSL120GLES('material.glsl');
|
||||
env.GLSL120GLES('canvas.glsl');
|
||||
env.GLSL120GLES('canvas_shadow.glsl');
|
||||
env.GLSL120GLES('blur.glsl');
|
||||
env.GLSL120GLES('copy.glsl');
|
||||
|
||||
|
|
|
@ -26,7 +26,17 @@ uniform float time;
|
|||
#ifdef USE_LIGHTING
|
||||
|
||||
uniform highp mat4 light_matrix;
|
||||
varying vec4 light_tex_pos;
|
||||
uniform vec2 light_pos;
|
||||
varying vec4 light_uv_interp;
|
||||
|
||||
#if defined(NORMAL_USED)
|
||||
varying vec4 local_rot;
|
||||
uniform vec2 normal_flip;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SHADOWS
|
||||
highp varying vec2 pos;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -46,29 +56,42 @@ void main() {
|
|||
|
||||
color_interp = color_attrib;
|
||||
uv_interp = uv_attrib;
|
||||
highp vec4 outvec = vec4(vertex, 1.0);
|
||||
highp vec4 outvec = vec4(vertex, 1.0);
|
||||
{
|
||||
vec2 src_vtx=outvec.xy;
|
||||
vec2 src_vtx=outvec.xy;
|
||||
VERTEX_SHADER_CODE
|
||||
|
||||
}
|
||||
outvec = extra_matrix * outvec;
|
||||
outvec = modelview_matrix * outvec;
|
||||
#if !defined(USE_WORLD_VEC)
|
||||
outvec = extra_matrix * outvec;
|
||||
outvec = modelview_matrix * outvec;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef USE_PIXEL_SNAP
|
||||
|
||||
outvec.xy=floor(outvec.xy+0.5);
|
||||
#endif
|
||||
|
||||
|
||||
gl_Position = projection_matrix * outvec;
|
||||
|
||||
#ifdef USE_LIGHTING
|
||||
|
||||
light_tex_pos.xy = light_matrix * outvec;
|
||||
light_tex_pos.zw=outvec.xy - light_matrix[4].xy; //likely wrong
|
||||
light_uv_interp.xy = (light_matrix * outvec).xy;
|
||||
light_uv_interp.zw = outvec.xy-light_pos;
|
||||
#ifdef USE_SHADOWS
|
||||
pos=outvec.xy;
|
||||
#endif
|
||||
|
||||
#if defined(NORMAL_USED)
|
||||
local_rot.xy=normalize( (modelview_matrix * ( extra_matrix * vec4(1.0,0.0,0.0,0.0) )).xy )*normal_flip.x;
|
||||
local_rot.zw=normalize( (modelview_matrix * ( extra_matrix * vec4(0.0,1.0,0.0,0.0) )).xy )*normal_flip.y;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
gl_Position = projection_matrix * outvec;
|
||||
}
|
||||
|
||||
[fragment]
|
||||
|
@ -118,17 +141,37 @@ varying vec4 var2_interp;
|
|||
uniform float time;
|
||||
#endif
|
||||
|
||||
#ifdef USE_MODULATE
|
||||
|
||||
uniform vec4 modulate;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIGHTING
|
||||
|
||||
uniform sampler2D light_texture;
|
||||
varying vec4 light_tex_pos;
|
||||
uniform vec4 light_color;
|
||||
uniform float light_height;
|
||||
varying vec4 light_uv_interp;
|
||||
|
||||
#if defined(NORMAL_USED)
|
||||
varying vec4 local_rot;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SHADOWS
|
||||
|
||||
uniform sampler2D shadow_texture;
|
||||
uniform float shadow_attenuation;
|
||||
|
||||
uniform highp mat4 shadow_matrix;
|
||||
uniform highp mat4 light_local_matrix;
|
||||
highp varying vec2 pos;
|
||||
uniform float shadowpixel_size;
|
||||
|
||||
#ifdef SHADOW_ESM
|
||||
uniform float shadow_esm_multiplier;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -148,6 +191,7 @@ void main() {
|
|||
vec3 normal = vec3(0,0,1);
|
||||
#endif
|
||||
|
||||
|
||||
color *= texture2D( texture, uv_interp );
|
||||
#if defined(ENABLE_SCREEN_UV)
|
||||
vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult;
|
||||
|
@ -161,37 +205,141 @@ FRAGMENT_SHADER_CODE
|
|||
color = vec4(vec3(enc32),1.0);
|
||||
#endif
|
||||
|
||||
#ifdef USE_MODULATE
|
||||
|
||||
color*=modulate;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_LIGHTING
|
||||
|
||||
#if defined(NORMAL_USED)
|
||||
normal.xy = mat2(local_rot.xy,local_rot.zw) * normal.xy;
|
||||
#endif
|
||||
|
||||
float att=1.0;
|
||||
|
||||
vec3 light = texture2D(light_texture,light_tex_pos).rgb;
|
||||
vec4 light = texture2D(light_texture,light_uv_interp.xy) * light_color;
|
||||
#ifdef USE_SHADOWS
|
||||
//this might not be that great on mobile?
|
||||
float light_dist = length(light_texture.zw);
|
||||
float light_angle = atan2(light_texture.x,light_texture.z) + 1.0 * 0.5;
|
||||
float shadow_dist = texture2D(shadow_texture,vec2(light_angle,0));
|
||||
if (light_dist>shadow_dist) {
|
||||
light*=shadow_attenuation;
|
||||
|
||||
|
||||
vec2 lpos = (light_local_matrix * vec4(pos,0.0,1.0)).xy;
|
||||
float angle_to_light = -atan(lpos.x,lpos.y);
|
||||
float PI = 3.14159265358979323846264;
|
||||
/*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays
|
||||
float ang*/
|
||||
|
||||
float su,sz;
|
||||
|
||||
float abs_angle = abs(angle_to_light);
|
||||
vec2 point;
|
||||
float sh;
|
||||
if (abs_angle<45.0*PI/180.0) {
|
||||
point = lpos;
|
||||
sh=0+(1.0/8.0);
|
||||
} else if (abs_angle>135.0*PI/180.0) {
|
||||
point = -lpos;
|
||||
sh = 0.5+(1.0/8.0);
|
||||
} else if (angle_to_light>0) {
|
||||
|
||||
point = vec2(lpos.y,-lpos.x);
|
||||
sh = 0.25+(1.0/8.0);
|
||||
} else {
|
||||
|
||||
point = vec2(-lpos.y,lpos.x);
|
||||
sh = 0.75+(1.0/8.0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
vec4 s = shadow_matrix * vec4(point,0.0,1.0);
|
||||
s.xyz/=s.w;
|
||||
su=s.x*0.5+0.5;
|
||||
sz=s.z*0.5+0.5;
|
||||
|
||||
float shadow_attenuation;
|
||||
|
||||
#ifdef SHADOW_PCF5
|
||||
|
||||
shadow_attenuation=0.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*2.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*2.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation/=5.0;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SHADOW_PCF13
|
||||
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*2.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*3.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*4.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*5.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su+shadowpixel_size*6.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*2.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*3.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*4.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*5.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation += texture2D(shadow_texture,vec2(su-shadowpixel_size*6.0,sh)).z<sz?0.0:1.0;
|
||||
shadow_attenuation/=13.0;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SHADOW_ESM
|
||||
|
||||
|
||||
{
|
||||
float unnormalized = su/shadowpixel_size;
|
||||
float fractional = fract(unnormalized);
|
||||
unnormalized = floor(unnormalized);
|
||||
float zc = texture2D(shadow_texture,vec2((unnormalized-0.5)*shadowpixel_size,sh)).z;
|
||||
float zn = texture2D(shadow_texture,vec2((unnormalized+0.5)*shadowpixel_size,sh)).z;
|
||||
float z = mix(zc,zn,fractional);
|
||||
shadow_attenuation=clamp(exp(shadow_esm_multiplier* ( z - sz )),0.0,1.0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(SHADOW_PCF5) && !defined(SHADOW_PCF13) && !defined(SHADOW_ESM)
|
||||
|
||||
shadow_attenuation = texture2D(shadow_texture,vec2(su+shadowpixel_size,sh)).z<sz?0.0:1.0;
|
||||
|
||||
#endif
|
||||
|
||||
light*=shadow_attenuation;
|
||||
//use shadows
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIGHT_SHADER_CODE)
|
||||
//light is written by the light shader
|
||||
{
|
||||
vec2 light_dir = normalize(light_tex_pos.zw);
|
||||
float light_distance = length(light_tex_pos.zw);
|
||||
vec2 light_dir = normalize(light_uv_interp.zw);
|
||||
float light_distance = length(light_uv_interp.zw);
|
||||
LIGHT_SHADER_CODE
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if defined(NORMAL_USED)
|
||||
vec2 light_normal = normalize(light_tex_pos.zw);
|
||||
light = color.rgb * light * max(dot(light_normal,normal),0);
|
||||
vec3 light_normal = normalize(vec3(light_uv_interp.zw,-light_height));
|
||||
light*=max(dot(-light_normal,normal),0);
|
||||
#endif
|
||||
|
||||
color.rgb=light;
|
||||
color*=light;
|
||||
/*
|
||||
#ifdef USE_NORMAL
|
||||
color.xy=local_rot.xy;//normal.xy;
|
||||
color.zw=vec2(0.0,1.0);
|
||||
#endif
|
||||
*/
|
||||
if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) {
|
||||
color.a=0.0; //invisible
|
||||
}
|
||||
|
||||
//light shader code
|
||||
#endif
|
||||
|
||||
|
|
62
drivers/gles2/shaders/canvas_shadow.glsl
Normal file
62
drivers/gles2/shaders/canvas_shadow.glsl
Normal file
|
@ -0,0 +1,62 @@
|
|||
[vertex]
|
||||
|
||||
#ifdef USE_GLES_OVER_GL
|
||||
#define mediump
|
||||
#define highp
|
||||
#else
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
#endif
|
||||
|
||||
uniform highp mat4 projection_matrix;
|
||||
uniform highp mat4 light_matrix;
|
||||
uniform highp mat4 world_matrix;
|
||||
|
||||
attribute highp vec3 vertex; // attrib:0
|
||||
|
||||
#ifndef USE_DEPTH_SHADOWS
|
||||
|
||||
varying vec4 position_interp;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void main() {
|
||||
|
||||
gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex,1.0)));
|
||||
|
||||
#ifndef USE_DEPTH_SHADOWS
|
||||
position_interp = gl_Position;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
[fragment]
|
||||
|
||||
#ifdef USE_GLES_OVER_GL
|
||||
#define mediump
|
||||
#define highp
|
||||
#else
|
||||
precision mediump float;
|
||||
precision mediump int;
|
||||
#endif
|
||||
|
||||
#ifndef USE_DEPTH_SHADOWS
|
||||
|
||||
varying vec4 position_interp;
|
||||
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
|
||||
#ifdef USE_DEPTH_SHADOWS
|
||||
|
||||
#else
|
||||
highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias;
|
||||
highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0));
|
||||
comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
|
||||
gl_FragColor = comp;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -28,14 +28,18 @@
|
|||
/*************************************************************************/
|
||||
#ifdef WINDOWS_ENABLED
|
||||
|
||||
#include <Windows.h>
|
||||
#include "Shlwapi.h"
|
||||
#include "file_access_windows.h"
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <wchar.h>
|
||||
#include <tchar.h>
|
||||
#include "print_string.h"
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define S_ISREG(m) ((m)&_S_IFREG)
|
||||
#endif
|
||||
|
@ -111,10 +115,20 @@ void FileAccessWindows::close() {
|
|||
|
||||
//unlink(save_path.utf8().get_data());
|
||||
//print_line("renaming..");
|
||||
_wunlink(save_path.c_str()); //unlink if exists
|
||||
int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str());
|
||||
//_wunlink(save_path.c_str()); //unlink if exists
|
||||
//int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str());
|
||||
|
||||
|
||||
bool rename_error;
|
||||
if (!PathFileExistsW(save_path.c_str())) {
|
||||
//creating new file
|
||||
rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str())!=0;
|
||||
} else {
|
||||
//atomic replace for existing file
|
||||
rename_error = !ReplaceFileW(save_path.c_str(), (save_path+".tmp").c_str(), NULL, 2|4, NULL, NULL);
|
||||
}
|
||||
save_path="";
|
||||
ERR_FAIL_COND( rename_error != 0);
|
||||
ERR_FAIL_COND( rename_error );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -89,6 +89,8 @@ const char *GDFunctions::get_func_name(Function p_func) {
|
|||
"printt",
|
||||
"printerr",
|
||||
"printraw",
|
||||
"var2str",
|
||||
"str2var",
|
||||
"range",
|
||||
"load",
|
||||
"inst2dict",
|
||||
|
@ -577,10 +579,23 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
|
|||
r_ret=Variant();
|
||||
|
||||
} break;
|
||||
case VAR_TO_STR: {
|
||||
VALIDATE_ARG_COUNT(1);
|
||||
r_ret=p_args[0]->get_construct_string();
|
||||
} break;
|
||||
case STR_TO_VAR: {
|
||||
VALIDATE_ARG_COUNT(1);
|
||||
if (p_args[0]->get_type()!=Variant::STRING) {
|
||||
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
|
||||
r_error.argument=0;
|
||||
r_error.expected=Variant::STRING;
|
||||
r_ret=Variant();
|
||||
return;
|
||||
}
|
||||
Variant::construct_from_string(*p_args[0],r_ret);
|
||||
} break;
|
||||
case GEN_RANGE: {
|
||||
|
||||
|
||||
|
||||
switch(p_arg_count) {
|
||||
|
||||
case 0: {
|
||||
|
@ -861,7 +876,6 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
r_ret = gdscr->_new(NULL,0,r_error);
|
||||
|
||||
} break;
|
||||
|
@ -1224,6 +1238,18 @@ MethodInfo GDFunctions::get_info(Function p_func) {
|
|||
return mi;
|
||||
|
||||
} break;
|
||||
case VAR_TO_STR: {
|
||||
MethodInfo mi("var2str",PropertyInfo(Variant::NIL,"var"));
|
||||
mi.return_val.type=Variant::STRING;
|
||||
return mi;
|
||||
|
||||
} break;
|
||||
case STR_TO_VAR: {
|
||||
|
||||
MethodInfo mi("str2var:var",PropertyInfo(Variant::STRING,"string"));
|
||||
mi.return_val.type=Variant::NIL;
|
||||
return mi;
|
||||
} break;
|
||||
case GEN_RANGE: {
|
||||
|
||||
MethodInfo mi("range",PropertyInfo(Variant::NIL,"..."));
|
||||
|
|
|
@ -85,6 +85,8 @@ public:
|
|||
TEXT_PRINT_TABBED,
|
||||
TEXT_PRINTERR,
|
||||
TEXT_PRINTRAW,
|
||||
VAR_TO_STR,
|
||||
STR_TO_VAR,
|
||||
GEN_RANGE,
|
||||
RESOURCE_LOAD,
|
||||
INST2DICT,
|
||||
|
|
|
@ -2696,7 +2696,10 @@ Error ResourceFormatSaverGDScript::save(const String &p_path,const RES& p_resour
|
|||
}
|
||||
|
||||
file->store_string(source);
|
||||
|
||||
if (file->get_error()!=OK && file->get_error()!=ERR_FILE_EOF) {
|
||||
memdelete(file);
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
file->close();
|
||||
memdelete(file);
|
||||
return OK;
|
||||
|
|
|
@ -539,10 +539,11 @@ void GDTokenizerText::_advance() {
|
|||
|
||||
case '\'':
|
||||
case '"': {
|
||||
|
||||
|
||||
if (GETCHAR(0)=='\'')
|
||||
string_mode=STRING_SINGLE_QUOTE;
|
||||
|
||||
|
||||
|
||||
int i=1;
|
||||
if (string_mode==STRING_DOUBLE_QUOTE && GETCHAR(i)=='"' && GETCHAR(i+1)=='"') {
|
||||
i+=2;
|
||||
|
|
|
@ -396,6 +396,14 @@ void AudioDriverOpenSL::finish(){
|
|||
void AudioDriverOpenSL::set_pause(bool p_pause) {
|
||||
|
||||
pause=p_pause;
|
||||
|
||||
if (active) {
|
||||
if (pause) {
|
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED);
|
||||
} else {
|
||||
(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_
|
|||
sample_manager = memnew( SampleManagerMallocSW );
|
||||
audio_server = memnew( AudioServerSW(sample_manager) );
|
||||
|
||||
audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
|
||||
audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,true);
|
||||
audio_server->init();
|
||||
|
||||
spatial_sound_server = memnew( SpatialSoundServerSW );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -415,7 +415,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)
|
||||
{
|
||||
|
@ -429,8 +441,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)
|
||||
|
@ -443,7 +460,11 @@ static void clear_touches() {
|
|||
{
|
||||
animationInterval = interval;
|
||||
|
||||
#if USE_CADISPLAYLINK
|
||||
if(displayLink)
|
||||
#else
|
||||
if(animationTimer)
|
||||
#endif
|
||||
{
|
||||
[self stopAnimation];
|
||||
[self startAnimation];
|
||||
|
@ -453,6 +474,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;
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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:(NSRect){.origin=pointInWindow}].origin;
|
||||
|
||||
//point in scren coords
|
||||
CGPoint lMouseWarpPos = { pointOnScreen.x, pointOnScreen.y};
|
||||
|
||||
//do the warping
|
||||
CGEventSourceRef lEventRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
|
||||
CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0);
|
||||
CGAssociateMouseAndMouseCursorPosition(false);
|
||||
|
|
|
@ -115,7 +115,7 @@ def configure(env):
|
|||
env.Append(CCFLAGS=['/DGLES2_ENABLED'])
|
||||
|
||||
env.Append(CCFLAGS=['/DGLEW_ENABLED'])
|
||||
LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI', 'wsock32', 'shell32','advapi32']
|
||||
LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI','Shlwapi', 'wsock32', 'shell32','advapi32']
|
||||
env.Append(LINKFLAGS=[p+env["LIBSUFFIX"] for p in LIBS])
|
||||
|
||||
env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"])
|
||||
|
@ -229,7 +229,7 @@ def configure(env):
|
|||
env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows'])
|
||||
env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED'])
|
||||
env.Append(CCFLAGS=['-DGLES2_ENABLED','-DGLEW_ENABLED'])
|
||||
env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','wsock32','kernel32'])
|
||||
env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','shlwapi','wsock32','kernel32'])
|
||||
|
||||
if (env["bits"]=="32" and env["mingw64_for_32"]!="yes"):
|
||||
# env.Append(LIBS=['gcc_s'])
|
||||
|
|
|
@ -54,10 +54,16 @@
|
|||
#include "io/marshalls.h"
|
||||
|
||||
#include "shlobj.h"
|
||||
#include <regstr.h>
|
||||
|
||||
static const WORD MAX_CONSOLE_LINES = 1500;
|
||||
|
||||
extern "C" {
|
||||
#ifdef _MSC_VER
|
||||
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
#else
|
||||
__attribute__((visibility("default"))) DWORD NvOptimusEnablement = 0x00000001;
|
||||
#endif
|
||||
}
|
||||
|
||||
//#define STDOUT_FILE
|
||||
|
@ -589,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;
|
||||
|
||||
|
@ -680,6 +687,53 @@ 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)
|
||||
{
|
||||
res = RegOpenKeyEx(HKEY_CURRENT_USER, 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;
|
||||
|
@ -721,7 +775,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;
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1377,9 +1437,13 @@ void OS_Windows::warp_mouse_pos(const Point2& p_to) {
|
|||
old_y=p_to.y;
|
||||
} else {
|
||||
|
||||
SetCursorPos(p_to.x, p_to.y);
|
||||
}
|
||||
POINT p;
|
||||
p.x=p_to.x;
|
||||
p.y=p_to.y;
|
||||
ClientToScreen(hWnd,&p);
|
||||
|
||||
SetCursorPos(p.x,p.y);
|
||||
}
|
||||
}
|
||||
|
||||
Point2 OS_Windows::get_mouse_pos() const {
|
||||
|
|
|
@ -187,6 +187,7 @@ protected:
|
|||
void probe_joysticks();
|
||||
void process_joysticks();
|
||||
void process_key_events();
|
||||
String get_joystick_name( int id, JOYCAPS jcaps);
|
||||
|
||||
struct ProcessInfo {
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "drivers/gles2/rasterizer_gles2.h"
|
||||
#include "drivers/gles1/rasterizer_gles1.h"
|
||||
#include "os_winrt.h"
|
||||
#include "drivers/nedmalloc/memory_pool_static_nedmalloc.h"
|
||||
#include "drivers/unix/memory_pool_static_malloc.h"
|
||||
|
@ -62,11 +61,11 @@ using namespace Microsoft::WRL;
|
|||
|
||||
int OSWinrt::get_video_driver_count() const {
|
||||
|
||||
return 2;
|
||||
return 1;
|
||||
}
|
||||
const char * OSWinrt::get_video_driver_name(int p_driver) const {
|
||||
|
||||
return p_driver==0?"GLES2":"GLES1";
|
||||
return "GLES2";
|
||||
}
|
||||
|
||||
OS::VideoMode OSWinrt::get_default_video_mode() const {
|
||||
|
|
|
@ -70,24 +70,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
|
||||
|
@ -141,11 +140,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') } )
|
||||
|
|
|
@ -479,8 +479,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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,192 @@
|
|||
#include "scene/resources/texture.h"
|
||||
#include "scene/resources/style_box.h"
|
||||
|
||||
|
||||
bool CanvasItemMaterial::_set(const StringName& p_name, const Variant& p_value) {
|
||||
|
||||
if (p_name==SceneStringNames::get_singleton()->shader_shader) {
|
||||
set_shader(p_value);
|
||||
return true;
|
||||
} else if (p_name==SceneStringNames::get_singleton()->shader_unshaded) {
|
||||
set_unshaded(p_value);
|
||||
print_line("set unshaded");
|
||||
return true;
|
||||
} else {
|
||||
|
||||
if (shader.is_valid()) {
|
||||
|
||||
|
||||
StringName pr = shader->remap_param(p_name);
|
||||
if (!pr) {
|
||||
String n = p_name;
|
||||
if (n.find("param/")==0) { //backwards compatibility
|
||||
pr = n.substr(6,n.length());
|
||||
}
|
||||
}
|
||||
if (pr) {
|
||||
VisualServer::get_singleton()->canvas_item_material_set_shader_param(material,pr,p_value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CanvasItemMaterial::_get(const StringName& p_name,Variant &r_ret) const {
|
||||
|
||||
|
||||
if (p_name==SceneStringNames::get_singleton()->shader_shader) {
|
||||
|
||||
r_ret=get_shader();
|
||||
return true;
|
||||
} else if (p_name==SceneStringNames::get_singleton()->shader_unshaded) {
|
||||
|
||||
|
||||
r_ret=unshaded;
|
||||
return true;
|
||||
} else {
|
||||
|
||||
if (shader.is_valid()) {
|
||||
|
||||
StringName pr = shader->remap_param(p_name);
|
||||
if (pr) {
|
||||
r_ret=VisualServer::get_singleton()->canvas_item_material_get_shader_param(material,pr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CanvasItemMaterial::_get_property_list( List<PropertyInfo> *p_list) const {
|
||||
|
||||
p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"CanvasItemShader,CanvasItemShaderGraph" ) );
|
||||
p_list->push_back( PropertyInfo( Variant::BOOL, "shader/unshaded") );
|
||||
|
||||
if (!shader.is_null()) {
|
||||
|
||||
shader->get_param_list(p_list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CanvasItemMaterial::set_shader(const Ref<Shader>& p_shader) {
|
||||
|
||||
ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode()!=Shader::MODE_CANVAS_ITEM);
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
if (shader.is_valid()) {
|
||||
shader->disconnect("changed",this,"_shader_changed");
|
||||
}
|
||||
#endif
|
||||
shader=p_shader;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
if (shader.is_valid()) {
|
||||
shader->connect("changed",this,"_shader_changed");
|
||||
}
|
||||
#endif
|
||||
|
||||
RID rid;
|
||||
if (shader.is_valid())
|
||||
rid=shader->get_rid();
|
||||
|
||||
VS::get_singleton()->canvas_item_material_set_shader(material,rid);
|
||||
_change_notify(); //properties for shader exposed
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
Ref<Shader> CanvasItemMaterial::get_shader() const{
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
void CanvasItemMaterial::set_shader_param(const StringName& p_param,const Variant& p_value){
|
||||
|
||||
VS::get_singleton()->canvas_item_material_set_shader_param(material,p_param,p_value);
|
||||
}
|
||||
|
||||
Variant CanvasItemMaterial::get_shader_param(const StringName& p_param) const{
|
||||
|
||||
return VS::get_singleton()->canvas_item_material_get_shader_param(material,p_param);
|
||||
}
|
||||
|
||||
void CanvasItemMaterial::_shader_changed() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
RID CanvasItemMaterial::get_rid() const {
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
void CanvasItemMaterial::set_unshaded(bool p_unshaded) {
|
||||
|
||||
unshaded=p_unshaded;
|
||||
VS::get_singleton()->canvas_item_material_set_unshaded(material,p_unshaded);
|
||||
}
|
||||
|
||||
bool CanvasItemMaterial::is_unshaded() const{
|
||||
|
||||
return unshaded;
|
||||
}
|
||||
|
||||
void CanvasItemMaterial::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_shader","shader:Shader"),&CanvasItemMaterial::set_shader);
|
||||
ObjectTypeDB::bind_method(_MD("get_shader:Shader"),&CanvasItemMaterial::get_shader);
|
||||
ObjectTypeDB::bind_method(_MD("set_shader_param","param","value"),&CanvasItemMaterial::set_shader_param);
|
||||
ObjectTypeDB::bind_method(_MD("get_shader_param","param"),&CanvasItemMaterial::get_shader_param);
|
||||
ObjectTypeDB::bind_method(_MD("set_unshaded","unshaded"),&CanvasItemMaterial::set_unshaded);
|
||||
ObjectTypeDB::bind_method(_MD("is_unshaded"),&CanvasItemMaterial::is_unshaded);
|
||||
|
||||
}
|
||||
|
||||
void CanvasItemMaterial::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
|
||||
|
||||
String f = p_function.operator String();
|
||||
if ((f=="get_shader_param" || f=="set_shader_param") && p_idx==0) {
|
||||
|
||||
if (shader.is_valid()) {
|
||||
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/","")+"\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
Resource::get_argument_options(p_function,p_idx,r_options);
|
||||
}
|
||||
|
||||
CanvasItemMaterial::CanvasItemMaterial() {
|
||||
|
||||
material=VS::get_singleton()->canvas_item_material_create();
|
||||
unshaded=false;
|
||||
}
|
||||
|
||||
CanvasItemMaterial::~CanvasItemMaterial(){
|
||||
|
||||
VS::get_singleton()->free(material);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
bool CanvasItem::is_visible() const {
|
||||
|
||||
if (!is_inside_tree())
|
||||
|
@ -458,6 +644,16 @@ CanvasItem::BlendMode CanvasItem::get_blend_mode() const {
|
|||
return blend_mode;
|
||||
}
|
||||
|
||||
void CanvasItem::set_light_mask(int p_light_mask) {
|
||||
|
||||
light_mask=p_light_mask;
|
||||
VS::get_singleton()->canvas_item_set_light_mask(canvas_item,p_light_mask);
|
||||
}
|
||||
|
||||
int CanvasItem::get_light_mask() const{
|
||||
|
||||
return light_mask;
|
||||
}
|
||||
|
||||
|
||||
void CanvasItem::item_rect_changed() {
|
||||
|
@ -511,7 +707,7 @@ void CanvasItem::draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos)
|
|||
p_texture->draw(canvas_item,p_pos);
|
||||
}
|
||||
|
||||
void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_rect, bool p_tile,const Color& p_modulate) {
|
||||
void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) {
|
||||
|
||||
if (!drawing) {
|
||||
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
|
||||
|
@ -519,17 +715,17 @@ void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_
|
|||
}
|
||||
|
||||
ERR_FAIL_COND(p_texture.is_null());
|
||||
p_texture->draw_rect(canvas_item,p_rect,p_tile,p_modulate);
|
||||
p_texture->draw_rect(canvas_item,p_rect,p_tile,p_modulate,p_transpose);
|
||||
|
||||
}
|
||||
void CanvasItem::draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) {
|
||||
void CanvasItem::draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) {
|
||||
|
||||
if (!drawing) {
|
||||
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
|
||||
ERR_FAIL();
|
||||
}
|
||||
ERR_FAIL_COND(p_texture.is_null());
|
||||
p_texture->draw_rect_region(canvas_item,p_rect,p_src_rect,p_modulate);
|
||||
p_texture->draw_rect_region(canvas_item,p_rect,p_src_rect,p_modulate,p_transpose);
|
||||
}
|
||||
|
||||
void CanvasItem::draw_style_box(const Ref<StyleBox>& p_style_box,const Rect2& p_rect) {
|
||||
|
@ -720,95 +916,36 @@ bool CanvasItem::is_draw_behind_parent_enabled() const{
|
|||
return behind;
|
||||
}
|
||||
|
||||
void CanvasItem::set_shader(const Ref<Shader>& p_shader) {
|
||||
void CanvasItem::set_material(const Ref<CanvasItemMaterial>& p_material) {
|
||||
|
||||
ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode()!=Shader::MODE_CANVAS_ITEM);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
if (shader.is_valid()) {
|
||||
shader->disconnect("changed",this,"_shader_changed");
|
||||
}
|
||||
#endif
|
||||
shader=p_shader;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
if (shader.is_valid()) {
|
||||
shader->connect("changed",this,"_shader_changed");
|
||||
}
|
||||
#endif
|
||||
|
||||
material=p_material;
|
||||
RID rid;
|
||||
if (shader.is_valid())
|
||||
rid=shader->get_rid();
|
||||
VS::get_singleton()->canvas_item_set_shader(canvas_item,rid);
|
||||
_change_notify(); //properties for shader exposed
|
||||
if (material.is_valid())
|
||||
rid=material->get_rid();
|
||||
VS::get_singleton()->canvas_item_set_material(canvas_item,rid);
|
||||
_change_notify(); //properties for material exposed
|
||||
}
|
||||
|
||||
void CanvasItem::set_use_parent_shader(bool p_use_parent_shader) {
|
||||
void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
|
||||
|
||||
use_parent_shader=p_use_parent_shader;
|
||||
VS::get_singleton()->canvas_item_set_use_parent_shader(canvas_item,p_use_parent_shader);
|
||||
use_parent_material=p_use_parent_material;
|
||||
VS::get_singleton()->canvas_item_set_use_parent_material(canvas_item,p_use_parent_material);
|
||||
}
|
||||
|
||||
bool CanvasItem::get_use_parent_shader() const{
|
||||
bool CanvasItem::get_use_parent_material() const{
|
||||
|
||||
return use_parent_shader;
|
||||
return use_parent_material;
|
||||
}
|
||||
|
||||
Ref<Shader> CanvasItem::get_shader() const{
|
||||
Ref<CanvasItemMaterial> CanvasItem::get_material() const{
|
||||
|
||||
return shader;
|
||||
return material;
|
||||
}
|
||||
|
||||
void CanvasItem::set_shader_param(const StringName& p_param,const Variant& p_value) {
|
||||
|
||||
VS::get_singleton()->canvas_item_set_shader_param(canvas_item,p_param,p_value);
|
||||
}
|
||||
|
||||
Variant CanvasItem::get_shader_param(const StringName& p_param) const {
|
||||
|
||||
return VS::get_singleton()->canvas_item_get_shader_param(canvas_item,p_param);
|
||||
}
|
||||
|
||||
bool CanvasItem::_set(const StringName& p_name, const Variant& p_value) {
|
||||
|
||||
if (shader.is_valid()) {
|
||||
StringName pr = shader->remap_param(p_name);
|
||||
if (pr) {
|
||||
set_shader_param(pr,p_value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CanvasItem::_get(const StringName& p_name,Variant &r_ret) const{
|
||||
|
||||
if (shader.is_valid()) {
|
||||
StringName pr = shader->remap_param(p_name);
|
||||
if (pr) {
|
||||
r_ret=get_shader_param(pr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
void CanvasItem::_get_property_list( List<PropertyInfo> *p_list) const{
|
||||
|
||||
if (shader.is_valid()) {
|
||||
shader->get_param_list(p_list);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void CanvasItem::_shader_changed() {
|
||||
|
||||
_change_notify();
|
||||
}
|
||||
#endif
|
||||
|
||||
void CanvasItem::_bind_methods() {
|
||||
|
||||
|
@ -840,19 +977,19 @@ void CanvasItem::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("set_blend_mode","blend_mode"),&CanvasItem::set_blend_mode);
|
||||
ObjectTypeDB::bind_method(_MD("get_blend_mode"),&CanvasItem::get_blend_mode);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_light_mask","light_mask"),&CanvasItem::set_light_mask);
|
||||
ObjectTypeDB::bind_method(_MD("get_light_mask"),&CanvasItem::get_light_mask);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_opacity","opacity"),&CanvasItem::set_opacity);
|
||||
ObjectTypeDB::bind_method(_MD("get_opacity"),&CanvasItem::get_opacity);
|
||||
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);
|
||||
ObjectTypeDB::bind_method(_MD("_is_on_top"),&CanvasItem::_is_on_top);
|
||||
#ifdef TOOLS_ENABLED
|
||||
ObjectTypeDB::bind_method(_MD("_shader_changed"),&CanvasItem::_shader_changed);
|
||||
#endif
|
||||
//ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("draw_line","from","to","color","width"),&CanvasItem::draw_line,DEFVAL(1.0));
|
||||
|
@ -871,16 +1008,18 @@ void CanvasItem::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("draw_set_transform","pos","rot","scale"),&CanvasItem::draw_set_transform);
|
||||
ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform);
|
||||
ObjectTypeDB::bind_method(_MD("get_global_transform"),&CanvasItem::get_global_transform);
|
||||
ObjectTypeDB::bind_method(_MD("get_global_transform_with_canvas"),&CanvasItem::get_global_transform_with_canvas);
|
||||
ObjectTypeDB::bind_method(_MD("get_viewport_transform"),&CanvasItem::get_viewport_transform);
|
||||
ObjectTypeDB::bind_method(_MD("get_viewport_rect"),&CanvasItem::get_viewport_rect);
|
||||
ObjectTypeDB::bind_method(_MD("get_canvas"),&CanvasItem::get_canvas);
|
||||
ObjectTypeDB::bind_method(_MD("get_world_2d"),&CanvasItem::get_world_2d);
|
||||
//ObjectTypeDB::bind_method(_MD("get_viewport"),&CanvasItem::get_viewport);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_shader","shader"),&CanvasItem::set_shader);
|
||||
ObjectTypeDB::bind_method(_MD("get_shader"),&CanvasItem::get_shader);
|
||||
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_material","material:CanvasItemMaterial"),&CanvasItem::set_material);
|
||||
ObjectTypeDB::bind_method(_MD("get_material:CanvasItemMaterial"),&CanvasItem::get_material);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_use_parent_material","enable"),&CanvasItem::set_use_parent_material);
|
||||
ObjectTypeDB::bind_method(_MD("get_use_parent_material"),&CanvasItem::get_use_parent_material);
|
||||
|
||||
BIND_VMETHOD(MethodInfo("_draw"));
|
||||
|
||||
|
@ -891,8 +1030,9 @@ void CanvasItem::_bind_methods() {
|
|||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/on_top",PROPERTY_HINT_NONE,"",0), _SCS("_set_on_top"),_SCS("_is_on_top") ); //compatibility
|
||||
|
||||
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,PMAlpha"), _SCS("set_blend_mode"),_SCS("get_blend_mode") );
|
||||
ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"shader/shader",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemShader,CanvasItemShaderGraph"), _SCS("set_shader"),_SCS("get_shader") );
|
||||
ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"shader/use_parent"), _SCS("set_use_parent_shader"),_SCS("get_use_parent_shader") );
|
||||
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") );
|
||||
ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"material/material",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial"), _SCS("set_material"),_SCS("get_material") );
|
||||
ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"material/use_parent"), _SCS("set_use_parent_material"),_SCS("get_use_parent_material") );
|
||||
//exporting these two things doesn't really make much sense i think
|
||||
//ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), _SCS("set_as_toplevel"),_SCS("is_set_as_toplevel") );
|
||||
//ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),_SCS("set_transform_notify"),_SCS("is_transform_notify_enabled"));
|
||||
|
@ -969,8 +1109,9 @@ CanvasItem::CanvasItem() : xform_change(this) {
|
|||
block_transform_notify=false;
|
||||
// viewport=NULL;
|
||||
canvas_layer=NULL;
|
||||
use_parent_shader;
|
||||
use_parent_material=false;
|
||||
global_invalid=true;
|
||||
light_mask=1;
|
||||
|
||||
C=NULL;
|
||||
|
||||
|
|
|
@ -40,6 +40,41 @@ class Font;
|
|||
|
||||
class StyleBox;
|
||||
|
||||
class CanvasItemMaterial : public Resource{
|
||||
|
||||
OBJ_TYPE(CanvasItemMaterial,Resource);
|
||||
RID material;
|
||||
Ref<Shader> shader;
|
||||
bool unshaded;
|
||||
|
||||
protected:
|
||||
|
||||
bool _set(const StringName& p_name, const Variant& p_value);
|
||||
bool _get(const StringName& p_name,Variant &r_ret) const;
|
||||
void _get_property_list( List<PropertyInfo> *p_list) const;
|
||||
|
||||
void _shader_changed();
|
||||
static void _bind_methods();
|
||||
|
||||
void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
|
||||
|
||||
public:
|
||||
|
||||
void set_shader(const Ref<Shader>& p_shader);
|
||||
Ref<Shader> get_shader() const;
|
||||
|
||||
void set_shader_param(const StringName& p_param,const Variant& p_value);
|
||||
Variant get_shader_param(const StringName& p_param) const;
|
||||
|
||||
void set_unshaded(bool p_unshaded);
|
||||
bool is_unshaded() const;
|
||||
|
||||
virtual RID get_rid() const;
|
||||
CanvasItemMaterial();
|
||||
~CanvasItemMaterial();
|
||||
};
|
||||
|
||||
|
||||
class CanvasItem : public Node {
|
||||
|
||||
OBJ_TYPE( CanvasItem, Node );
|
||||
|
@ -71,6 +106,7 @@ private:
|
|||
List<CanvasItem*>::Element *C;
|
||||
|
||||
BlendMode blend_mode;
|
||||
int light_mask;
|
||||
|
||||
bool first_draw;
|
||||
bool hidden;
|
||||
|
@ -80,9 +116,9 @@ private:
|
|||
bool drawing;
|
||||
bool block_transform_notify;
|
||||
bool behind;
|
||||
bool use_parent_material;
|
||||
|
||||
bool use_parent_shader;
|
||||
Ref<Shader> shader;
|
||||
Ref<CanvasItemMaterial> material;
|
||||
|
||||
mutable Matrix32 global_transform;
|
||||
mutable bool global_invalid;
|
||||
|
@ -103,9 +139,6 @@ private:
|
|||
void _queue_sort_children();
|
||||
void _sort_children();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
void _shader_changed();
|
||||
#endif
|
||||
void _notify_transform(CanvasItem *p_node);
|
||||
|
||||
void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); }
|
||||
|
@ -113,11 +146,6 @@ private:
|
|||
|
||||
protected:
|
||||
|
||||
bool _set(const StringName& p_name, const Variant& p_value);
|
||||
bool _get(const StringName& p_name,Variant &r_ret) const;
|
||||
void _get_property_list( List<PropertyInfo> *p_list) const;
|
||||
|
||||
|
||||
_FORCE_INLINE_ void _notify_transform() { if (!is_inside_tree()) return; _notify_transform(this); if (!block_transform_notify) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); }
|
||||
|
||||
void item_rect_changed();
|
||||
|
@ -158,6 +186,9 @@ public:
|
|||
void set_blend_mode(BlendMode p_blend_mode);
|
||||
BlendMode get_blend_mode() const;
|
||||
|
||||
void set_light_mask(int p_light_mask);
|
||||
int get_light_mask() const;
|
||||
|
||||
void set_opacity(float p_opacity);
|
||||
float get_opacity() const;
|
||||
|
||||
|
@ -170,8 +201,8 @@ public:
|
|||
void draw_rect(const Rect2& p_rect, const Color& p_color);
|
||||
void draw_circle(const Point2& p_pos, float p_radius, const Color& p_color);
|
||||
void draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos);
|
||||
void draw_texture_rect(const Ref<Texture>& p_texture, const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1));
|
||||
void draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1));
|
||||
void draw_texture_rect(const Ref<Texture>& p_texture, const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false);
|
||||
void draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false);
|
||||
void draw_style_box(const Ref<StyleBox>& p_style_box,const Rect2& p_rect);
|
||||
void draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, Ref<Texture> p_texture=Ref<Texture>(),float p_width=1);
|
||||
void draw_polygon(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), Ref<Texture> p_texture=Ref<Texture>());
|
||||
|
@ -212,14 +243,12 @@ public:
|
|||
RID get_canvas() const;
|
||||
Ref<World2D> get_world_2d() const;
|
||||
|
||||
void set_shader(const Ref<Shader>& p_shader);
|
||||
Ref<Shader> get_shader() const;
|
||||
void set_material(const Ref<CanvasItemMaterial>& p_material);
|
||||
Ref<CanvasItemMaterial> get_material() const;
|
||||
|
||||
void set_use_parent_shader(bool p_use_parent_shader);
|
||||
bool get_use_parent_shader() const;
|
||||
void set_use_parent_material(bool p_use_parent_material);
|
||||
bool get_use_parent_material() const;
|
||||
|
||||
void set_shader_param(const StringName& p_param,const Variant& p_value);
|
||||
Variant get_shader_param(const StringName& p_param) const;
|
||||
|
||||
CanvasItem();
|
||||
~CanvasItem();
|
||||
|
|
46
scene/2d/canvas_modulate.cpp
Normal file
46
scene/2d/canvas_modulate.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "canvas_modulate.h"
|
||||
|
||||
|
||||
void CanvasModulate::_notification(int p_what) {
|
||||
|
||||
if (p_what==NOTIFICATION_ENTER_CANVAS) {
|
||||
|
||||
VS::get_singleton()->canvas_set_modulate(get_canvas(),color);
|
||||
} else if (p_what==NOTIFICATION_EXIT_CANVAS) {
|
||||
|
||||
VS::get_singleton()->canvas_set_modulate(get_canvas(),Color(1,1,1,1));
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasModulate::_bind_methods(){
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_color","color"),&CanvasModulate::set_color);
|
||||
ObjectTypeDB::bind_method(_MD("get_color"),&CanvasModulate::get_color);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color"));
|
||||
}
|
||||
|
||||
|
||||
void CanvasModulate::set_color(const Color& p_color){
|
||||
|
||||
color=p_color;
|
||||
if (is_inside_tree()) {
|
||||
VS::get_singleton()->canvas_set_modulate(get_canvas(),color);
|
||||
}
|
||||
}
|
||||
Color CanvasModulate::get_color() const {
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
CanvasModulate::CanvasModulate()
|
||||
{
|
||||
color=Color(1,1,1,1);
|
||||
}
|
||||
|
||||
CanvasModulate::~CanvasModulate()
|
||||
{
|
||||
|
||||
}
|
||||
|
23
scene/2d/canvas_modulate.h
Normal file
23
scene/2d/canvas_modulate.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef CANVASMODULATE_H
|
||||
#define CANVASMODULATE_H
|
||||
|
||||
#include "scene/2d/node_2d.h"
|
||||
|
||||
class CanvasModulate : public Node2D {
|
||||
|
||||
OBJ_TYPE(CanvasModulate,Node2D);
|
||||
|
||||
Color color;
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
void set_color(const Color& p_color);
|
||||
Color get_color() const;
|
||||
|
||||
CanvasModulate();
|
||||
~CanvasModulate();
|
||||
};
|
||||
|
||||
#endif // CANVASMODULATE_H
|
300
scene/2d/light_2d.cpp
Normal file
300
scene/2d/light_2d.cpp
Normal file
|
@ -0,0 +1,300 @@
|
|||
#include "light_2d.h"
|
||||
#include "servers/visual_server.h"
|
||||
|
||||
void Light2D::edit_set_pivot(const Point2& p_pivot) {
|
||||
|
||||
set_texture_offset(p_pivot);
|
||||
|
||||
}
|
||||
|
||||
Point2 Light2D::edit_get_pivot() const {
|
||||
|
||||
return get_texture_offset();
|
||||
}
|
||||
bool Light2D::edit_has_pivot() const {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Rect2 Light2D::get_item_rect() const {
|
||||
|
||||
if (texture.is_null())
|
||||
return Rect2(0,0,1,1);
|
||||
|
||||
Size2i s;
|
||||
|
||||
s = texture->get_size();
|
||||
Point2i ofs=texture_offset;
|
||||
ofs-=s/2;
|
||||
|
||||
if (s==Size2(0,0))
|
||||
s=Size2(1,1);
|
||||
|
||||
return Rect2(ofs,s);
|
||||
}
|
||||
|
||||
|
||||
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_layer_range_min( int p_min_layer) {
|
||||
|
||||
layer_min=p_min_layer;
|
||||
VS::get_singleton()->canvas_light_set_layer_range(canvas_light,layer_min,layer_max);
|
||||
|
||||
}
|
||||
int Light2D::get_layer_range_min() const {
|
||||
|
||||
return layer_min;
|
||||
}
|
||||
|
||||
void Light2D::set_layer_range_max( int p_max_layer) {
|
||||
|
||||
layer_max=p_max_layer;
|
||||
VS::get_singleton()->canvas_light_set_layer_range(canvas_light,layer_min,layer_max);
|
||||
|
||||
}
|
||||
int Light2D::get_layer_range_max() const {
|
||||
|
||||
return layer_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_subtract_mode( bool p_enable ) {
|
||||
|
||||
subtract_mode=p_enable;
|
||||
VS::get_singleton()->canvas_light_set_subtract_mode(canvas_light,p_enable);
|
||||
}
|
||||
|
||||
bool Light2D::get_subtract_mode() const {
|
||||
|
||||
return subtract_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::set_shadow_buffer_size( int p_size ) {
|
||||
|
||||
shadow_buffer_size=p_size;
|
||||
VS::get_singleton()->canvas_light_set_shadow_buffer_size(canvas_light,shadow_buffer_size);
|
||||
}
|
||||
|
||||
int Light2D::get_shadow_buffer_size() const {
|
||||
|
||||
return shadow_buffer_size;
|
||||
}
|
||||
|
||||
void Light2D::set_shadow_esm_multiplier( float p_multiplier) {
|
||||
|
||||
shadow_esm_multiplier=p_multiplier;
|
||||
VS::get_singleton()->canvas_light_set_shadow_esm_multiplier(canvas_light,p_multiplier);
|
||||
}
|
||||
|
||||
float Light2D::get_shadow_esm_multiplier() const{
|
||||
|
||||
return shadow_esm_multiplier;
|
||||
}
|
||||
|
||||
|
||||
void Light2D::_notification(int p_what) {
|
||||
|
||||
if (p_what==NOTIFICATION_ENTER_TREE) {
|
||||
|
||||
VS::get_singleton()->canvas_light_attach_to_canvas( canvas_light, get_canvas() );
|
||||
}
|
||||
|
||||
if (p_what==NOTIFICATION_TRANSFORM_CHANGED) {
|
||||
|
||||
VS::get_singleton()->canvas_light_set_transform( canvas_light, get_global_transform());
|
||||
}
|
||||
|
||||
if (p_what==NOTIFICATION_EXIT_TREE) {
|
||||
|
||||
VS::get_singleton()->canvas_light_attach_to_canvas( canvas_light, RID() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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_layer_range_min","layer"),&Light2D::set_layer_range_min);
|
||||
ObjectTypeDB::bind_method(_MD("get_layer_range_min"),&Light2D::get_layer_range_min);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_layer_range_max","layer"),&Light2D::set_layer_range_max);
|
||||
ObjectTypeDB::bind_method(_MD("get_layer_range_max"),&Light2D::get_layer_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_subtract_mode","enable"),&Light2D::set_subtract_mode);
|
||||
ObjectTypeDB::bind_method(_MD("get_subtract_mode"),&Light2D::get_subtract_mode);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_shadow_enabled","enabled"),&Light2D::set_shadow_enabled);
|
||||
ObjectTypeDB::bind_method(_MD("is_shadow_enabled"),&Light2D::is_shadow_enabled);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_shadow_buffer_size","size"),&Light2D::set_shadow_buffer_size);
|
||||
ObjectTypeDB::bind_method(_MD("get_shadow_buffer_size"),&Light2D::get_shadow_buffer_size);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_shadow_esm_multiplier","multiplier"),&Light2D::set_shadow_esm_multiplier);
|
||||
ObjectTypeDB::bind_method(_MD("get_shadow_esm_multiplier"),&Light2D::get_shadow_esm_multiplier);
|
||||
|
||||
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,"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::BOOL,"subtract"),_SCS("set_subtract_mode"),_SCS("get_subtract_mode"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::REAL,"range/height"),_SCS("set_height"),_SCS("get_height"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_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,"range/z_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,"range/layer_min",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_min"),_SCS("get_layer_range_min"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_max",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_max"),_SCS("get_layer_range_max"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::INT,"range/item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_mask"),_SCS("get_item_mask"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow/enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/buffer_size",PROPERTY_HINT_RANGE,"32,16384,1"),_SCS("set_shadow_buffer_size"),_SCS("get_shadow_buffer_size"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::REAL,"shadow/esm_multiplier",PROPERTY_HINT_RANGE,"1,4096,0.1"),_SCS("set_shadow_esm_multiplier"),_SCS("get_shadow_esm_multiplier"));
|
||||
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
layer_min=0;
|
||||
layer_max=0;
|
||||
item_mask=1;
|
||||
subtract_mode=false;
|
||||
shadow_buffer_size=2048;
|
||||
shadow_esm_multiplier=80;
|
||||
|
||||
}
|
||||
|
||||
Light2D::~Light2D() {
|
||||
|
||||
VisualServer::get_singleton()->free(canvas_light);
|
||||
}
|
86
scene/2d/light_2d.h
Normal file
86
scene/2d/light_2d.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
#ifndef LIGHT_2D_H
|
||||
#define LIGHT_2D_H
|
||||
|
||||
#include "scene/2d/node_2d.h"
|
||||
|
||||
class Light2D : public Node2D {
|
||||
|
||||
OBJ_TYPE(Light2D,Node2D);
|
||||
private:
|
||||
RID canvas_light;
|
||||
bool enabled;
|
||||
bool shadow;
|
||||
Color color;
|
||||
float height;
|
||||
int z_min;
|
||||
int z_max;
|
||||
int layer_min;
|
||||
int layer_max;
|
||||
int item_mask;
|
||||
int shadow_buffer_size;
|
||||
float shadow_esm_multiplier;
|
||||
bool subtract_mode;
|
||||
Ref<Texture> texture;
|
||||
Vector2 texture_offset;
|
||||
|
||||
protected:
|
||||
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
|
||||
virtual void edit_set_pivot(const Point2& p_pivot);
|
||||
virtual Point2 edit_get_pivot() const;
|
||||
virtual bool edit_has_pivot() const;
|
||||
|
||||
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_layer_range_min( int p_min_layer);
|
||||
int get_layer_range_min() const;
|
||||
|
||||
void set_layer_range_max( int p_max_layer);
|
||||
int get_layer_range_max() const;
|
||||
|
||||
void set_item_mask( int p_mask);
|
||||
int get_item_mask() const;
|
||||
|
||||
void set_subtract_mode( bool p_enable );
|
||||
bool get_subtract_mode() const;
|
||||
|
||||
void set_shadow_enabled( bool p_enabled);
|
||||
bool is_shadow_enabled() const;
|
||||
|
||||
void set_shadow_buffer_size( int p_size );
|
||||
int get_shadow_buffer_size() const;
|
||||
|
||||
void set_shadow_esm_multiplier( float p_multiplier);
|
||||
float get_shadow_esm_multiplier() const;
|
||||
|
||||
virtual Rect2 get_item_rect() const;
|
||||
|
||||
Light2D();
|
||||
~Light2D();
|
||||
};
|
||||
|
||||
|
||||
#endif // LIGHT_2D_H
|
201
scene/2d/light_occluder_2d.cpp
Normal file
201
scene/2d/light_occluder_2d.cpp
Normal file
|
@ -0,0 +1,201 @@
|
|||
#include "light_occluder_2d.h"
|
||||
|
||||
|
||||
void OccluderPolygon2D::set_polygon(const DVector<Vector2>& p_polygon) {
|
||||
|
||||
polygon=p_polygon;
|
||||
VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,p_polygon,closed);
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
DVector<Vector2> OccluderPolygon2D::get_polygon() const{
|
||||
|
||||
return polygon;
|
||||
}
|
||||
|
||||
void OccluderPolygon2D::set_closed(bool p_closed) {
|
||||
|
||||
if (closed==p_closed)
|
||||
return;
|
||||
closed=p_closed;
|
||||
VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,polygon,closed);
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
bool OccluderPolygon2D::is_closed() const{
|
||||
|
||||
return closed;
|
||||
}
|
||||
|
||||
void OccluderPolygon2D::set_cull_mode(CullMode p_mode){
|
||||
|
||||
cull=p_mode;
|
||||
VS::get_singleton()->canvas_occluder_polygon_set_cull_mode(occ_polygon,VS::CanvasOccluderPolygonCullMode(p_mode));
|
||||
}
|
||||
|
||||
OccluderPolygon2D::CullMode OccluderPolygon2D::get_cull_mode() const{
|
||||
|
||||
return cull;
|
||||
}
|
||||
|
||||
|
||||
RID OccluderPolygon2D::get_rid() const {
|
||||
|
||||
return occ_polygon;
|
||||
}
|
||||
|
||||
void OccluderPolygon2D::_bind_methods() {
|
||||
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_closed","closed"),&OccluderPolygon2D::set_closed);
|
||||
ObjectTypeDB::bind_method(_MD("is_closed"),&OccluderPolygon2D::is_closed);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_cull_mode","cull_mode"),&OccluderPolygon2D::set_cull_mode);
|
||||
ObjectTypeDB::bind_method(_MD("get_cull_mode"),&OccluderPolygon2D::get_cull_mode);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&OccluderPolygon2D::set_polygon);
|
||||
ObjectTypeDB::bind_method(_MD("get_polygon"),&OccluderPolygon2D::get_polygon);
|
||||
|
||||
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"closed"),_SCS("set_closed"),_SCS("is_closed"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::INT,"cull_mode",PROPERTY_HINT_ENUM,"Disabled,ClockWise,CounterClockWise"),_SCS("set_cull_mode"),_SCS("get_cull_mode"));
|
||||
|
||||
BIND_CONSTANT(CULL_DISABLED);
|
||||
BIND_CONSTANT(CULL_CLOCKWISE);
|
||||
BIND_CONSTANT(CULL_COUNTER_CLOCKWISE);
|
||||
}
|
||||
|
||||
|
||||
OccluderPolygon2D::OccluderPolygon2D() {
|
||||
|
||||
occ_polygon=VS::get_singleton()->canvas_occluder_polygon_create();
|
||||
closed=true;
|
||||
cull=CULL_DISABLED;
|
||||
}
|
||||
|
||||
OccluderPolygon2D::~OccluderPolygon2D() {
|
||||
|
||||
VS::get_singleton()->free(occ_polygon);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void LightOccluder2D::_poly_changed() {
|
||||
|
||||
update();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void LightOccluder2D::_notification(int p_what) {
|
||||
|
||||
if (p_what==NOTIFICATION_ENTER_CANVAS) {
|
||||
|
||||
VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,get_canvas());
|
||||
VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform());
|
||||
|
||||
}
|
||||
if (p_what==NOTIFICATION_TRANSFORM_CHANGED) {
|
||||
|
||||
VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform());
|
||||
}
|
||||
|
||||
if (p_what==NOTIFICATION_DRAW) {
|
||||
|
||||
if (get_tree()->is_editor_hint()) {
|
||||
|
||||
if (occluder_polygon.is_valid()) {
|
||||
|
||||
DVector<Vector2> poly = occluder_polygon->get_polygon();
|
||||
|
||||
if (poly.size()) {
|
||||
if (occluder_polygon->is_closed()) {
|
||||
Vector<Color> color;
|
||||
color.push_back(Color(0,0,0,0.6));
|
||||
draw_polygon(Variant(poly),color);
|
||||
} else {
|
||||
|
||||
int ps=poly.size();
|
||||
DVector<Vector2>::Read r = poly.read();
|
||||
for(int i=0;i<ps-1;i++) {
|
||||
|
||||
draw_line(r[i],r[i+1],Color(0,0,0,0.6),3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (p_what==NOTIFICATION_EXIT_CANVAS) {
|
||||
|
||||
VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,RID());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D>& p_polygon) {
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (occluder_polygon.is_valid())
|
||||
occluder_polygon->disconnect("changed",this,"_poly_changed");
|
||||
#endif
|
||||
occluder_polygon=p_polygon;
|
||||
|
||||
if (occluder_polygon.is_valid())
|
||||
VS::get_singleton()->canvas_light_occluder_set_polygon(occluder,occluder_polygon->get_rid());
|
||||
else
|
||||
VS::get_singleton()->canvas_light_occluder_set_polygon(occluder,RID());
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (occluder_polygon.is_valid())
|
||||
occluder_polygon->connect("changed",this,"_poly_changed");
|
||||
update();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
Ref<OccluderPolygon2D> LightOccluder2D::get_occluder_polygon() const {
|
||||
|
||||
return occluder_polygon;
|
||||
}
|
||||
|
||||
void LightOccluder2D::set_occluder_light_mask(int p_mask) {
|
||||
|
||||
mask=p_mask;
|
||||
VS::get_singleton()->canvas_light_occluder_set_light_mask(occluder,mask);
|
||||
}
|
||||
|
||||
int LightOccluder2D::get_occluder_light_mask() const{
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
void LightOccluder2D::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_occluder_polygon","polygon:OccluderPolygon2D"),&LightOccluder2D::set_occluder_polygon);
|
||||
ObjectTypeDB::bind_method(_MD("get_occluder_polygon:OccluderPolygon2D"),&LightOccluder2D::get_occluder_polygon);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_occluder_light_mask","mask"),&LightOccluder2D::set_occluder_light_mask);
|
||||
ObjectTypeDB::bind_method(_MD("get_occluder_light_mask"),&LightOccluder2D::get_occluder_light_mask);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
ObjectTypeDB::bind_method("_poly_changed",&LightOccluder2D::_poly_changed);
|
||||
#endif
|
||||
|
||||
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"occluder",PROPERTY_HINT_RESOURCE_TYPE,"OccluderPolygon2D"),_SCS("set_occluder_polygon"),_SCS("get_occluder_polygon"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::INT,"light_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_occluder_light_mask"),_SCS("get_occluder_light_mask"));
|
||||
}
|
||||
|
||||
LightOccluder2D::LightOccluder2D() {
|
||||
|
||||
occluder=VS::get_singleton()->canvas_light_occluder_create();
|
||||
mask=1;
|
||||
}
|
||||
|
||||
LightOccluder2D::~LightOccluder2D() {
|
||||
|
||||
VS::get_singleton()->free(occluder);
|
||||
}
|
||||
|
73
scene/2d/light_occluder_2d.h
Normal file
73
scene/2d/light_occluder_2d.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
#ifndef LIGHTOCCLUDER2D_H
|
||||
#define LIGHTOCCLUDER2D_H
|
||||
|
||||
#include "scene/2d/node_2d.h"
|
||||
|
||||
class OccluderPolygon2D : public Resource {
|
||||
|
||||
OBJ_TYPE(OccluderPolygon2D,Resource);
|
||||
public:
|
||||
|
||||
enum CullMode {
|
||||
CULL_DISABLED,
|
||||
CULL_CLOCKWISE,
|
||||
CULL_COUNTER_CLOCKWISE
|
||||
};
|
||||
private:
|
||||
|
||||
|
||||
RID occ_polygon;
|
||||
DVector<Vector2> polygon;
|
||||
bool closed;
|
||||
CullMode cull;
|
||||
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
void set_polygon(const DVector<Vector2>& p_polygon);
|
||||
DVector<Vector2> get_polygon() const;
|
||||
|
||||
void set_closed(bool p_closed);
|
||||
bool is_closed() const;
|
||||
|
||||
void set_cull_mode(CullMode p_mode);
|
||||
CullMode get_cull_mode() const;
|
||||
|
||||
virtual RID get_rid() const;
|
||||
OccluderPolygon2D();
|
||||
~OccluderPolygon2D();
|
||||
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(OccluderPolygon2D::CullMode);
|
||||
|
||||
class LightOccluder2D : public Node2D {
|
||||
OBJ_TYPE(LightOccluder2D,Node2D);
|
||||
|
||||
RID occluder;
|
||||
bool enabled;
|
||||
int mask;
|
||||
Ref<OccluderPolygon2D> occluder_polygon;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void _poly_changed();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
void set_occluder_polygon(const Ref<OccluderPolygon2D>& p_polygon);
|
||||
Ref<OccluderPolygon2D> get_occluder_polygon() const;
|
||||
|
||||
void set_occluder_light_mask(int p_mask);
|
||||
int get_occluder_light_mask() const;
|
||||
|
||||
LightOccluder2D();
|
||||
~LightOccluder2D();
|
||||
};
|
||||
|
||||
#endif // LIGHTOCCLUDER2D_H
|
660
scene/2d/navigation2d.cpp
Normal file
660
scene/2d/navigation2d.cpp
Normal file
|
@ -0,0 +1,660 @@
|
|||
#include "navigation2d.h"
|
||||
|
||||
#define USE_ENTRY_POINT
|
||||
|
||||
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;
|
||||
|
||||
begin_poly->entry=p_start;
|
||||
|
||||
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;
|
||||
#ifdef USE_ENTRY_POINT
|
||||
Vector2 edge[2]={
|
||||
_get_vertex(begin_poly->edges[i].point),
|
||||
_get_vertex(begin_poly->edges[(i+1)%begin_poly->edges.size()].point)
|
||||
};
|
||||
|
||||
Vector2 entry = Geometry::get_closest_point_to_segment_2d(begin_poly->entry,edge);
|
||||
begin_poly->edges[i].C->distance = begin_poly->entry.distance_to(entry);
|
||||
begin_poly->edges[i].C->entry=entry;
|
||||
#else
|
||||
begin_poly->edges[i].C->distance=begin_poly->center.distance_to(begin_poly->edges[i].C->center);
|
||||
#endif
|
||||
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
|
||||
int es = p->edges.size();
|
||||
|
||||
for(int i=0;i<es;i++) {
|
||||
|
||||
|
||||
Polygon::Edge &e=p->edges[i];
|
||||
|
||||
if (!e.C)
|
||||
continue;
|
||||
|
||||
#ifdef USE_ENTRY_POINT
|
||||
Vector2 edge[2]={
|
||||
_get_vertex(p->edges[i].point),
|
||||
_get_vertex(p->edges[(i+1)%es].point)
|
||||
};
|
||||
|
||||
Vector2 edge_entry = Geometry::get_closest_point_to_segment_2d(p->entry,edge);
|
||||
float distance = p->entry.distance_to(edge_entry) + p->distance;
|
||||
|
||||
#else
|
||||
|
||||
float distance = p->center.distance_to(e.C->center) + p->distance;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
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;
|
||||
#ifdef USE_ENTRY_POINT
|
||||
e.C->entry=edge_entry;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
//add to open neighbours
|
||||
|
||||
e.C->prev_edge=e.C_edge;
|
||||
e.C->distance=distance;
|
||||
#ifdef USE_ENTRY_POINT
|
||||
e.C->entry=edge_entry;
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
}
|
138
scene/2d/navigation2d.h
Normal file
138
scene/2d/navigation2d.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
#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;
|
||||
Vector2 entry;
|
||||
|
||||
float distance;
|
||||
int prev_edge;
|
||||
|
||||
NavMesh *owner;
|
||||
};
|
||||
|
||||
|
||||
struct Connection {
|
||||
|
||||
Polygon *A;
|
||||
int A_edge;
|
||||
Polygon *B;
|
||||
int B_edge;
|
||||
Connection() { A=NULL; B=NULL; A_edge=-1; B_edge=-1;}
|
||||
};
|
||||
|
||||
Map<EdgeKey,Connection> connections;
|
||||
|
||||
|
||||
struct NavMesh {
|
||||
|
||||
Object *owner;
|
||||
Matrix32 xform;
|
||||
bool linked;
|
||||
Ref<NavigationPolygon> navpoly;
|
||||
List<Polygon> polygons;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
_FORCE_INLINE_ Point _get_point(const Vector2& p_pos) const {
|
||||
|
||||
int x = int(Math::floor(p_pos.x/cell_size));
|
||||
int y = int(Math::floor(p_pos.y/cell_size));
|
||||
|
||||
Point p;
|
||||
p.key=0;
|
||||
p.x=x;
|
||||
p.y=y;
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ Vector2 _get_vertex(const Point& p_point) const {
|
||||
|
||||
return Vector2(p_point.x,p_point.y)*cell_size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _navpoly_link(int p_id);
|
||||
void _navpoly_unlink(int p_id);
|
||||
|
||||
float cell_size;
|
||||
Map<int,NavMesh> navpoly_map;
|
||||
int last_id;
|
||||
#if 0
|
||||
void _clip_path(Vector<Vector2>& path,Polygon *from_poly, const Vector2& p_to_point, Polygon* p_to_poly);
|
||||
#endif
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
|
||||
//API should be as dynamic as possible
|
||||
int navpoly_create(const Ref<NavigationPolygon>& p_mesh,const Matrix32& p_xform,Object* p_owner=NULL);
|
||||
void navpoly_set_transform(int p_id, const Matrix32& p_xform);
|
||||
void navpoly_remove(int p_id);
|
||||
|
||||
Vector<Vector2> get_simple_path(const Vector2& p_start, const Vector2& p_end,bool p_optimize=true);
|
||||
Vector2 get_closest_point(const Vector2& p_point);
|
||||
|
||||
Navigation2D();
|
||||
};
|
||||
|
||||
|
||||
#endif // Navigation2D2D_H
|
450
scene/2d/navigation_polygon.cpp
Normal file
450
scene/2d/navigation_polygon.cpp
Normal file
|
@ -0,0 +1,450 @@
|
|||
#include "navigation_polygon.h"
|
||||
#include "navigation2d.h"
|
||||
#include "triangulator.h"
|
||||
#include "core_string_names.h"
|
||||
|
||||
void NavigationPolygon::set_vertices(const DVector<Vector2>& p_vertices) {
|
||||
|
||||
vertices=p_vertices;
|
||||
}
|
||||
|
||||
DVector<Vector2> NavigationPolygon::get_vertices() const{
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
|
||||
void NavigationPolygon::_set_polygons(const Array& p_array) {
|
||||
|
||||
polygons.resize(p_array.size());
|
||||
for(int i=0;i<p_array.size();i++) {
|
||||
polygons[i].indices=p_array[i];
|
||||
}
|
||||
}
|
||||
|
||||
Array NavigationPolygon::_get_polygons() const {
|
||||
|
||||
Array ret;
|
||||
ret.resize(polygons.size());
|
||||
for(int i=0;i<ret.size();i++) {
|
||||
ret[i]=polygons[i].indices;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void NavigationPolygon::_set_outlines(const Array& p_array) {
|
||||
|
||||
outlines.resize(p_array.size());
|
||||
for(int i=0;i<p_array.size();i++) {
|
||||
outlines[i]=p_array[i];
|
||||
}
|
||||
}
|
||||
|
||||
Array NavigationPolygon::_get_outlines() const {
|
||||
|
||||
Array ret;
|
||||
ret.resize(outlines.size());
|
||||
for(int i=0;i<ret.size();i++) {
|
||||
ret[i]=outlines[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void NavigationPolygon::add_polygon(const Vector<int>& p_polygon){
|
||||
|
||||
Polygon polygon;
|
||||
polygon.indices=p_polygon;
|
||||
polygons.push_back(polygon);
|
||||
|
||||
}
|
||||
|
||||
void NavigationPolygon::add_outline_at_index(const DVector<Vector2>& p_outline,int p_index) {
|
||||
|
||||
outlines.insert(p_index,p_outline);
|
||||
}
|
||||
|
||||
int NavigationPolygon::get_polygon_count() const{
|
||||
|
||||
return polygons.size();
|
||||
}
|
||||
Vector<int> NavigationPolygon::get_polygon(int p_idx){
|
||||
|
||||
ERR_FAIL_INDEX_V(p_idx,polygons.size(),Vector<int>());
|
||||
return polygons[p_idx].indices;
|
||||
}
|
||||
void NavigationPolygon::clear_polygons(){
|
||||
|
||||
polygons.clear();
|
||||
}
|
||||
|
||||
void NavigationPolygon::add_outline(const DVector<Vector2>& p_outline) {
|
||||
|
||||
outlines.push_back(p_outline);
|
||||
}
|
||||
|
||||
int NavigationPolygon::get_outline_count() const{
|
||||
|
||||
return outlines.size();
|
||||
}
|
||||
|
||||
void NavigationPolygon::set_outline(int p_idx,const DVector<Vector2>& p_outline) {
|
||||
ERR_FAIL_INDEX(p_idx,outlines.size());
|
||||
outlines[p_idx]=p_outline;
|
||||
}
|
||||
|
||||
void NavigationPolygon::remove_outline(int p_idx) {
|
||||
|
||||
ERR_FAIL_INDEX(p_idx,outlines.size());
|
||||
outlines.remove(p_idx);
|
||||
|
||||
}
|
||||
|
||||
DVector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx,outlines.size(),DVector<Vector2>());
|
||||
return outlines[p_idx];
|
||||
}
|
||||
|
||||
void NavigationPolygon::clear_outlines(){
|
||||
|
||||
outlines.clear();;
|
||||
}
|
||||
void NavigationPolygon::make_polygons_from_outlines(){
|
||||
|
||||
List<TriangulatorPoly> in_poly,out_poly;
|
||||
|
||||
Vector2 outside_point(-1e10,-1e10);
|
||||
|
||||
for(int i=0;i<outlines.size();i++) {
|
||||
|
||||
DVector<Vector2> ol = outlines[i];
|
||||
int olsize = ol.size();
|
||||
if (olsize<3)
|
||||
continue;
|
||||
DVector<Vector2>::Read r=ol.read();
|
||||
for(int j=0;j<olsize;j++) {
|
||||
outside_point.x = MAX( r[j].x, outside_point.x );
|
||||
outside_point.y = MAX( r[j].y, outside_point.y );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
outside_point+=Vector2(0.7239784,0.819238); //avoid precision issues
|
||||
|
||||
|
||||
|
||||
for(int i=0;i<outlines.size();i++) {
|
||||
|
||||
DVector<Vector2> ol = outlines[i];
|
||||
int olsize = ol.size();
|
||||
if (olsize<3)
|
||||
continue;
|
||||
DVector<Vector2>::Read r=ol.read();
|
||||
|
||||
int interscount=0;
|
||||
//test if this is an outer outline
|
||||
for(int k=0;k<outlines.size();k++) {
|
||||
|
||||
if (i==k)
|
||||
continue; //no self intersect
|
||||
|
||||
DVector<Vector2> ol2 = outlines[k];
|
||||
int olsize2 = ol2.size();
|
||||
if (olsize2<3)
|
||||
continue;
|
||||
DVector<Vector2>::Read r2=ol2.read();
|
||||
|
||||
for(int l=0;l<olsize2;l++) {
|
||||
|
||||
if (Geometry::segment_intersects_segment_2d(r[0],outside_point,r2[l],r2[(l+1)%olsize2],NULL)) {
|
||||
interscount++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool outer = (interscount%2)==0;
|
||||
|
||||
TriangulatorPoly tp;
|
||||
tp.Init(olsize);
|
||||
for(int j=0;j<olsize;j++) {
|
||||
tp[j]=r[j];
|
||||
}
|
||||
|
||||
if (outer)
|
||||
tp.SetOrientation(TRIANGULATOR_CCW);
|
||||
else {
|
||||
tp.SetOrientation(TRIANGULATOR_CW);
|
||||
tp.SetHole(true);
|
||||
}
|
||||
|
||||
in_poly.push_back(tp);
|
||||
}
|
||||
|
||||
|
||||
TriangulatorPartition tpart;
|
||||
if (tpart.ConvexPartition_HM(&in_poly,&out_poly)==0) { //failed!
|
||||
print_line("convex partition failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
polygons.clear();
|
||||
vertices.resize(0);
|
||||
|
||||
Map<Vector2,int> points;
|
||||
for(List<TriangulatorPoly>::Element*I = out_poly.front();I;I=I->next()) {
|
||||
|
||||
TriangulatorPoly& tp = I->get();
|
||||
|
||||
struct Polygon p;
|
||||
|
||||
for(int i=0;i<tp.GetNumPoints();i++) {
|
||||
|
||||
Map<Vector2,int>::Element *E=points.find(tp[i]);
|
||||
if (!E) {
|
||||
E=points.insert(tp[i],vertices.size());
|
||||
vertices.push_back(tp[i]);
|
||||
}
|
||||
p.indices.push_back(E->get());
|
||||
}
|
||||
|
||||
polygons.push_back(p);
|
||||
}
|
||||
|
||||
emit_signal(CoreStringNames::get_singleton()->changed);
|
||||
}
|
||||
|
||||
|
||||
void NavigationPolygon::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_vertices","vertices"),&NavigationPolygon::set_vertices);
|
||||
ObjectTypeDB::bind_method(_MD("get_vertices"),&NavigationPolygon::get_vertices);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("add_polygon","polygon"),&NavigationPolygon::add_polygon);
|
||||
ObjectTypeDB::bind_method(_MD("get_polygon_count"),&NavigationPolygon::get_polygon_count);
|
||||
ObjectTypeDB::bind_method(_MD("get_polygon","idx"),&NavigationPolygon::get_polygon);
|
||||
ObjectTypeDB::bind_method(_MD("clear_polygons"),&NavigationPolygon::clear_polygons);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("add_outline","outline"),&NavigationPolygon::add_outline);
|
||||
ObjectTypeDB::bind_method(_MD("add_outline_at_index","outline","index"),&NavigationPolygon::add_outline_at_index);
|
||||
ObjectTypeDB::bind_method(_MD("get_outline_count"),&NavigationPolygon::get_outline_count);
|
||||
ObjectTypeDB::bind_method(_MD("set_outline","idx","outline"),&NavigationPolygon::set_outline);
|
||||
ObjectTypeDB::bind_method(_MD("get_outline","idx"),&NavigationPolygon::get_outline);
|
||||
ObjectTypeDB::bind_method(_MD("remove_outline","idx"),&NavigationPolygon::remove_outline);
|
||||
ObjectTypeDB::bind_method(_MD("clear_outlines"),&NavigationPolygon::clear_outlines);
|
||||
ObjectTypeDB::bind_method(_MD("make_polygons_from_outlines"),&NavigationPolygon::make_polygons_from_outlines);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_set_polygons","polygons"),&NavigationPolygon::_set_polygons);
|
||||
ObjectTypeDB::bind_method(_MD("_get_polygons"),&NavigationPolygon::_get_polygons);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_set_outlines","outlines"),&NavigationPolygon::_set_outlines);
|
||||
ObjectTypeDB::bind_method(_MD("_get_outlines"),&NavigationPolygon::_get_outlines);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3_ARRAY,"vertices",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_vertices"),_SCS("get_vertices"));
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"polygons",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_polygons"),_SCS("_get_polygons"));
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"outlines",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_outlines"),_SCS("_get_outlines"));
|
||||
}
|
||||
|
||||
NavigationPolygon::NavigationPolygon() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
void NavigationPolygonInstance::set_enabled(bool p_enabled) {
|
||||
|
||||
if (enabled==p_enabled)
|
||||
return;
|
||||
enabled=p_enabled;
|
||||
|
||||
if (!is_inside_tree())
|
||||
return;
|
||||
|
||||
if (!enabled) {
|
||||
|
||||
if (nav_id!=-1) {
|
||||
navigation->navpoly_remove(nav_id);
|
||||
nav_id=-1;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (navigation) {
|
||||
|
||||
if (navpoly.is_valid()) {
|
||||
|
||||
nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (get_tree()->is_editor_hint())
|
||||
update();
|
||||
|
||||
// update_gizmo();
|
||||
}
|
||||
|
||||
bool NavigationPolygonInstance::is_enabled() const {
|
||||
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
void NavigationPolygonInstance::_notification(int p_what) {
|
||||
|
||||
|
||||
switch(p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
|
||||
Node2D *c=this;
|
||||
while(c) {
|
||||
|
||||
navigation=c->cast_to<Navigation2D>();
|
||||
if (navigation) {
|
||||
|
||||
if (enabled && navpoly.is_valid()) {
|
||||
|
||||
nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
c=c->get_parent()->cast_to<Node2D>();
|
||||
}
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_TRANSFORM_CHANGED: {
|
||||
|
||||
if (navigation && nav_id!=-1) {
|
||||
navigation->navpoly_set_transform(nav_id,get_relative_transform(navigation));
|
||||
}
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
|
||||
if (navigation) {
|
||||
|
||||
if (nav_id!=-1) {
|
||||
navigation->navpoly_remove(nav_id);
|
||||
nav_id=-1;
|
||||
}
|
||||
}
|
||||
navigation=NULL;
|
||||
} break;
|
||||
case NOTIFICATION_DRAW: {
|
||||
|
||||
if (is_inside_tree() && get_tree()->is_editor_hint() && navpoly.is_valid()) {
|
||||
|
||||
DVector<Vector2> verts=navpoly->get_vertices();
|
||||
int vsize = verts.size();
|
||||
if (vsize<3)
|
||||
return;
|
||||
|
||||
|
||||
Color color;
|
||||
if (enabled) {
|
||||
color=Color(0.1,0.8,1.0,0.4);
|
||||
} else {
|
||||
color=Color(1.0,0.8,0.1,0.4);
|
||||
}
|
||||
Vector<Color> colors;
|
||||
Vector<Vector2> vertices;
|
||||
vertices.resize(vsize);
|
||||
colors.resize(vsize);
|
||||
{
|
||||
DVector<Vector2>::Read vr = verts.read();
|
||||
for(int i=0;i<vsize;i++) {
|
||||
vertices[i]=vr[i];
|
||||
colors[i]=color;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<int> indices;
|
||||
|
||||
|
||||
for(int i=0;i<navpoly->get_polygon_count();i++) {
|
||||
Vector<int> polygon = navpoly->get_polygon(i);
|
||||
|
||||
for(int j=2;j<polygon.size();j++) {
|
||||
|
||||
int kofs[3]={0,j-1,j};
|
||||
for(int k=0;k<3;k++) {
|
||||
|
||||
int idx = polygon[ kofs[k] ];
|
||||
ERR_FAIL_INDEX(idx,vsize);
|
||||
indices.push_back(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(),indices,vertices,colors);
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NavigationPolygonInstance::set_navigation_polygon(const Ref<NavigationPolygon>& p_navpoly) {
|
||||
|
||||
if (p_navpoly==navpoly)
|
||||
return;
|
||||
|
||||
if (navigation && nav_id!=-1) {
|
||||
navigation->navpoly_remove(nav_id);
|
||||
nav_id=-1;
|
||||
}
|
||||
if (navpoly.is_valid()) {
|
||||
navpoly->disconnect(CoreStringNames::get_singleton()->changed,this,"_navpoly_changed");
|
||||
}
|
||||
navpoly=p_navpoly;
|
||||
|
||||
if (navpoly.is_valid()) {
|
||||
navpoly->connect(CoreStringNames::get_singleton()->changed,this,"_navpoly_changed");
|
||||
}
|
||||
|
||||
if (navigation && navpoly.is_valid() && enabled) {
|
||||
nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
|
||||
}
|
||||
//update_gizmo();
|
||||
_change_notify("navpoly");
|
||||
|
||||
}
|
||||
|
||||
Ref<NavigationPolygon> NavigationPolygonInstance::get_navigation_polygon() const{
|
||||
|
||||
return navpoly;
|
||||
}
|
||||
|
||||
void NavigationPolygonInstance::_navpoly_changed() {
|
||||
|
||||
if (is_inside_tree() && get_tree()->is_editor_hint())
|
||||
update();
|
||||
}
|
||||
|
||||
void NavigationPolygonInstance::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_navigation_polygon","navpoly"),&NavigationPolygonInstance::set_navigation_polygon);
|
||||
ObjectTypeDB::bind_method(_MD("get_navigation_polygon"),&NavigationPolygonInstance::get_navigation_polygon);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&NavigationPolygonInstance::set_enabled);
|
||||
ObjectTypeDB::bind_method(_MD("is_enabled"),&NavigationPolygonInstance::is_enabled);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_navpoly_changed"),&NavigationPolygonInstance::_navpoly_changed);
|
||||
|
||||
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"navpoly",PROPERTY_HINT_RESOURCE_TYPE,"NavigationPolygon"),_SCS("set_navigation_polygon"),_SCS("get_navigation_polygon"));
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
|
||||
}
|
||||
|
||||
NavigationPolygonInstance::NavigationPolygonInstance() {
|
||||
|
||||
navigation=NULL;
|
||||
nav_id=-1;
|
||||
enabled=true;
|
||||
|
||||
}
|
84
scene/2d/navigation_polygon.h
Normal file
84
scene/2d/navigation_polygon.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
#ifndef NAVIGATION_POLYGON_H
|
||||
#define NAVIGATION_POLYGON_H
|
||||
|
||||
#include "scene/2d/node_2d.h"
|
||||
|
||||
|
||||
class NavigationPolygon : public Resource {
|
||||
|
||||
OBJ_TYPE( NavigationPolygon, Resource );
|
||||
|
||||
DVector<Vector2> vertices;
|
||||
struct Polygon {
|
||||
Vector<int> indices;
|
||||
};
|
||||
Vector<Polygon> polygons;
|
||||
Vector< DVector<Vector2> > outlines;
|
||||
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
void _set_polygons(const Array& p_array);
|
||||
Array _get_polygons() const;
|
||||
|
||||
void _set_outlines(const Array& p_array);
|
||||
Array _get_outlines() const;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
|
||||
void set_vertices(const DVector<Vector2>& p_vertices);
|
||||
DVector<Vector2> get_vertices() const;
|
||||
|
||||
void add_polygon(const Vector<int>& p_polygon);
|
||||
int get_polygon_count() const;
|
||||
|
||||
void add_outline(const DVector<Vector2>& p_outline);
|
||||
void add_outline_at_index(const DVector<Vector2>& p_outline,int p_index);
|
||||
void set_outline(int p_idx,const DVector<Vector2>& p_outline);
|
||||
DVector<Vector2> get_outline(int p_idx) const;
|
||||
void remove_outline(int p_idx);
|
||||
int get_outline_count() const;
|
||||
|
||||
void clear_outlines();
|
||||
void make_polygons_from_outlines();
|
||||
|
||||
Vector<int> get_polygon(int p_idx);
|
||||
void clear_polygons();
|
||||
|
||||
NavigationPolygon();
|
||||
};
|
||||
|
||||
|
||||
class Navigation2D;
|
||||
|
||||
class NavigationPolygonInstance : public Node2D {
|
||||
|
||||
OBJ_TYPE(NavigationPolygonInstance,Node2D);
|
||||
|
||||
bool enabled;
|
||||
int nav_id;
|
||||
Navigation2D *navigation;
|
||||
Ref<NavigationPolygon> navpoly;
|
||||
|
||||
void _navpoly_changed();
|
||||
|
||||
protected:
|
||||
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
void set_enabled(bool p_enabled);
|
||||
bool is_enabled() const;
|
||||
|
||||
void set_navigation_polygon(const Ref<NavigationPolygon>& p_navpoly);
|
||||
Ref<NavigationPolygon> get_navigation_polygon() const;
|
||||
|
||||
NavigationPolygonInstance();
|
||||
};
|
||||
|
||||
|
||||
#endif // NAVIGATIONPOLYGON_H
|
|
@ -317,6 +317,18 @@ int Node2D::get_z() const{
|
|||
return z;
|
||||
}
|
||||
|
||||
Matrix32 Node2D::get_relative_transform(const Node *p_parent) const {
|
||||
|
||||
if (p_parent==this)
|
||||
return Matrix32();
|
||||
|
||||
Node2D *parent_2d = get_parent()->cast_to<Node2D>();
|
||||
ERR_FAIL_COND_V(!parent_2d,Matrix32());
|
||||
if (p_parent==parent_2d)
|
||||
return get_transform();
|
||||
else
|
||||
return parent_2d->get_relative_transform(p_parent) * get_transform();
|
||||
}
|
||||
|
||||
void Node2D::_bind_methods() {
|
||||
|
||||
|
@ -351,6 +363,8 @@ void Node2D::_bind_methods() {
|
|||
|
||||
ObjectTypeDB::bind_method(_MD("edit_set_pivot"),&Node2D::edit_set_pivot);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("get_relative_transform"),&Node2D::get_relative_transform);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos"));
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd"));
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale"));
|
||||
|
|
|
@ -93,6 +93,9 @@ public:
|
|||
void set_z_as_relative(bool p_enabled);
|
||||
bool is_z_relative() const;
|
||||
|
||||
Matrix32 get_relative_transform(const Node *p_parent) const;
|
||||
|
||||
|
||||
Matrix32 get_transform() const;
|
||||
|
||||
Node2D();
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "tile_map.h"
|
||||
#include "io/marshalls.h"
|
||||
#include "servers/physics_2d_server.h"
|
||||
#include "method_bind_ext.inc"
|
||||
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++) {
|
||||
|
@ -225,11 +226,9 @@ void TileMap::_update_dirty_quadrants() {
|
|||
|
||||
rect.pos+=tile_ofs;
|
||||
if (r==Rect2()) {
|
||||
|
||||
tex->draw_rect(q.canvas_item,rect);
|
||||
tex->draw_rect(q.canvas_item,rect,false,Color(1,1,1),c.transpose);
|
||||
} else {
|
||||
|
||||
tex->draw_rect_region(q.canvas_item,rect,r);
|
||||
tex->draw_rect_region(q.canvas_item,rect,r,Color(1,1,1),c.transpose);
|
||||
}
|
||||
|
||||
Vector< Ref<Shape2D> > shapes = tile_set->tile_get_shapes(c.id);
|
||||
|
@ -243,24 +242,29 @@ void TileMap::_update_dirty_quadrants() {
|
|||
Vector2 shape_ofs = tile_set->tile_get_shape_offset(c.id);
|
||||
Matrix32 xform;
|
||||
xform.set_origin(offset.floor());
|
||||
if (c.transpose) {
|
||||
SWAP(xform.elements[0].x, xform.elements[0].y);
|
||||
SWAP(xform.elements[1].x, xform.elements[1].y);
|
||||
SWAP(shape_ofs.x, shape_ofs.y);
|
||||
SWAP(s.x, s.y);
|
||||
}
|
||||
if (c.flip_h) {
|
||||
xform.elements[0]=-xform.elements[0];
|
||||
xform.elements[2].x+=s.x-shape_ofs.x;
|
||||
} else {
|
||||
|
||||
xform.elements[2].x+=shape_ofs.x;
|
||||
xform.elements[0].x=-xform.elements[0].x;
|
||||
xform.elements[1].x=-xform.elements[1].x;
|
||||
shape_ofs.x=s.x-shape_ofs.x;
|
||||
}
|
||||
if (c.flip_v) {
|
||||
xform.elements[1]=-xform.elements[1];
|
||||
xform.elements[2].y+=s.y-shape_ofs.y;
|
||||
} else {
|
||||
|
||||
xform.elements[2].y+=shape_ofs.y;
|
||||
xform.elements[0].y=-xform.elements[0].y;
|
||||
xform.elements[1].y=-xform.elements[1].y;
|
||||
shape_ofs.y=s.y-shape_ofs.y;
|
||||
}
|
||||
xform.elements[2].x+=shape_ofs.x;
|
||||
xform.elements[2].y+=shape_ofs.y;
|
||||
|
||||
|
||||
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 +343,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 +365,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);
|
||||
|
@ -385,7 +389,7 @@ void TileMap::_make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q) {
|
|||
}
|
||||
|
||||
|
||||
void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
|
||||
void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) {
|
||||
|
||||
PosKey pk(p_x,p_y);
|
||||
|
||||
|
@ -421,7 +425,7 @@ void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
|
|||
} else {
|
||||
ERR_FAIL_COND(!Q); // quadrant should exist...
|
||||
|
||||
if (E->get().id==p_tile && E->get().flip_h==p_flip_x && E->get().flip_v==p_flip_y)
|
||||
if (E->get().id==p_tile && E->get().flip_h==p_flip_x && E->get().flip_v==p_flip_y && E->get().transpose==p_transpose)
|
||||
return; //nothing changed
|
||||
|
||||
}
|
||||
|
@ -432,6 +436,7 @@ void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) {
|
|||
c.id=p_tile;
|
||||
c.flip_h=p_flip_x;
|
||||
c.flip_v=p_flip_y;
|
||||
c.transpose=p_transpose;
|
||||
|
||||
_make_quadrant_dirty(Q);
|
||||
|
||||
|
@ -471,6 +476,17 @@ bool TileMap::is_cell_y_flipped(int p_x,int p_y) const {
|
|||
|
||||
return E->get().flip_v;
|
||||
}
|
||||
bool TileMap::is_cell_transposed(int p_x,int p_y) const {
|
||||
|
||||
PosKey pk(p_x,p_y);
|
||||
|
||||
const Map<PosKey,Cell>::Element *E=tile_map.find(pk);
|
||||
|
||||
if (!E)
|
||||
return false;
|
||||
|
||||
return E->get().transpose;
|
||||
}
|
||||
|
||||
|
||||
void TileMap::_recreate_quadrants() {
|
||||
|
@ -535,11 +551,12 @@ void TileMap::_set_tile_data(const DVector<int>& p_data) {
|
|||
uint32_t v = decode_uint32(&local[4]);
|
||||
bool flip_h = v&(1<<29);
|
||||
bool flip_v = v&(1<<30);
|
||||
bool transpose = v&(1<<31);
|
||||
v&=(1<<29)-1;
|
||||
|
||||
// if (x<-20 || y <-20 || x>4000 || y>4000)
|
||||
// continue;
|
||||
set_cell(x,y,v,flip_h,flip_v);
|
||||
set_cell(x,y,v,flip_h,flip_v,transpose);
|
||||
|
||||
}
|
||||
|
||||
|
@ -562,6 +579,8 @@ DVector<int> TileMap::_get_tile_data() const {
|
|||
val|=(1<<29);
|
||||
if (E->get().flip_v)
|
||||
val|=(1<<30);
|
||||
if (E->get().transpose)
|
||||
val|=(1<<31);
|
||||
|
||||
encode_uint32(val,&ptr[4]);
|
||||
idx+=2;
|
||||
|
@ -586,17 +605,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 +643,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 +835,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);
|
||||
|
||||
|
@ -813,7 +847,7 @@ void TileMap::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("set_collision_bounce","value"),&TileMap::set_collision_bounce);
|
||||
ObjectTypeDB::bind_method(_MD("get_collision_bounce"),&TileMap::get_collision_bounce);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false));
|
||||
ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y","transpose"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false),DEFVAL(false));
|
||||
ObjectTypeDB::bind_method(_MD("get_cell","x","y"),&TileMap::get_cell);
|
||||
ObjectTypeDB::bind_method(_MD("is_cell_x_flipped","x","y"),&TileMap::is_cell_x_flipped);
|
||||
ObjectTypeDB::bind_method(_MD("is_cell_y_flipped","x","y"),&TileMap::is_cell_y_flipped);
|
||||
|
@ -837,6 +871,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 +905,7 @@ TileMap::TileMap() {
|
|||
bounce=0;
|
||||
mode=MODE_SQUARE;
|
||||
half_offset=HALF_OFFSET_DISABLED;
|
||||
use_kinematic=false;
|
||||
|
||||
fp_adjust=0.01;
|
||||
fp_adjust=0.01;
|
||||
|
|
|
@ -60,6 +60,7 @@ private:
|
|||
Mode mode;
|
||||
Matrix32 custom_transform;
|
||||
HalfOffset half_offset;
|
||||
bool use_kinematic;
|
||||
|
||||
|
||||
union PosKey {
|
||||
|
@ -85,6 +86,7 @@ private:
|
|||
int32_t id:24;
|
||||
bool flip_h:1;
|
||||
bool flip_v:1;
|
||||
bool transpose:1;
|
||||
};
|
||||
|
||||
uint32_t _u32t;
|
||||
|
@ -97,14 +99,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) {}
|
||||
};
|
||||
|
||||
|
@ -167,16 +169,20 @@ public:
|
|||
void set_center_y(bool p_enable);
|
||||
bool get_center_y() const;
|
||||
|
||||
void set_cell(int p_x,int p_y,int p_tile,bool p_flip_x=false,bool p_flip_y=false);
|
||||
void set_cell(int p_x,int p_y,int p_tile,bool p_flip_x=false,bool p_flip_y=false,bool p_transpose=false);
|
||||
int get_cell(int p_x,int p_y) const;
|
||||
bool is_cell_x_flipped(int p_x,int p_y) const;
|
||||
bool is_cell_y_flipped(int p_x,int p_y) const;
|
||||
bool is_cell_transposed(int p_x,int p_y) const;
|
||||
|
||||
Rect2 get_item_rect() const;
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -152,11 +152,11 @@ void Camera::_get_property_list( List<PropertyInfo> *p_list) const {
|
|||
|
||||
case PROJECTION_PERSPECTIVE: {
|
||||
|
||||
p_list->push_back( PropertyInfo( Variant::REAL, "fov" , PROPERTY_HINT_RANGE, "1,89,0.1",PROPERTY_USAGE_NOEDITOR) );
|
||||
p_list->push_back( PropertyInfo( Variant::REAL, "fov" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_NOEDITOR) );
|
||||
if (keep_aspect==KEEP_WIDTH)
|
||||
p_list->push_back( PropertyInfo( Variant::REAL, "fovx" , PROPERTY_HINT_RANGE, "1,89,0.1",PROPERTY_USAGE_EDITOR) );
|
||||
p_list->push_back( PropertyInfo( Variant::REAL, "fovx" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_EDITOR) );
|
||||
else
|
||||
p_list->push_back( PropertyInfo( Variant::REAL, "fovy" , PROPERTY_HINT_RANGE, "1,89,0.1",PROPERTY_USAGE_EDITOR) );
|
||||
p_list->push_back( PropertyInfo( Variant::REAL, "fovy" , PROPERTY_HINT_RANGE, "1,179,0.1",PROPERTY_USAGE_EDITOR) );
|
||||
|
||||
|
||||
} break;
|
||||
|
@ -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);
|
||||
|
|
|
@ -310,6 +310,17 @@ int GeometryInstance::get_baked_light_texture_id() const{
|
|||
return baked_light_texture_id;
|
||||
}
|
||||
|
||||
void GeometryInstance::set_extra_cull_margin(float p_margin) {
|
||||
|
||||
ERR_FAIL_COND(p_margin<0);
|
||||
extra_cull_margin=p_margin;
|
||||
VS::get_singleton()->instance_set_extra_visibility_margin(get_instance(),extra_cull_margin);
|
||||
}
|
||||
|
||||
float GeometryInstance::get_extra_cull_margin() const{
|
||||
|
||||
return extra_cull_margin;
|
||||
}
|
||||
|
||||
void GeometryInstance::_bind_methods() {
|
||||
|
||||
|
@ -328,6 +339,9 @@ void GeometryInstance::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("set_baked_light_texture_id","id"), &GeometryInstance::set_baked_light_texture_id);
|
||||
ObjectTypeDB::bind_method(_MD("get_baked_light_texture_id"), &GeometryInstance::get_baked_light_texture_id);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_extra_cull_margin","margin"), &GeometryInstance::set_extra_cull_margin);
|
||||
ObjectTypeDB::bind_method(_MD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_baked_light_changed"), &GeometryInstance::_baked_light_changed);
|
||||
|
||||
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE);
|
||||
|
@ -336,6 +350,7 @@ void GeometryInstance::_bind_methods() {
|
|||
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/receive_shadows"), _SCS("set_flag"), _SCS("get_flag"),FLAG_RECEIVE_SHADOWS);
|
||||
ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_begin",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_begin"), _SCS("get_draw_range_begin"));
|
||||
ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/range_end",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_draw_range_end"), _SCS("get_draw_range_end"));
|
||||
ADD_PROPERTY( PropertyInfo( Variant::REAL, "geometry/extra_cull_margin",PROPERTY_HINT_RANGE,"0,16384,0"), _SCS("set_extra_cull_margin"), _SCS("get_extra_cull_margin"));
|
||||
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD);
|
||||
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard_y"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD_FIX_Y);
|
||||
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE);
|
||||
|
|
|
@ -108,6 +108,7 @@ private:
|
|||
void _find_baked_light();
|
||||
BakedLightInstance *baked_light_instance;
|
||||
int baked_light_texture_id;
|
||||
float extra_cull_margin;
|
||||
|
||||
void _baked_light_changed();
|
||||
void _update_visibility();
|
||||
|
@ -132,6 +133,9 @@ public:
|
|||
void set_baked_light_texture_id(int p_id);
|
||||
int get_baked_light_texture_id() const;
|
||||
|
||||
void set_extra_cull_margin(float p_margin);
|
||||
float get_extra_cull_margin() const;
|
||||
|
||||
GeometryInstance();
|
||||
};
|
||||
|
||||
|
|
|
@ -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")));
|
||||
|
|
|
@ -380,7 +380,7 @@ public:
|
|||
|
||||
void grab_click_focus();
|
||||
|
||||
|
||||
void warp_mouse(const Point2& p_to_pos);
|
||||
|
||||
Control();
|
||||
~Control();
|
||||
|
|
|
@ -328,8 +328,8 @@ AcceptDialog::AcceptDialog() {
|
|||
label->set_anchor(MARGIN_RIGHT,ANCHOR_END);
|
||||
label->set_anchor(MARGIN_BOTTOM,ANCHOR_END);
|
||||
label->set_begin( Point2( margin, margin) );
|
||||
label->set_end( Point2( margin, button_margin) );
|
||||
label->set_autowrap(true);
|
||||
label->set_end( Point2( margin, button_margin+10) );
|
||||
//label->set_autowrap(true);
|
||||
add_child(label);
|
||||
|
||||
hbc = memnew( HBoxContainer );
|
||||
|
|
|
@ -94,6 +94,8 @@ void Popup::popup_centered_minsize(const Size2& p_minsize) {
|
|||
Control *c=get_child(i)->cast_to<Control>();
|
||||
if (!c)
|
||||
continue;
|
||||
if (c->is_hidden())
|
||||
continue;
|
||||
|
||||
Size2 minsize = c->get_combined_minimum_size();
|
||||
|
||||
|
@ -114,6 +116,8 @@ void Popup::popup_centered_minsize(const Size2& p_minsize) {
|
|||
|
||||
}
|
||||
|
||||
print_line(String(c->get_type())+": "+minsize);
|
||||
|
||||
total_minsize.width = MAX( total_minsize.width, minsize.width );
|
||||
total_minsize.height = MAX( total_minsize.height, minsize.height );
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ public:
|
|||
void add_icon_check_item(const Ref<Texture>& p_icon,const String& p_label,int p_ID=-1,uint32_t p_accel=0);
|
||||
void add_check_item(const String& p_label,int p_ID=-1,uint32_t p_accel=0);
|
||||
void add_submenu_item(const String& p_label,const String& p_submenu, int p_ID=-1);
|
||||
|
||||
|
||||
void set_item_text(int p_idx,const String& p_text);
|
||||
void set_item_icon(int p_idx,const Ref<Texture>& p_icon);
|
||||
void set_item_checked(int p_idx,bool p_checked);
|
||||
|
|
|
@ -2472,6 +2472,10 @@ void Tree::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
|
||||
if (p_what==NOTIFICATION_THEME_CHANGED) {
|
||||
update_cache();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
@ -970,6 +972,22 @@ bool Viewport::get_render_target_vflip() const{
|
|||
return render_target_vflip;
|
||||
}
|
||||
|
||||
void Viewport::set_render_target_clear_on_new_frame(bool p_enable) {
|
||||
|
||||
render_target_clear_on_new_frame=p_enable;
|
||||
VisualServer::get_singleton()->viewport_set_render_target_clear_on_new_frame(viewport,p_enable);
|
||||
}
|
||||
|
||||
bool Viewport::get_render_target_clear_on_new_frame() const{
|
||||
|
||||
return render_target_clear_on_new_frame;
|
||||
}
|
||||
|
||||
void Viewport::render_target_clear() {
|
||||
|
||||
//render_target_clear=true;
|
||||
VisualServer::get_singleton()->viewport_render_target_clear(viewport);
|
||||
}
|
||||
|
||||
void Viewport::set_render_target_filter(bool p_enable) {
|
||||
|
||||
|
@ -1100,6 +1118,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());
|
||||
|
@ -1256,6 +1280,11 @@ void Viewport::_bind_methods() {
|
|||
|
||||
ObjectTypeDB::bind_method(_MD("set_render_target_vflip","enable"), &Viewport::set_render_target_vflip);
|
||||
ObjectTypeDB::bind_method(_MD("get_render_target_vflip"), &Viewport::get_render_target_vflip);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_render_target_clear_on_new_frame","enable"), &Viewport::set_render_target_clear_on_new_frame);
|
||||
ObjectTypeDB::bind_method(_MD("get_render_target_clear_on_new_frame"), &Viewport::get_render_target_clear_on_new_frame);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("render_target_clear"), &Viewport::render_target_clear);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_render_target_filter","enable"), &Viewport::set_render_target_filter);
|
||||
ObjectTypeDB::bind_method(_MD("get_render_target_filter"), &Viewport::get_render_target_filter);
|
||||
|
@ -1289,6 +1318,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") );
|
||||
|
@ -1297,6 +1327,7 @@ void Viewport::_bind_methods() {
|
|||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transparent_bg"), _SCS("set_transparent_background"), _SCS("has_transparent_background") );
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/enabled"), _SCS("set_as_render_target"), _SCS("is_set_as_render_target") );
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/v_flip"), _SCS("set_render_target_vflip"), _SCS("get_render_target_vflip") );
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/clear_on_new_frame"), _SCS("set_render_target_clear_on_new_frame"), _SCS("get_render_target_clear_on_new_frame") );
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/filter"), _SCS("set_render_target_filter"), _SCS("get_render_target_filter") );
|
||||
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/gen_mipmaps"), _SCS("set_render_target_gen_mipmaps"), _SCS("get_render_target_gen_mipmaps") );
|
||||
ADD_PROPERTY( PropertyInfo(Variant::INT,"render_target/update_mode",PROPERTY_HINT_ENUM,"Disabled,Once,When Visible,Always"), _SCS("set_render_target_update_mode"), _SCS("get_render_target_update_mode") );
|
||||
|
@ -1335,6 +1366,8 @@ Viewport::Viewport() {
|
|||
render_target_gen_mipmaps=false;
|
||||
render_target=false;
|
||||
render_target_vflip=false;
|
||||
render_target_clear_on_new_frame=true;
|
||||
//render_target_clear=true;
|
||||
render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE;
|
||||
render_target_texture = Ref<RenderTargetTexture>( memnew( RenderTargetTexture(this) ) );
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ friend class RenderTargetTexture;
|
|||
|
||||
bool transparent_bg;
|
||||
bool render_target_vflip;
|
||||
bool render_target_clear_on_new_frame;
|
||||
bool render_target_filter;
|
||||
bool render_target_gen_mipmaps;
|
||||
|
||||
|
@ -220,6 +221,10 @@ public:
|
|||
void set_render_target_vflip(bool p_enable);
|
||||
bool get_render_target_vflip() const;
|
||||
|
||||
void set_render_target_clear_on_new_frame(bool p_enable);
|
||||
bool get_render_target_clear_on_new_frame() const;
|
||||
void render_target_clear();
|
||||
|
||||
void set_render_target_filter(bool p_enable);
|
||||
bool get_render_target_filter() const;
|
||||
|
||||
|
@ -246,6 +251,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();
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@
|
|||
#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/light_occluder_2d.h"
|
||||
|
||||
#include "scene/2d/canvas_item.h"
|
||||
#include "scene/2d/sprite.h"
|
||||
|
@ -102,6 +104,8 @@
|
|||
#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/canvas_modulate.h"
|
||||
|
||||
#include "scene/2d/position_2d.h"
|
||||
#include "scene/2d/tile_map.h"
|
||||
|
@ -262,6 +266,7 @@ void register_scene_types() {
|
|||
ObjectTypeDB::register_virtual_type<RenderTargetTexture>();
|
||||
ObjectTypeDB::register_type<Timer>();
|
||||
ObjectTypeDB::register_type<CanvasLayer>();
|
||||
ObjectTypeDB::register_type<CanvasModulate>();
|
||||
ObjectTypeDB::register_type<ResourcePreloader>();
|
||||
|
||||
/* REGISTER GUI */
|
||||
|
@ -450,6 +455,7 @@ void register_scene_types() {
|
|||
//ObjectTypeDB::set_type_enabled("BodyVolumeCylinder",false);
|
||||
//ObjectTypeDB::set_type_enabled("BodyVolumeConvexPolygon",false);
|
||||
|
||||
ObjectTypeDB::register_type<CanvasItemMaterial>();
|
||||
ObjectTypeDB::register_virtual_type<CanvasItem>();
|
||||
ObjectTypeDB::register_type<Node2D>();
|
||||
ObjectTypeDB::register_type<Particles2D>();
|
||||
|
@ -471,6 +477,9 @@ void register_scene_types() {
|
|||
ObjectTypeDB::register_type<VisibilityNotifier2D>();
|
||||
ObjectTypeDB::register_type<VisibilityEnabler2D>();
|
||||
ObjectTypeDB::register_type<Polygon2D>();
|
||||
ObjectTypeDB::register_type<Light2D>();
|
||||
ObjectTypeDB::register_type<LightOccluder2D>();
|
||||
ObjectTypeDB::register_type<OccluderPolygon2D>();
|
||||
ObjectTypeDB::register_type<YSort>();
|
||||
|
||||
ObjectTypeDB::set_type_enabled("CollisionShape2D",false);
|
||||
|
@ -499,6 +508,7 @@ void register_scene_types() {
|
|||
ObjectTypeDB::register_virtual_type<Shader>();
|
||||
ObjectTypeDB::register_virtual_type<ShaderGraph>();
|
||||
ObjectTypeDB::register_type<CanvasItemShader>();
|
||||
ObjectTypeDB::register_type<CanvasItemShaderGraph>();
|
||||
|
||||
#ifndef _3D_DISABLED
|
||||
ObjectTypeDB::register_type<Mesh>();
|
||||
|
@ -574,6 +584,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>();
|
||||
|
|
|
@ -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/","")+"\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -221,6 +221,13 @@ void ShaderGraph::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("comment_node_set_text","shader_type","id","text"),&ShaderGraph::comment_node_set_text);
|
||||
ObjectTypeDB::bind_method(_MD("comment_node_get_text","shader_type","id"),&ShaderGraph::comment_node_get_text);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("color_ramp_node_set_ramp","shader_type","id","colors","offsets"),&ShaderGraph::color_ramp_node_set_ramp);
|
||||
ObjectTypeDB::bind_method(_MD("color_ramp_node_get_colors","shader_type","id"),&ShaderGraph::color_ramp_node_get_colors);
|
||||
ObjectTypeDB::bind_method(_MD("color_ramp_node_get_offsets","shader_type","id"),&ShaderGraph::color_ramp_node_get_offsets);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("curve_map_node_set_points","shader_type","id","points"),&ShaderGraph::curve_map_node_set_points);
|
||||
ObjectTypeDB::bind_method(_MD("curve_map_node_get_points","shader_type","id"),&ShaderGraph::curve_map_node_get_points);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("connect_node:Error","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::connect_node);
|
||||
ObjectTypeDB::bind_method(_MD("is_node_connected","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::is_node_connected);
|
||||
ObjectTypeDB::bind_method(_MD("disconnect_node","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::disconnect_node);
|
||||
|
@ -263,12 +270,15 @@ void ShaderGraph::_bind_methods() {
|
|||
BIND_CONSTANT( NODE_XFORM_TO_VEC ); // 3 vec input ); 1 xform output
|
||||
BIND_CONSTANT( NODE_SCALAR_INTERP ); // scalar interpolation (with optional curve)
|
||||
BIND_CONSTANT( NODE_VEC_INTERP ); // vec3 interpolation (with optional curve)
|
||||
BIND_CONSTANT( NODE_COLOR_RAMP );
|
||||
BIND_CONSTANT( NODE_CURVE_MAP );
|
||||
BIND_CONSTANT( NODE_SCALAR_INPUT ); // scalar uniform (assignable in material)
|
||||
BIND_CONSTANT( NODE_VEC_INPUT ); // vec3 uniform (assignable in material)
|
||||
BIND_CONSTANT( NODE_RGB_INPUT ); // color uniform (assignable in material)
|
||||
BIND_CONSTANT( NODE_XFORM_INPUT ); // mat4 uniform (assignable in material)
|
||||
BIND_CONSTANT( NODE_TEXTURE_INPUT ); // texture input (assignable in material)
|
||||
BIND_CONSTANT( NODE_CUBEMAP_INPUT ); // cubemap input (assignable in material)
|
||||
BIND_CONSTANT( NODE_DEFAULT_TEXTURE );
|
||||
BIND_CONSTANT( NODE_OUTPUT ); // output (shader type dependent)
|
||||
BIND_CONSTANT( NODE_COMMENT ); // comment
|
||||
BIND_CONSTANT( NODE_TYPE_MAX );
|
||||
|
@ -519,12 +529,15 @@ void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) {
|
|||
case NODE_XFORM_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
|
||||
case NODE_SCALAR_INTERP: {} break; // scalar interpolation (with optional curve)
|
||||
case NODE_VEC_INTERP: {} break; // vec3 interpolation (with optional curve)
|
||||
case NODE_COLOR_RAMP: { node.param1=DVector<Color>(); node.param2=DVector<real_t>();} break; // vec3 interpolation (with optional curve)
|
||||
case NODE_CURVE_MAP: { node.param1=DVector<Vector2>();} break; // vec3 interpolation (with optional curve)
|
||||
case NODE_SCALAR_INPUT: {node.param1=_find_unique_name("Scalar"); node.param2=0;} break; // scalar uniform (assignable in material)
|
||||
case NODE_VEC_INPUT: {node.param1=_find_unique_name("Vec3");node.param2=Vector3();} break; // vec3 uniform (assignable in material)
|
||||
case NODE_RGB_INPUT: {node.param1=_find_unique_name("Color");node.param2=Color();} break; // color uniform (assignable in material)
|
||||
case NODE_XFORM_INPUT: {node.param1=_find_unique_name("XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material)
|
||||
case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name("Tex"); } break; // texture input (assignable in material)
|
||||
case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
|
||||
case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
|
||||
case NODE_DEFAULT_TEXTURE: {}; break;
|
||||
case NODE_OUTPUT: {} break; // output (shader type dependent)
|
||||
case NODE_COMMENT: {} break; // comment
|
||||
case NODE_TYPE_MAX: {};
|
||||
|
@ -964,6 +977,59 @@ ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type,
|
|||
return VecFunc(func);
|
||||
}
|
||||
|
||||
void ShaderGraph::color_ramp_node_set_ramp(ShaderType p_type,int p_id,const DVector<Color>& p_colors, const DVector<real_t>& p_offsets){
|
||||
|
||||
ERR_FAIL_INDEX(p_type,3);
|
||||
ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
|
||||
ERR_FAIL_COND(p_colors.size()!=p_offsets.size());
|
||||
Node& n = shader[p_type].node_map[p_id];
|
||||
n.param1=p_colors;
|
||||
n.param2=p_offsets;
|
||||
_request_update();
|
||||
|
||||
}
|
||||
|
||||
DVector<Color> ShaderGraph::color_ramp_node_get_colors(ShaderType p_type,int p_id) const{
|
||||
|
||||
ERR_FAIL_INDEX_V(p_type,3,DVector<Color>());
|
||||
ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Color>());
|
||||
const Node& n = shader[p_type].node_map[p_id];
|
||||
return n.param1;
|
||||
|
||||
|
||||
}
|
||||
|
||||
DVector<real_t> ShaderGraph::color_ramp_node_get_offsets(ShaderType p_type,int p_id) const{
|
||||
|
||||
ERR_FAIL_INDEX_V(p_type,3,DVector<real_t>());
|
||||
ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<real_t>());
|
||||
const Node& n = shader[p_type].node_map[p_id];
|
||||
return n.param2;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ShaderGraph::curve_map_node_set_points(ShaderType p_type,int p_id,const DVector<Vector2>& p_points) {
|
||||
|
||||
ERR_FAIL_INDEX(p_type,3);
|
||||
ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
|
||||
Node& n = shader[p_type].node_map[p_id];
|
||||
n.param1=p_points;
|
||||
_request_update();
|
||||
|
||||
}
|
||||
|
||||
DVector<Vector2> ShaderGraph::curve_map_node_get_points(ShaderType p_type,int p_id) const{
|
||||
|
||||
ERR_FAIL_INDEX_V(p_type,3,DVector<Vector2>());
|
||||
ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Vector2>());
|
||||
const Node& n = shader[p_type].node_map[p_id];
|
||||
return n.param1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ShaderGraph::input_node_set_name(ShaderType p_type,int p_id,const String& p_name){
|
||||
|
||||
ERR_FAIL_INDEX(p_type,3);
|
||||
|
@ -1223,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},
|
||||
|
@ -1254,6 +1320,43 @@ const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={
|
|||
{MODE_MATERIAL,SHADER_TYPE_LIGHT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_IN},
|
||||
//light out
|
||||
{MODE_MATERIAL,SHADER_TYPE_LIGHT,"Light","LIGHT","",SLOT_TYPE_VEC,SLOT_OUT},
|
||||
//canvas item vertex in
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Vertex","vec3(SRC_VERTEX,0)","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"UV","SRC_UV","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Color","SRC_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Alpha","SRC_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"WorldMatrix","WORLD_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"ExtraMatrix","EXTRA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"ProjectionMatrix","PROJECTION_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
|
||||
//canvas item vertex out
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Vertex","VERTEX",".xy",SLOT_TYPE_VEC,SLOT_OUT},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"UV","UV",".xy",SLOT_TYPE_VEC,SLOT_OUT},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"PointSize","POINT_SIZE","",SLOT_TYPE_SCALAR,SLOT_OUT},
|
||||
//canvas item fragment in
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Color","SRC_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Alpha","SRC_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"UVScreen","vec3(SCREEN_UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"TexPixelSize","vec3(TEXTURE_PIXEL_SIZE,0)","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
//canvas item fragment out
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
|
||||
//canvas item light in
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightDist","LIGHT_DISTANCE","",SLOT_TYPE_SCALAR,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightDir","vec3(LIGHT_DIR,0)","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
|
||||
//canvas item light out
|
||||
{MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Light","LIGHT","",SLOT_TYPE_VEC,SLOT_OUT},
|
||||
//end
|
||||
{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT},
|
||||
|
||||
|
@ -1299,12 +1402,15 @@ const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[]= {
|
|||
{NODE_SCALAR_TO_VEC,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // 3 scalar input,{SLOT_MAX},{SLOT_MAX}}, 1 vec3 output
|
||||
{NODE_SCALAR_INTERP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar interpolation (with optional curve)
|
||||
{NODE_VEC_INTERP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 interpolation (with optional curve)
|
||||
{NODE_COLOR_RAMP,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 interpolation (with optional curve)
|
||||
{NODE_CURVE_MAP,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 interpolation (with optional curve)
|
||||
{NODE_SCALAR_INPUT,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar uniform (assignable in material)
|
||||
{NODE_VEC_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 uniform (assignable in material)
|
||||
{NODE_RGB_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // color uniform (assignable in material)
|
||||
{NODE_XFORM_INPUT,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 uniform (assignable in material)
|
||||
{NODE_TEXTURE_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // texture input (assignable in material)
|
||||
{NODE_CUBEMAP_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material)
|
||||
{NODE_DEFAULT_TEXTURE,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material)
|
||||
{NODE_COMMENT,{SLOT_MAX},{SLOT_MAX}}, // comment
|
||||
{NODE_TYPE_MAX,{SLOT_MAX},{SLOT_MAX}}
|
||||
};
|
||||
|
@ -1663,6 +1769,11 @@ void ShaderGraph::_update_shader() {
|
|||
} else if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
|
||||
if (name==("IN_NORMAL"))
|
||||
code[i]="vec3 IN_NORMAL=NORMAL;\n"+code[i];
|
||||
} else if (i==SHADER_TYPE_VERTEX && get_mode()==MODE_CANVAS_ITEM) {
|
||||
if (name==("SRC_COLOR"))
|
||||
code[i]="vec3 SRC_COLOR=COLOR.rgb;\n"+code[i];
|
||||
if (name==("SRC_UV"))
|
||||
code[i]="vec3 SRC_UV=vec3(UV,0);\n"+code[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1679,6 +1790,10 @@ void ShaderGraph::_update_shader() {
|
|||
all_ok=false;
|
||||
}
|
||||
|
||||
/*print_line("VERTEX: \n"+code[0]);
|
||||
print_line("FRAGMENT: \n"+code[1]);
|
||||
print_line("LIGHT: \n"+code[2]);*/
|
||||
|
||||
if (all_ok) {
|
||||
set_code(code[0],code[1],code[2]);
|
||||
}
|
||||
|
@ -1688,6 +1803,134 @@ void ShaderGraph::_update_shader() {
|
|||
emit_signal(SceneStringNames::get_singleton()->updated);
|
||||
}
|
||||
|
||||
void ShaderGraph::_plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d,uint8_t* p_heights,bool *p_useds) {
|
||||
|
||||
float geometry[4][4];
|
||||
float tmp1[4][4];
|
||||
float tmp2[4][4];
|
||||
float deltas[4][4];
|
||||
double x, dx, dx2, dx3;
|
||||
double y, dy, dy2, dy3;
|
||||
double d, d2, d3;
|
||||
int lastx, lasty;
|
||||
int newx, newy;
|
||||
int ntimes;
|
||||
int i,j;
|
||||
|
||||
int xmax=255;
|
||||
int ymax=255;
|
||||
|
||||
/* construct the geometry matrix from the segment */
|
||||
for (i = 0; i < 4; i++) {
|
||||
geometry[i][2] = 0;
|
||||
geometry[i][3] = 0;
|
||||
}
|
||||
|
||||
geometry[0][0] = (p_a[0] * xmax);
|
||||
geometry[1][0] = (p_b[0] * xmax);
|
||||
geometry[2][0] = (p_c[0] * xmax);
|
||||
geometry[3][0] = (p_d[0] * xmax);
|
||||
|
||||
geometry[0][1] = (p_a[1] * ymax);
|
||||
geometry[1][1] = (p_b[1] * ymax);
|
||||
geometry[2][1] = (p_c[1] * ymax);
|
||||
geometry[3][1] = (p_d[1] * ymax);
|
||||
|
||||
/* subdivide the curve ntimes (1000) times */
|
||||
ntimes = 4 * xmax;
|
||||
/* ntimes can be adjusted to give a finer or coarser curve */
|
||||
d = 1.0 / ntimes;
|
||||
d2 = d * d;
|
||||
d3 = d * d * d;
|
||||
|
||||
/* construct a temporary matrix for determining the forward differencing deltas */
|
||||
tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1;
|
||||
tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0;
|
||||
tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0;
|
||||
tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0;
|
||||
|
||||
/* compose the basis and geometry matrices */
|
||||
|
||||
static const float CR_basis[4][4] =
|
||||
{
|
||||
{ -0.5, 1.5, -1.5, 0.5 },
|
||||
{ 1.0, -2.5, 2.0, -0.5 },
|
||||
{ -0.5, 0.0, 0.5, 0.0 },
|
||||
{ 0.0, 1.0, 0.0, 0.0 },
|
||||
};
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
|
||||
CR_basis[i][1] * geometry[1][j] +
|
||||
CR_basis[i][2] * geometry[2][j] +
|
||||
CR_basis[i][3] * geometry[3][j]);
|
||||
}
|
||||
}
|
||||
/* compose the above results to get the deltas matrix */
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
|
||||
tmp2[i][1] * tmp1[1][j] +
|
||||
tmp2[i][2] * tmp1[2][j] +
|
||||
tmp2[i][3] * tmp1[3][j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* extract the x deltas */
|
||||
x = deltas[0][0];
|
||||
dx = deltas[1][0];
|
||||
dx2 = deltas[2][0];
|
||||
dx3 = deltas[3][0];
|
||||
|
||||
/* extract the y deltas */
|
||||
y = deltas[0][1];
|
||||
dy = deltas[1][1];
|
||||
dy2 = deltas[2][1];
|
||||
dy3 = deltas[3][1];
|
||||
|
||||
|
||||
lastx = CLAMP (x, 0, xmax);
|
||||
lasty = CLAMP (y, 0, ymax);
|
||||
|
||||
p_heights[lastx] = lasty;
|
||||
p_useds[lastx] = true;
|
||||
|
||||
/* loop over the curve */
|
||||
for (i = 0; i < ntimes; i++)
|
||||
{
|
||||
/* increment the x values */
|
||||
x += dx;
|
||||
dx += dx2;
|
||||
dx2 += dx3;
|
||||
|
||||
/* increment the y values */
|
||||
y += dy;
|
||||
dy += dy2;
|
||||
dy2 += dy3;
|
||||
|
||||
newx = CLAMP ((Math::round (x)), 0, xmax);
|
||||
newy = CLAMP ((Math::round (y)), 0, ymax);
|
||||
|
||||
/* if this point is different than the last one...then draw it */
|
||||
if ((lastx != newx) || (lasty != newy))
|
||||
{
|
||||
p_useds[newx]=true;
|
||||
p_heights[newx]=newy;
|
||||
}
|
||||
|
||||
lastx = newx;
|
||||
lasty = newy;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code) {
|
||||
|
||||
|
||||
|
@ -1730,7 +1973,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
|
|||
code+=OUTNAME(p_node->id,0)+"=TIME;\n";
|
||||
}break;
|
||||
case NODE_SCREEN_TEX: {
|
||||
code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+");\n";
|
||||
code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+".xy);\n";
|
||||
}break;
|
||||
case NODE_SCALAR_OP: {
|
||||
int op = p_node->param1;
|
||||
|
@ -1987,6 +2230,129 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
|
|||
case NODE_VEC_INTERP: {
|
||||
code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
|
||||
|
||||
}break;
|
||||
case NODE_COLOR_RAMP: {
|
||||
|
||||
static const int color_ramp_len=512;
|
||||
DVector<uint8_t> cramp;
|
||||
cramp.resize(color_ramp_len*4);
|
||||
{
|
||||
|
||||
DVector<Color> colors=p_node->param1;
|
||||
DVector<real_t> offsets=p_node->param2;
|
||||
int cc =colors.size();
|
||||
DVector<uint8_t>::Write crw = cramp.write();
|
||||
DVector<Color>::Read cr = colors.read();
|
||||
DVector<real_t>::Read ofr = offsets.read();
|
||||
|
||||
int at=0;
|
||||
Color color_at(0,0,0,1);
|
||||
for(int i=0;i<=cc;i++) {
|
||||
|
||||
int pos;
|
||||
Color to;
|
||||
if (i==cc) {
|
||||
if (at==color_ramp_len)
|
||||
break;
|
||||
pos=color_ramp_len;
|
||||
to=Color(1,1,1,1);
|
||||
} else {
|
||||
to=cr[i];
|
||||
pos= MIN(ofr[i]*color_ramp_len,color_ramp_len);
|
||||
}
|
||||
for(int j=at;j<pos;j++) {
|
||||
float t = (j-at)/float(pos-at);
|
||||
Color c = color_at.linear_interpolate(to,t);
|
||||
crw[j*4+0]=Math::fast_ftoi( CLAMP(c.r*255.0,0,255) );
|
||||
crw[j*4+1]=Math::fast_ftoi( CLAMP(c.g*255.0,0,255) );
|
||||
crw[j*4+2]=Math::fast_ftoi( CLAMP(c.b*255.0,0,255) );
|
||||
crw[j*4+3]=Math::fast_ftoi( CLAMP(c.a*255.0,0,255) );
|
||||
}
|
||||
|
||||
at=pos;
|
||||
color_at=to;
|
||||
}
|
||||
}
|
||||
|
||||
Image gradient(color_ramp_len,1,0,Image::FORMAT_RGBA,cramp);
|
||||
Ref<ImageTexture> it = memnew( ImageTexture );
|
||||
it->create_from_image(gradient,Texture::FLAG_FILTER|Texture::FLAG_MIPMAPS);
|
||||
|
||||
String crampname= "cramp_"+itos(p_node->id);
|
||||
set_default_texture_param(crampname,it);
|
||||
|
||||
code +="uniform texture "+crampname+";\n";
|
||||
code +="vec4 "+crampname+"_r=tex("+crampname+",vec2("+p_inputs[0]+",0));\n";
|
||||
code += OUTNAME(p_node->id,0)+"="+crampname+"_r.rgb;\n";
|
||||
code += OUTNAME(p_node->id,1)+"="+crampname+"_r.a;\n";
|
||||
|
||||
}break;
|
||||
case NODE_CURVE_MAP: {
|
||||
static const int curve_map_len=256;
|
||||
bool mapped[256];
|
||||
zeromem(mapped,sizeof(mapped));
|
||||
DVector<uint8_t> cmap;
|
||||
cmap.resize(curve_map_len);
|
||||
{
|
||||
|
||||
DVector<Point2> points=p_node->param1;
|
||||
int pc =points.size();
|
||||
DVector<uint8_t>::Write cmw = cmap.write();
|
||||
DVector<Point2>::Read pr = points.read();
|
||||
|
||||
Vector2 prev=Vector2(0,0);
|
||||
Vector2 prev2=Vector2(0,0);
|
||||
|
||||
for(int i=-1;i<pc;i++) {
|
||||
|
||||
Vector2 next;
|
||||
Vector2 next2;
|
||||
if (i+1>=pc) {
|
||||
next=Vector2(1,1);
|
||||
} else {
|
||||
next=Vector2(pr[i+1].x,pr[i+1].y);
|
||||
}
|
||||
|
||||
if (i+2>=pc) {
|
||||
next2=Vector2(1,1);
|
||||
} else {
|
||||
next2=Vector2(pr[i+2].x,pr[i+2].y);
|
||||
}
|
||||
|
||||
/*if (i==-1 && prev.offset==next.offset) {
|
||||
prev=next;
|
||||
continue;
|
||||
}*/
|
||||
|
||||
_plot_curve(prev2,prev,next,next2,cmw.ptr(),mapped);
|
||||
|
||||
prev2=prev;
|
||||
prev=next;
|
||||
}
|
||||
|
||||
uint8_t pp=0;
|
||||
for(int i=0;i<curve_map_len;i++) {
|
||||
|
||||
if (!mapped[i]) {
|
||||
cmw[i]=pp;
|
||||
} else {
|
||||
pp=cmw[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Image gradient(curve_map_len,1,0,Image::FORMAT_GRAYSCALE,cmap);
|
||||
Ref<ImageTexture> it = memnew( ImageTexture );
|
||||
it->create_from_image(gradient,Texture::FLAG_FILTER|Texture::FLAG_MIPMAPS);
|
||||
|
||||
String cmapname= "cmap_"+itos(p_node->id);
|
||||
set_default_texture_param(cmapname,it);
|
||||
|
||||
code +="uniform texture "+cmapname+";\n";
|
||||
code += OUTNAME(p_node->id,0)+"=tex("+cmapname+",vec2("+p_inputs[0]+",0)).r;\n";
|
||||
|
||||
}break;
|
||||
case NODE_SCALAR_INPUT: {
|
||||
String name = p_node->param1;
|
||||
|
@ -2043,6 +2409,22 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
|
|||
code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
|
||||
code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
|
||||
}break;
|
||||
case NODE_DEFAULT_TEXTURE: {
|
||||
|
||||
if (get_mode()==MODE_CANVAS_ITEM && p_type==SHADER_TYPE_FRAGMENT) {
|
||||
|
||||
String rname="rt_default_tex"+itos(p_node->id);
|
||||
code +="vec4 "+rname+"=tex(TEXTURE,"+p_inputs[0]+".xy);\n";
|
||||
code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
|
||||
code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
|
||||
|
||||
} else {
|
||||
//not supported
|
||||
code += OUTNAME(p_node->id,0)+"=vec3(0,0,0);\n";
|
||||
code += OUTNAME(p_node->id,1)+"=1.0;\n";
|
||||
|
||||
}
|
||||
} break;
|
||||
case NODE_OUTPUT: {
|
||||
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue