diff options
| author | Juan Linietsky <reduzio@gmail.com> | 2015-03-03 14:41:36 -0300 | 
|---|---|---|
| committer | Juan Linietsky <reduzio@gmail.com> | 2015-03-03 14:41:36 -0300 | 
| commit | 2c2894ceb674927a35d2798b3e63adabdb020077 (patch) | |
| tree | 9e8950e0acc8fb7531fa60ce8c0321a5b60c335a | |
| parent | 4d2198110b4af7f203eeef95697255569e49bce7 (diff) | |
| parent | a0ee5cc3531786a652ee43d3a57cb69dff34bd70 (diff) | |
Merge branch 'master' of https://github.com/okamstudio/godot
Conflicts:
	modules/gdscript/gd_tokenizer.cpp
	scene/resources/shader_graph.h
151 files changed, 12074 insertions, 905 deletions
diff --git a/.gitignore b/.gitignore index 4aee83c13f..09fac62297 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/bin/tests/test_string.cpp b/bin/tests/test_string.cpp index 66238b066d..4aaddd8ac1 100644 --- a/bin/tests/test_string.cpp +++ b/bin/tests/test_string.cpp @@ -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  }; diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 0c5d21b4f6..8d18acdc23 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -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); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 12a4ae86eb..057ad90fe9 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -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); diff --git a/core/dvector.h b/core/dvector.h index 72661882cd..29be417844 100644 --- a/core/dvector.h +++ b/core/dvector.h @@ -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; diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index faead675d4..c7906018e9 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -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(){ diff --git a/core/io/http_client.h b/core/io/http_client.h index 09ad64f48a..d0ebaa4596 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -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(); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index e2371fe24f..ead6984650 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -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(); diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp index 75384d4ab6..033b4d5e5a 100644 --- a/core/io/resource_format_xml.cpp +++ b/core/io/resource_format_xml.cpp @@ -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); diff --git a/core/list.h b/core/list.h index f581feb735..ef30e43d21 100644 --- a/core/list.h +++ b/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  	 */ diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index a60dea7379..fbe5f8c741 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -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;			 diff --git a/core/math/geometry.h b/core/math/geometry.h index 81530e30c0..7e0cc01a22 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -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]; diff --git a/core/math/math_2d.h b/core/math/math_2d.h index fa40d305f5..5bc1b5f0be 100644 --- a/core/math/math_2d.h +++ b/core/math/math_2d.h @@ -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 { diff --git a/core/math/triangulator.cpp b/core/math/triangulator.cpp new file mode 100644 index 0000000000..8f82d76823 --- /dev/null +++ b/core/math/triangulator.cpp @@ -0,0 +1,1550 @@ +//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. + + +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include "triangulator.h" + + +#define TRIANGULATOR_VERTEXTYPE_REGULAR 0 +#define TRIANGULATOR_VERTEXTYPE_START 1 +#define TRIANGULATOR_VERTEXTYPE_END 2 +#define TRIANGULATOR_VERTEXTYPE_SPLIT 3 +#define TRIANGULATOR_VERTEXTYPE_MERGE 4 + +TriangulatorPoly::TriangulatorPoly() { +	hole = false; +	numpoints = 0; +	points = NULL; +} + +TriangulatorPoly::~TriangulatorPoly() { +	if(points) delete [] points; +} + +void TriangulatorPoly::Clear() { +	if(points) delete [] points; +	hole = false; +	numpoints = 0; +	points = NULL; +} + +void TriangulatorPoly::Init(long numpoints) { +	Clear(); +	this->numpoints = numpoints; +	points = new Vector2[numpoints]; +} + +void TriangulatorPoly::Triangle(Vector2 &p1, Vector2 &p2, Vector2 &p3) { +	Init(3); +	points[0] = p1; +	points[1] = p2; +	points[2] = p3; +} + +TriangulatorPoly::TriangulatorPoly(const TriangulatorPoly &src) { +	hole = src.hole; +	numpoints = src.numpoints; +	points = new Vector2[numpoints]; +	memcpy(points, src.points, numpoints*sizeof(Vector2)); +} + +TriangulatorPoly& TriangulatorPoly::operator=(const TriangulatorPoly &src) { +	Clear(); +	hole = src.hole; +	numpoints = src.numpoints; +	points = new Vector2[numpoints]; +	memcpy(points, src.points, numpoints*sizeof(Vector2)); +	return *this; +} + +int TriangulatorPoly::GetOrientation() { +	long i1,i2; +	real_t area = 0; +	for(i1=0; i1<numpoints; i1++) { +		i2 = i1+1; +		if(i2 == numpoints) i2 = 0; +		area += points[i1].x * points[i2].y - points[i1].y * points[i2].x; +	} +	if(area>0) return TRIANGULATOR_CCW; +	if(area<0) return TRIANGULATOR_CW; +	return 0; +} + +void TriangulatorPoly::SetOrientation(int orientation) { +	int polyorientation = GetOrientation(); +	if(polyorientation&&(polyorientation!=orientation)) { +		Invert(); +	} +} + +void TriangulatorPoly::Invert() { +	long i; +	Vector2 *invpoints; + +	invpoints = new Vector2[numpoints]; +	for(i=0;i<numpoints;i++) { +		invpoints[i] = points[numpoints-i-1]; +	} + +	delete [] points; +	points = invpoints; +} + +Vector2 TriangulatorPartition::Normalize(const Vector2 &p) { +	Vector2 r; +	real_t n = sqrt(p.x*p.x + p.y*p.y); +	if(n!=0) { +		r = p/n; +	} else { +		r.x = 0; +		r.y = 0; +	} +	return r; +} + +real_t TriangulatorPartition::Distance(const Vector2 &p1, const Vector2 &p2) { +	real_t dx,dy; +	dx = p2.x - p1.x; +	dy = p2.y - p1.y; +	return(sqrt(dx*dx + dy*dy)); +} + +//checks if two lines intersect +int TriangulatorPartition::Intersects(Vector2 &p11, Vector2 &p12, Vector2 &p21, Vector2 &p22) { +	if((p11.x == p21.x)&&(p11.y == p21.y)) return 0; +	if((p11.x == p22.x)&&(p11.y == p22.y)) return 0; +	if((p12.x == p21.x)&&(p12.y == p21.y)) return 0; +	if((p12.x == p22.x)&&(p12.y == p22.y)) return 0; + +	Vector2 v1ort,v2ort,v; +	real_t dot11,dot12,dot21,dot22; + +	v1ort.x = p12.y-p11.y; +	v1ort.y = p11.x-p12.x; + +	v2ort.x = p22.y-p21.y; +	v2ort.y = p21.x-p22.x; + +	v = p21-p11; +	dot21 = v.x*v1ort.x + v.y*v1ort.y; +	v = p22-p11; +	dot22 = v.x*v1ort.x + v.y*v1ort.y; + +	v = p11-p21; +	dot11 = v.x*v2ort.x + v.y*v2ort.y; +	v = p12-p21; +	dot12 = v.x*v2ort.x + v.y*v2ort.y; + +	if(dot11*dot12>0) return 0; +	if(dot21*dot22>0) return 0; + +	return 1; +} + +//removes holes from inpolys by merging them with non-holes +int TriangulatorPartition::RemoveHoles(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *outpolys) { +	List<TriangulatorPoly> polys; +	List<TriangulatorPoly>::Element *holeiter,*polyiter,*iter,*iter2; +	long i,i2,holepointindex,polypointindex; +	Vector2 holepoint,polypoint,bestpolypoint; +	Vector2 linep1,linep2; +	Vector2 v1,v2; +	TriangulatorPoly newpoly; +	bool hasholes; +	bool pointvisible; +	bool pointfound; + +	//check for trivial case (no holes) +	hasholes = false; +	for(iter = inpolys->front(); iter; iter=iter->next()) { +		if(iter->get().IsHole()) { +			hasholes = true; +			break; +		} +	} +	if(!hasholes) { +		for(iter = inpolys->front(); iter; iter=iter->next()) { +			outpolys->push_back(iter->get()); +		} +		return 1; +	} + +	polys = *inpolys; + +	while(1) { +		//find the hole point with the largest x +		hasholes = false; +		for(iter = polys.front(); iter; iter=iter->next()) { +			if(!iter->get().IsHole()) continue; + +			if(!hasholes) { +				hasholes = true; +				holeiter = iter; +				holepointindex = 0; +			} + +			for(i=0; i < iter->get().GetNumPoints(); i++) { +				if(iter->get().GetPoint(i).x > holeiter->get().GetPoint(holepointindex).x) { +					holeiter = iter; +					holepointindex = i; +				} +			} +		} +		if(!hasholes) break; +		holepoint = holeiter->get().GetPoint(holepointindex); + +		pointfound = false; +		for(iter = polys.front(); iter; iter=iter->next()) { +			if(iter->get().IsHole()) continue; +			for(i=0; i < iter->get().GetNumPoints(); i++) { +				if(iter->get().GetPoint(i).x <= holepoint.x) continue; +				if(!InCone(iter->get().GetPoint((i+iter->get().GetNumPoints()-1)%(iter->get().GetNumPoints())), +					   iter->get().GetPoint(i), +					   iter->get().GetPoint((i+1)%(iter->get().GetNumPoints())), +					   holepoint)) +					continue; +				polypoint = iter->get().GetPoint(i); +				if(pointfound) { +					v1 = Normalize(polypoint-holepoint); +					v2 = Normalize(bestpolypoint-holepoint); +					if(v2.x > v1.x) continue; +				} +				pointvisible = true; +				for(iter2 = polys.front(); iter2; iter2=iter2->next()) { +					if(iter2->get().IsHole()) continue; +					for(i2=0; i2 < iter2->get().GetNumPoints(); i2++) { +						linep1 = iter2->get().GetPoint(i2); +						linep2 = iter2->get().GetPoint((i2+1)%(iter2->get().GetNumPoints())); +						if(Intersects(holepoint,polypoint,linep1,linep2)) { +							pointvisible = false; +							break; +						} +					} +					if(!pointvisible) break; +				} +				if(pointvisible) { +					pointfound = true; +					bestpolypoint = polypoint; +					polyiter = iter; +					polypointindex = i; +				} +			} +		} + +		if(!pointfound) return 0; + +		newpoly.Init(holeiter->get().GetNumPoints() + polyiter->get().GetNumPoints() + 2); +		i2 = 0; +		for(i=0;i<=polypointindex;i++) { +			newpoly[i2] = polyiter->get().GetPoint(i); +			i2++; +		} +		for(i=0;i<=holeiter->get().GetNumPoints();i++) { +			newpoly[i2] = holeiter->get().GetPoint((i+holepointindex)%holeiter->get().GetNumPoints()); +			i2++; +		} +		for(i=polypointindex;i<polyiter->get().GetNumPoints();i++) { +			newpoly[i2] = polyiter->get().GetPoint(i); +			i2++; +		} + +		polys.erase(holeiter); +		polys.erase(polyiter); +		polys.push_back(newpoly); +	} + +	for(iter = polys.front(); iter; iter=iter->next()) { +		outpolys->push_back(iter->get()); +	} + +	return 1; +} + +bool TriangulatorPartition::IsConvex(Vector2& p1, Vector2& p2, Vector2& p3) { +	real_t tmp; +	tmp = (p3.y-p1.y)*(p2.x-p1.x)-(p3.x-p1.x)*(p2.y-p1.y); +	if(tmp>0) return 1; +	else return 0; +} + +bool TriangulatorPartition::IsReflex(Vector2& p1, Vector2& p2, Vector2& p3) { +	real_t tmp; +	tmp = (p3.y-p1.y)*(p2.x-p1.x)-(p3.x-p1.x)*(p2.y-p1.y); +	if(tmp<0) return 1; +	else return 0; +} + +bool TriangulatorPartition::IsInside(Vector2& p1, Vector2& p2, Vector2& p3, Vector2 &p) { +	if(IsConvex(p1,p,p2)) return false; +	if(IsConvex(p2,p,p3)) return false; +	if(IsConvex(p3,p,p1)) return false; +	return true; +} + +bool TriangulatorPartition::InCone(Vector2 &p1, Vector2 &p2, Vector2 &p3, Vector2 &p) { +	bool convex; + +	convex = IsConvex(p1,p2,p3); + +	if(convex) { +		if(!IsConvex(p1,p2,p)) return false; +		if(!IsConvex(p2,p3,p)) return false; +		return true; +	} else { +		if(IsConvex(p1,p2,p)) return true; +		if(IsConvex(p2,p3,p)) return true; +		return false; +	} +} + +bool TriangulatorPartition::InCone(PartitionVertex *v, Vector2 &p) { +	Vector2 p1,p2,p3; + +	p1 = v->previous->p; +	p2 = v->p; +	p3 = v->next->p; + +	return InCone(p1,p2,p3,p); +} + +void TriangulatorPartition::UpdateVertexReflexity(PartitionVertex *v) { +	PartitionVertex *v1,*v3; +	v1 = v->previous; +	v3 = v->next; +	v->isConvex = !IsReflex(v1->p,v->p,v3->p); +} + +void TriangulatorPartition::UpdateVertex(PartitionVertex *v, PartitionVertex *vertices, long numvertices) { +	long i; +	PartitionVertex *v1,*v3; +	Vector2 vec1,vec3; + +	v1 = v->previous; +	v3 = v->next; + +	v->isConvex = IsConvex(v1->p,v->p,v3->p); + +	vec1 = Normalize(v1->p - v->p); +	vec3 = Normalize(v3->p - v->p); +	v->angle = vec1.x*vec3.x + vec1.y*vec3.y; + +	if(v->isConvex) { +		v->isEar = true; +		for(i=0;i<numvertices;i++) { +			if((vertices[i].p.x==v->p.x)&&(vertices[i].p.y==v->p.y)) continue; +			if((vertices[i].p.x==v1->p.x)&&(vertices[i].p.y==v1->p.y)) continue; +			if((vertices[i].p.x==v3->p.x)&&(vertices[i].p.y==v3->p.y)) continue; +			if(IsInside(v1->p,v->p,v3->p,vertices[i].p)) { +				v->isEar = false; +				break; +			} +		} +	} else { +		v->isEar = false; +	} +} + +//triangulation by ear removal +int TriangulatorPartition::Triangulate_EC(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles) { +	long numvertices; +	PartitionVertex *vertices; +	PartitionVertex *ear; +	TriangulatorPoly triangle; +	long i,j; +	bool earfound; + +	if(poly->GetNumPoints() < 3) return 0; +	if(poly->GetNumPoints() == 3) { +		triangles->push_back(*poly); +		return 1; +	} + +	numvertices = poly->GetNumPoints(); + +	vertices = new PartitionVertex[numvertices]; +	for(i=0;i<numvertices;i++) { +		vertices[i].isActive = true; +		vertices[i].p = poly->GetPoint(i); +		if(i==(numvertices-1)) vertices[i].next=&(vertices[0]); +		else vertices[i].next=&(vertices[i+1]); +		if(i==0) vertices[i].previous = &(vertices[numvertices-1]); +		else vertices[i].previous = &(vertices[i-1]); +	} +	for(i=0;i<numvertices;i++) { +		UpdateVertex(&vertices[i],vertices,numvertices); +	} + +	for(i=0;i<numvertices-3;i++) { +		earfound = false; +		//find the most extruded ear +		for(j=0;j<numvertices;j++) { +			if(!vertices[j].isActive) continue; +			if(!vertices[j].isEar) continue; +			if(!earfound) { +				earfound = true; +				ear = &(vertices[j]); +			} else { +				if(vertices[j].angle > ear->angle) { +					ear = &(vertices[j]); +				} +			} +		} +		if(!earfound) { +			delete [] vertices; +			return 0; +		} + +		triangle.Triangle(ear->previous->p,ear->p,ear->next->p); +		triangles->push_back(triangle); + +		ear->isActive = false; +		ear->previous->next = ear->next; +		ear->next->previous = ear->previous; + +		if(i==numvertices-4) break; + +		UpdateVertex(ear->previous,vertices,numvertices); +		UpdateVertex(ear->next,vertices,numvertices); +	} +	for(i=0;i<numvertices;i++) { +		if(vertices[i].isActive) { +			triangle.Triangle(vertices[i].previous->p,vertices[i].p,vertices[i].next->p); +			triangles->push_back(triangle); +			break; +		} +	} + +	delete [] vertices; + +	return 1; +} + +int TriangulatorPartition::Triangulate_EC(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles) { +	List<TriangulatorPoly> outpolys; +	List<TriangulatorPoly>::Element*iter; + +	if(!RemoveHoles(inpolys,&outpolys)) return 0; +	for(iter=outpolys.front();iter;iter=iter->next()) { +		if(!Triangulate_EC(&(iter->get()),triangles)) return 0; +	} +	return 1; +} + +int TriangulatorPartition::ConvexPartition_HM(TriangulatorPoly *poly, List<TriangulatorPoly> *parts) { +	List<TriangulatorPoly> triangles; +	List<TriangulatorPoly>::Element *iter1,*iter2; +	TriangulatorPoly *poly1,*poly2; +	TriangulatorPoly newpoly; +	Vector2 d1,d2,p1,p2,p3; +	long i11,i12,i21,i22,i13,i23,j,k; +	bool isdiagonal; +	long numreflex; + +	//check if the poly is already convex +	numreflex = 0; +	for(i11=0;i11<poly->GetNumPoints();i11++) { +		if(i11==0) i12 = poly->GetNumPoints()-1; +		else i12=i11-1; +		if(i11==(poly->GetNumPoints()-1)) i13=0; +		else i13=i11+1; +		if(IsReflex(poly->GetPoint(i12),poly->GetPoint(i11),poly->GetPoint(i13))) { +			numreflex = 1; +			break; +		} +	} +	if(numreflex == 0) { +		parts->push_back(*poly); +		return 1; +	} + +	if(!Triangulate_EC(poly,&triangles)) return 0; + +	for(iter1 = triangles.front(); iter1 ; iter1=iter1->next()) { +		poly1 = &(iter1->get()); +		for(i11=0;i11<poly1->GetNumPoints();i11++) { +			d1 = poly1->GetPoint(i11); +			i12 = (i11+1)%(poly1->GetNumPoints()); +			d2 = poly1->GetPoint(i12); + +			isdiagonal = false; +			for(iter2 = iter1; iter2 ; iter2=iter2->next()) { +				if(iter1 == iter2) continue; +				poly2 = &(iter2->get()); + +				for(i21=0;i21<poly2->GetNumPoints();i21++) { +					if((d2.x != poly2->GetPoint(i21).x)||(d2.y != poly2->GetPoint(i21).y)) continue; +					i22 = (i21+1)%(poly2->GetNumPoints()); +					if((d1.x != poly2->GetPoint(i22).x)||(d1.y != poly2->GetPoint(i22).y)) continue; +					isdiagonal = true; +					break; +				} +				if(isdiagonal) break; +			} + +			if(!isdiagonal) continue; + +			p2 = poly1->GetPoint(i11); +			if(i11 == 0) i13 = poly1->GetNumPoints()-1; +			else i13 = i11-1; +			p1 = poly1->GetPoint(i13); +			if(i22 == (poly2->GetNumPoints()-1)) i23 = 0; +			else i23 = i22+1; +			p3 = poly2->GetPoint(i23); + +			if(!IsConvex(p1,p2,p3)) continue; + +			p2 = poly1->GetPoint(i12); +			if(i12 == (poly1->GetNumPoints()-1)) i13 = 0; +			else i13 = i12+1; +			p3 = poly1->GetPoint(i13); +			if(i21 == 0) i23 = poly2->GetNumPoints()-1; +			else i23 = i21-1; +			p1 = poly2->GetPoint(i23); + +			if(!IsConvex(p1,p2,p3)) continue; + +			newpoly.Init(poly1->GetNumPoints()+poly2->GetNumPoints()-2); +			k = 0; +			for(j=i12;j!=i11;j=(j+1)%(poly1->GetNumPoints())) { +				newpoly[k] = poly1->GetPoint(j); +				k++; +			} +			for(j=i22;j!=i21;j=(j+1)%(poly2->GetNumPoints())) { +				newpoly[k] = poly2->GetPoint(j); +				k++; +			} + +			triangles.erase(iter2); +			iter1->get() = newpoly; +			poly1 = &(iter1->get()); +			i11 = -1; + +			continue; +		} +	} + +	for(iter1 = triangles.front(); iter1 ; iter1=iter1->next()) { +		parts->push_back(iter1->get()); +	} + +	return 1; +} + +int TriangulatorPartition::ConvexPartition_HM(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *parts) { +	List<TriangulatorPoly> outpolys; +	List<TriangulatorPoly>::Element* iter; + +	if(!RemoveHoles(inpolys,&outpolys)) return 0; +	for(iter=outpolys.front();iter;iter=iter->next()) { +		if(!ConvexPartition_HM(&(iter->get()),parts)) return 0; +	} +	return 1; +} + +//minimum-weight polygon triangulation by dynamic programming +//O(n^3) time complexity +//O(n^2) space complexity +int TriangulatorPartition::Triangulate_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles) { +	long i,j,k,gap,n; +	DPState **dpstates; +	Vector2 p1,p2,p3,p4; +	long bestvertex; +	real_t weight,minweight,d1,d2; +	Diagonal diagonal,newdiagonal; +	List<Diagonal> diagonals; +	TriangulatorPoly triangle; +	int ret = 1; + +	n = poly->GetNumPoints(); +	dpstates = new DPState *[n]; +	for(i=1;i<n;i++) { +		dpstates[i] = new DPState[i]; +	} + +	//init states and visibility +	for(i=0;i<(n-1);i++) { +		p1 = poly->GetPoint(i); +		for(j=i+1;j<n;j++) { +			dpstates[j][i].visible = true; +			dpstates[j][i].weight = 0; +			dpstates[j][i].bestvertex = -1; +			if(j!=(i+1)) { +				p2 = poly->GetPoint(j); + +				//visibility check +				if(i==0) p3 = poly->GetPoint(n-1); +				else p3 = poly->GetPoint(i-1); +				if(i==(n-1)) p4 = poly->GetPoint(0); +				else p4 = poly->GetPoint(i+1); +				if(!InCone(p3,p1,p4,p2)) { +					dpstates[j][i].visible = false; +					continue; +				} + +				if(j==0) p3 = poly->GetPoint(n-1); +				else p3 = poly->GetPoint(j-1); +				if(j==(n-1)) p4 = poly->GetPoint(0); +				else p4 = poly->GetPoint(j+1); +				if(!InCone(p3,p2,p4,p1)) { +					dpstates[j][i].visible = false; +					continue; +				} + +				for(k=0;k<n;k++) { +					p3 = poly->GetPoint(k); +					if(k==(n-1)) p4 = poly->GetPoint(0); +					else p4 = poly->GetPoint(k+1); +					if(Intersects(p1,p2,p3,p4)) { +						dpstates[j][i].visible = false; +						break; +					} +				} +			} +		} +	} +	dpstates[n-1][0].visible = true; +	dpstates[n-1][0].weight = 0; +	dpstates[n-1][0].bestvertex = -1; + +	for(gap = 2; gap<n; gap++) { +		for(i=0; i<(n-gap); i++) { +			j = i+gap; +			if(!dpstates[j][i].visible) continue; +			bestvertex = -1; +			for(k=(i+1);k<j;k++) { +				if(!dpstates[k][i].visible) continue; +				if(!dpstates[j][k].visible) continue; + +				if(k<=(i+1)) d1=0; +				else d1 = Distance(poly->GetPoint(i),poly->GetPoint(k)); +				if(j<=(k+1)) d2=0; +				else d2 = Distance(poly->GetPoint(k),poly->GetPoint(j)); + +				weight = dpstates[k][i].weight + dpstates[j][k].weight + d1 + d2; + +				if((bestvertex == -1)||(weight<minweight)) { +					bestvertex = k; +					minweight = weight; +				} +			} +			if(bestvertex == -1) { +				for(i=1;i<n;i++) { +					delete [] dpstates[i]; +				} +				delete [] dpstates; + +				return 0; +			} + +			dpstates[j][i].bestvertex = bestvertex; +			dpstates[j][i].weight = minweight; +		} +	} + +	newdiagonal.index1 = 0; +	newdiagonal.index2 = n-1; +	diagonals.push_back(newdiagonal); +	while(!diagonals.empty()) { +		diagonal = (diagonals.front()->get()); +		diagonals.pop_front(); +		bestvertex = dpstates[diagonal.index2][diagonal.index1].bestvertex; +		if(bestvertex == -1) { +			ret = 0; +			break; +		} +		triangle.Triangle(poly->GetPoint(diagonal.index1),poly->GetPoint(bestvertex),poly->GetPoint(diagonal.index2)); +		triangles->push_back(triangle); +		if(bestvertex > (diagonal.index1+1)) { +			newdiagonal.index1 = diagonal.index1; +			newdiagonal.index2 = bestvertex; +			diagonals.push_back(newdiagonal); +		} +		if(diagonal.index2 > (bestvertex+1)) { +			newdiagonal.index1 = bestvertex; +			newdiagonal.index2 = diagonal.index2; +			diagonals.push_back(newdiagonal); +		} +	} + +	for(i=1;i<n;i++) { +		delete [] dpstates[i]; +	} +	delete [] dpstates; + +	return ret; +} + +void TriangulatorPartition::UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates) { +	Diagonal newdiagonal; +	List<Diagonal> *pairs; +	long w2; + +	w2 = dpstates[a][b].weight; +	if(w>w2) return; + +	pairs = &(dpstates[a][b].pairs); +	newdiagonal.index1 = i; +	newdiagonal.index2 = j; + +	if(w<w2) { +		pairs->clear(); +		pairs->push_front(newdiagonal); +		dpstates[a][b].weight = w; +	} else { +		if((!pairs->empty())&&(i <= pairs->front()->get().index1)) return; +		while((!pairs->empty())&&(pairs->front()->get().index2 >= j)) pairs->pop_front(); +		pairs->push_front(newdiagonal); +	} +} + +void TriangulatorPartition::TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) { +	List<Diagonal> *pairs; +	List<Diagonal>::Element *iter,*lastiter; +	long top; +	long w; + +	if(!dpstates[i][j].visible) return; +	top = j; +	w = dpstates[i][j].weight; +	if(k-j > 1) { +		if (!dpstates[j][k].visible) return; +		w += dpstates[j][k].weight + 1; +	} +	if(j-i > 1) { +		pairs = &(dpstates[i][j].pairs); +		iter = NULL; +		lastiter = NULL; +		while(iter!=pairs->front()) { +			if (!iter) +				iter=pairs->back(); +			else +				iter=iter->prev(); + +			if(!IsReflex(vertices[iter->get().index2].p,vertices[j].p,vertices[k].p)) lastiter = iter; +			else break; +		} +		if(lastiter == NULL) w++; +		else { +			if(IsReflex(vertices[k].p,vertices[i].p,vertices[lastiter->get().index1].p)) w++; +			else top = lastiter->get().index1; +		} +	} +	UpdateState(i,k,w,top,j,dpstates); +} + +void TriangulatorPartition::TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) { +	List<Diagonal> *pairs; +	List<Diagonal>::Element* iter,*lastiter; +	long top; +	long w; + +	if(!dpstates[j][k].visible) return; +	top = j; +	w = dpstates[j][k].weight; + +	if (j-i > 1) { +		if (!dpstates[i][j].visible) return; +		w += dpstates[i][j].weight + 1; +	} +	if (k-j > 1) { +		pairs = &(dpstates[j][k].pairs); + +		iter = pairs->front(); +		if((!pairs->empty())&&(!IsReflex(vertices[i].p,vertices[j].p,vertices[iter->get().index1].p))) { +			lastiter = iter; +			while(iter!=NULL) { +				if(!IsReflex(vertices[i].p,vertices[j].p,vertices[iter->get().index1].p)) { +					lastiter = iter; +					iter=iter->next(); +				} +				else break; +			} +			if(IsReflex(vertices[lastiter->get().index2].p,vertices[k].p,vertices[i].p)) w++; +			else top = lastiter->get().index2; +		} else w++; +	} +	UpdateState(i,k,w,j,top,dpstates); +} + +int TriangulatorPartition::ConvexPartition_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *parts) { +	Vector2 p1,p2,p3,p4; +	PartitionVertex *vertices; +	DPState2 **dpstates; +	long i,j,k,n,gap; +	List<Diagonal> diagonals,diagonals2; +	Diagonal diagonal,newdiagonal; +	List<Diagonal> *pairs,*pairs2; +	List<Diagonal>::Element* iter,*iter2; +	int ret; +	TriangulatorPoly newpoly; +	List<long> indices; +	List<long>::Element* iiter; +	bool ijreal,jkreal; + +	n = poly->GetNumPoints(); +	vertices = new PartitionVertex[n]; + +	dpstates = new DPState2 *[n]; +	for(i=0;i<n;i++) { +		dpstates[i] = new DPState2[n]; +	} + +	//init vertex information +	for(i=0;i<n;i++) { +		vertices[i].p = poly->GetPoint(i); +		vertices[i].isActive = true; +		if(i==0) vertices[i].previous = &(vertices[n-1]); +		else vertices[i].previous = &(vertices[i-1]); +		if(i==(poly->GetNumPoints()-1)) vertices[i].next = &(vertices[0]); +		else vertices[i].next = &(vertices[i+1]); +	} +	for(i=1;i<n;i++) { +		UpdateVertexReflexity(&(vertices[i])); +	} + +	//init states and visibility +	for(i=0;i<(n-1);i++) { +		p1 = poly->GetPoint(i); +		for(j=i+1;j<n;j++) { +			dpstates[i][j].visible = true; +			if(j==i+1) { +				dpstates[i][j].weight = 0; +			} else { +				dpstates[i][j].weight = 2147483647; +			} +			if(j!=(i+1)) { +				p2 = poly->GetPoint(j); + +				//visibility check +				if(!InCone(&vertices[i],p2)) { +					dpstates[i][j].visible = false; +					continue; +				} +				if(!InCone(&vertices[j],p1)) { +					dpstates[i][j].visible = false; +					continue; +				} + +				for(k=0;k<n;k++) { +					p3 = poly->GetPoint(k); +					if(k==(n-1)) p4 = poly->GetPoint(0); +					else p4 = poly->GetPoint(k+1); +					if(Intersects(p1,p2,p3,p4)) { +						dpstates[i][j].visible = false; +						break; +					} +				} +			} +		} +	} +	for(i=0;i<(n-2);i++) { +		j = i+2; +		if(dpstates[i][j].visible) { +			dpstates[i][j].weight = 0; +			newdiagonal.index1 = i+1; +			newdiagonal.index2 = i+1; +			dpstates[i][j].pairs.push_back(newdiagonal); +		} +	} + +	dpstates[0][n-1].visible = true; +	vertices[0].isConvex = false; //by convention + +	for(gap=3; gap<n; gap++) { +		for(i=0;i<n-gap;i++) { +			if(vertices[i].isConvex) continue; +			k = i+gap; +			if(dpstates[i][k].visible) { +				if(!vertices[k].isConvex) { +					for(j=i+1;j<k;j++) TypeA(i,j,k,vertices,dpstates); +				} else { +					for(j=i+1;j<(k-1);j++) { +						if(vertices[j].isConvex) continue; +						TypeA(i,j,k,vertices,dpstates); +					} +					TypeA(i,k-1,k,vertices,dpstates); +				} +			} +		} +		for(k=gap;k<n;k++) { +			if(vertices[k].isConvex) continue; +			i = k-gap; +			if((vertices[i].isConvex)&&(dpstates[i][k].visible)) { +				TypeB(i,i+1,k,vertices,dpstates); +				for(j=i+2;j<k;j++) { +					if(vertices[j].isConvex) continue; +					TypeB(i,j,k,vertices,dpstates); +				} +			} +		} +	} + + +	//recover solution +	ret = 1; +	newdiagonal.index1 = 0; +	newdiagonal.index2 = n-1; +	diagonals.push_front(newdiagonal); +	while(!diagonals.empty()) { +		diagonal = (diagonals.front()->get()); +		diagonals.pop_front(); +		if((diagonal.index2 - diagonal.index1) <=1) continue; +		pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs); +		if(pairs->empty()) { +			ret = 0; +			break; +		} +		if(!vertices[diagonal.index1].isConvex) { +			iter = pairs->back(); + +			j = iter->get().index2; +			newdiagonal.index1 = j; +			newdiagonal.index2 = diagonal.index2; +			diagonals.push_front(newdiagonal); +			if((j - diagonal.index1)>1) { +				if(iter->get().index1 != iter->get().index2) { +					pairs2 = &(dpstates[diagonal.index1][j].pairs); +					while(1) { +						if(pairs2->empty()) { +							ret = 0; +							break; +						} +						iter2 = pairs2->back(); + +						if(iter->get().index1 != iter2->get().index1) pairs2->pop_back(); +						else break; +					} +					if(ret == 0) break; +				} +				newdiagonal.index1 = diagonal.index1; +				newdiagonal.index2 = j; +				diagonals.push_front(newdiagonal); +			} +		} else { +			iter = pairs->front(); +			j = iter->get().index1; +			newdiagonal.index1 = diagonal.index1; +			newdiagonal.index2 = j; +			diagonals.push_front(newdiagonal); +			if((diagonal.index2 - j) > 1) { +				if(iter->get().index1 != iter->get().index2) { +					pairs2 = &(dpstates[j][diagonal.index2].pairs); +					while(1) { +						if(pairs2->empty()) { +							ret = 0; +							break; +						} +						iter2 = pairs2->front(); +						if(iter->get().index2 != iter2->get().index2) pairs2->pop_front(); +						else break; +					} +					if(ret == 0) break; +				} +				newdiagonal.index1 = j; +				newdiagonal.index2 = diagonal.index2; +				diagonals.push_front(newdiagonal); +			} +		} +	} + +	if(ret == 0) { +		for(i=0;i<n;i++) { +			delete [] dpstates[i]; +		} +		delete [] dpstates; +		delete [] vertices; + +		return ret; +	} + +	newdiagonal.index1 = 0; +	newdiagonal.index2 = n-1; +	diagonals.push_front(newdiagonal); +	while(!diagonals.empty()) { +		diagonal = (diagonals.front())->get(); +		diagonals.pop_front(); +		if((diagonal.index2 - diagonal.index1) <= 1) continue; + +		indices.clear(); +		diagonals2.clear(); +		indices.push_back(diagonal.index1); +		indices.push_back(diagonal.index2); +		diagonals2.push_front(diagonal); + +		while(!diagonals2.empty()) { +			diagonal = (diagonals2.front()->get()); +			diagonals2.pop_front(); +			if((diagonal.index2 - diagonal.index1) <= 1) continue; +			ijreal = true; +			jkreal = true; +			pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs); +			if(!vertices[diagonal.index1].isConvex) { +				iter = pairs->back(); +				j = iter->get().index2; +				if(iter->get().index1 != iter->get().index2) ijreal = false; +			} else { +				iter = pairs->front(); +				j = iter->get().index1; +				if(iter->get().index1 != iter->get().index2) jkreal = false; +			} + +			newdiagonal.index1 = diagonal.index1; +			newdiagonal.index2 = j; +			if(ijreal) { +				diagonals.push_back(newdiagonal); +			} else { +				diagonals2.push_back(newdiagonal); +			} + +			newdiagonal.index1 = j; +			newdiagonal.index2 = diagonal.index2; +			if(jkreal) { +				diagonals.push_back(newdiagonal); +			} else { +				diagonals2.push_back(newdiagonal); +			} + +			indices.push_back(j); +		} + +		indices.sort(); +		newpoly.Init((long)indices.size()); +		k=0; +		for(iiter = indices.front();iiter;iiter=iiter->next()) { +			newpoly[k] = vertices[iiter->get()].p; +			k++; +		} +		parts->push_back(newpoly); +	} + +	for(i=0;i<n;i++) { +		delete [] dpstates[i]; +	} +	delete [] dpstates; +	delete [] vertices; + +	return ret; +} + +//triangulates a set of polygons by first partitioning them into monotone polygons +//O(n*log(n)) time complexity, O(n) space complexity +//the algorithm used here is outlined in the book +//"Computational Geometry: Algorithms and Applications" +//by Mark de Berg, Otfried Cheong, Marc van Kreveld and Mark Overmars +int TriangulatorPartition::MonotonePartition(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *monotonePolys) { +	List<TriangulatorPoly>::Element *iter; +	MonotoneVertex *vertices; +	long i,numvertices,vindex,vindex2,newnumvertices,maxnumvertices; +	long polystartindex, polyendindex; +	TriangulatorPoly *poly; +	MonotoneVertex *v,*v2,*vprev,*vnext; +	ScanLineEdge newedge; +	bool error = false; + +	numvertices = 0; +	for(iter = inpolys->front(); iter ; iter=iter->next()) { +		numvertices += iter->get().GetNumPoints(); +	} + +	maxnumvertices = numvertices*3; +	vertices = new MonotoneVertex[maxnumvertices]; +	newnumvertices = numvertices; + +	polystartindex = 0; +	for(iter = inpolys->front(); iter ; iter=iter->next()) { +		poly = &(iter->get()); +		polyendindex = polystartindex + poly->GetNumPoints()-1; +		for(i=0;i<poly->GetNumPoints();i++) { +			vertices[i+polystartindex].p = poly->GetPoint(i); +			if(i==0) vertices[i+polystartindex].previous = polyendindex; +			else vertices[i+polystartindex].previous = i+polystartindex-1; +			if(i==(poly->GetNumPoints()-1)) vertices[i+polystartindex].next = polystartindex; +			else vertices[i+polystartindex].next = i+polystartindex+1; +		} +		polystartindex = polyendindex+1; +	} + +	//construct the priority queue +	long *priority = new long [numvertices]; +	for(i=0;i<numvertices;i++) priority[i] = i; +	SortArray<long,VertexSorter> sorter; +	sorter.compare.vertices=vertices; +	sorter.sort(priority,numvertices); + +	//determine vertex types +	char *vertextypes = new char[maxnumvertices]; +	for(i=0;i<numvertices;i++) { +		v = &(vertices[i]); +		vprev = &(vertices[v->previous]); +		vnext = &(vertices[v->next]); + +		if(Below(vprev->p,v->p)&&Below(vnext->p,v->p)) { +			if(IsConvex(vnext->p,vprev->p,v->p)) { +				vertextypes[i] = TRIANGULATOR_VERTEXTYPE_START; +			} else { +				vertextypes[i] = TRIANGULATOR_VERTEXTYPE_SPLIT; +			} +		} else if(Below(v->p,vprev->p)&&Below(v->p,vnext->p)) { +			if(IsConvex(vnext->p,vprev->p,v->p)) +			{ +				vertextypes[i] = TRIANGULATOR_VERTEXTYPE_END; +			} else { +				vertextypes[i] = TRIANGULATOR_VERTEXTYPE_MERGE; +			} +		} else { +			vertextypes[i] = TRIANGULATOR_VERTEXTYPE_REGULAR; +		} +	} + +	//helpers +	long *helpers = new long[maxnumvertices]; + +	//binary search tree that holds edges intersecting the scanline +	//note that while set doesn't actually have to be implemented as a tree +	//complexity requirements for operations are the same as for the balanced binary search tree +	Set<ScanLineEdge> edgeTree; +	//store iterators to the edge tree elements +	//this makes deleting existing edges much faster +	Set<ScanLineEdge>::Element **edgeTreeIterators,*edgeIter; +	edgeTreeIterators = new Set<ScanLineEdge>::Element*[maxnumvertices]; +//	Pair<Set<ScanLineEdge>::Element*,bool> edgeTreeRet; +	for(i = 0; i<numvertices; i++) edgeTreeIterators[i] = NULL; + +	//for each vertex +	for(i=0;i<numvertices;i++) { +		vindex = priority[i]; +		v = &(vertices[vindex]); +		vindex2 = vindex; +		v2 = v; + +		//depending on the vertex type, do the appropriate action +		//comments in the following sections are copied from "Computational Geometry: Algorithms and Applications" +		switch(vertextypes[vindex]) { +			case TRIANGULATOR_VERTEXTYPE_START: +				//Insert ei in T and set helper(ei) to vi. +				newedge.p1 = v->p; +				newedge.p2 = vertices[v->next].p; +				newedge.index = vindex; +				edgeTreeIterators[vindex] = edgeTree.insert(newedge); +				helpers[vindex] = vindex; +				break; + +			case TRIANGULATOR_VERTEXTYPE_END: +				//if helper(ei-1) is a merge vertex +				if(vertextypes[helpers[v->previous]]==TRIANGULATOR_VERTEXTYPE_MERGE) { +					//Insert the diagonal connecting vi to helper(ei-1) in D. +					AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous], +							vertextypes, edgeTreeIterators, &edgeTree, helpers); +				} +				//Delete ei-1 from T +				edgeTree.erase(edgeTreeIterators[v->previous]); +				break; + +			case TRIANGULATOR_VERTEXTYPE_SPLIT: +				//Search in T to find the edge e j directly left of vi. +				newedge.p1 = v->p; +				newedge.p2 = v->p; +				edgeIter = edgeTree.lower_bound(newedge); +				if(edgeIter == edgeTree.front()) { +					error = true; +					break; +				} +				edgeIter=edgeIter->prev(); +				//Insert the diagonal connecting vi to helper(ej) in D. +				AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->get().index], +						vertextypes, edgeTreeIterators, &edgeTree, helpers); +				vindex2 = newnumvertices-2; +				v2 = &(vertices[vindex2]); +				//helper(e j)�vi +				helpers[edgeIter->get().index] = vindex; +				//Insert ei in T and set helper(ei) to vi. +				newedge.p1 = v2->p; +				newedge.p2 = vertices[v2->next].p; +				newedge.index = vindex2; + +				edgeTreeIterators[vindex2] = edgeTree.insert(newedge); +				helpers[vindex2] = vindex2; +				break; + +			case TRIANGULATOR_VERTEXTYPE_MERGE: +				//if helper(ei-1) is a merge vertex +				if(vertextypes[helpers[v->previous]]==TRIANGULATOR_VERTEXTYPE_MERGE) { +					//Insert the diagonal connecting vi to helper(ei-1) in D. +					AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous], +							vertextypes, edgeTreeIterators, &edgeTree, helpers); +					vindex2 = newnumvertices-2; +					v2 = &(vertices[vindex2]); +				} +				//Delete ei-1 from T. +				edgeTree.erase(edgeTreeIterators[v->previous]); +				//Search in T to find the edge e j directly left of vi. +				newedge.p1 = v->p; +				newedge.p2 = v->p; +				edgeIter = edgeTree.lower_bound(newedge); +				if(edgeIter == edgeTree.front()) { +					error = true; +					break; +				} +				edgeIter=edgeIter->prev(); +				//if helper(ej) is a merge vertex +				if(vertextypes[helpers[edgeIter->get().index]]==TRIANGULATOR_VERTEXTYPE_MERGE) { +					//Insert the diagonal connecting vi to helper(e j) in D. +					AddDiagonal(vertices,&newnumvertices,vindex2,helpers[edgeIter->get().index], +							vertextypes, edgeTreeIterators, &edgeTree, helpers); +				} +				//helper(e j)�vi +				helpers[edgeIter->get().index] = vindex2; +				break; + +			case TRIANGULATOR_VERTEXTYPE_REGULAR: +				//if the interior of P lies to the right of vi +				if(Below(v->p,vertices[v->previous].p)) { +					//if helper(ei-1) is a merge vertex +					if(vertextypes[helpers[v->previous]]==TRIANGULATOR_VERTEXTYPE_MERGE) { +						//Insert the diagonal connecting vi to helper(ei-1) in D. +						AddDiagonal(vertices,&newnumvertices,vindex,helpers[v->previous], +								vertextypes, edgeTreeIterators, &edgeTree, helpers); +						vindex2 = newnumvertices-2; +						v2 = &(vertices[vindex2]); +					} +					//Delete ei-1 from T. +					edgeTree.erase(edgeTreeIterators[v->previous]); +					//Insert ei in T and set helper(ei) to vi. +					newedge.p1 = v2->p; +					newedge.p2 = vertices[v2->next].p; +					newedge.index = vindex2; +					edgeTreeIterators[vindex2] = edgeTree.insert(newedge); +					helpers[vindex2] = vindex; +				} else { +					//Search in T to find the edge ej directly left of vi. +					newedge.p1 = v->p; +					newedge.p2 = v->p; +					edgeIter = edgeTree.lower_bound(newedge); +					if(edgeIter == edgeTree.front()) { +						error = true; +						break; +					} +					edgeIter=edgeIter->prev(); +					//if helper(ej) is a merge vertex +					if(vertextypes[helpers[edgeIter->get().index]]==TRIANGULATOR_VERTEXTYPE_MERGE) { +						//Insert the diagonal connecting vi to helper(e j) in D. +						AddDiagonal(vertices,&newnumvertices,vindex,helpers[edgeIter->get().index], +								vertextypes, edgeTreeIterators, &edgeTree, helpers); +					} +					//helper(e j)�vi +					helpers[edgeIter->get().index] = vindex; +				} +				break; +		} + +		if(error) break; +	} + +	char *used = new char[newnumvertices]; +	memset(used,0,newnumvertices*sizeof(char)); + +	if(!error) { +		//return result +		long size; +		TriangulatorPoly mpoly; +		for(i=0;i<newnumvertices;i++) { +			if(used[i]) continue; +			v = &(vertices[i]); +			vnext = &(vertices[v->next]); +			size = 1; +			while(vnext!=v) { +				vnext = &(vertices[vnext->next]); +				size++; +			} +			mpoly.Init(size); +			v = &(vertices[i]); +			mpoly[0] = v->p; +			vnext = &(vertices[v->next]); +			size = 1; +			used[i] = 1; +			used[v->next] = 1; +			while(vnext!=v) { +				mpoly[size] = vnext->p; +				used[vnext->next] = 1; +				vnext = &(vertices[vnext->next]); +				size++; +			} +			monotonePolys->push_back(mpoly); +		} +	} + +	//cleanup +	delete [] vertices; +	delete [] priority; +	delete [] vertextypes; +	delete [] edgeTreeIterators; +	delete [] helpers; +	delete [] used; + +	if(error) { +		return 0; +	} else { +		return 1; +	} +} + +//adds a diagonal to the doubly-connected list of vertices +void TriangulatorPartition::AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2, +					char *vertextypes, Set<ScanLineEdge>::Element **edgeTreeIterators, +					Set<ScanLineEdge> *edgeTree, long *helpers) +{ +	long newindex1,newindex2; + +	newindex1 = *numvertices; +	(*numvertices)++; +	newindex2 = *numvertices; +	(*numvertices)++; + +	vertices[newindex1].p = vertices[index1].p; +	vertices[newindex2].p = vertices[index2].p; + +	vertices[newindex2].next = vertices[index2].next; +	vertices[newindex1].next = vertices[index1].next; + +	vertices[vertices[index2].next].previous = newindex2; +	vertices[vertices[index1].next].previous = newindex1; + +	vertices[index1].next = newindex2; +	vertices[newindex2].previous = index1; + +	vertices[index2].next = newindex1; +	vertices[newindex1].previous = index2; + +	//update all relevant structures +	vertextypes[newindex1] = vertextypes[index1]; +	edgeTreeIterators[newindex1] = edgeTreeIterators[index1]; +	helpers[newindex1] = helpers[index1]; +	if(edgeTreeIterators[newindex1] != NULL) +		edgeTreeIterators[newindex1]->get().index = newindex1; +	vertextypes[newindex2] = vertextypes[index2]; +	edgeTreeIterators[newindex2] = edgeTreeIterators[index2]; +	helpers[newindex2] = helpers[index2]; +	if(edgeTreeIterators[newindex2] != NULL) +		edgeTreeIterators[newindex2]->get().index = newindex2; +} + +bool TriangulatorPartition::Below(Vector2 &p1, Vector2 &p2) { +	if(p1.y < p2.y) return true; +	else if(p1.y == p2.y) { +		if(p1.x < p2.x) return true; +	} +	return false; +} + + + + + +//sorts in the falling order of y values, if y is equal, x is used instead +bool TriangulatorPartition::VertexSorter::operator() (long index1, long index2) const { +	if(vertices[index1].p.y > vertices[index2].p.y) return true; +	else if(vertices[index1].p.y == vertices[index2].p.y) { +		if(vertices[index1].p.x > vertices[index2].p.x) return true; +	} +	return false; +} + +bool TriangulatorPartition::ScanLineEdge::IsConvex(const Vector2& p1, const Vector2& p2, const Vector2& p3) const { +	real_t tmp; +	tmp = (p3.y-p1.y)*(p2.x-p1.x)-(p3.x-p1.x)*(p2.y-p1.y); +	if(tmp>0) return 1; +	else return 0; +} + +bool TriangulatorPartition::ScanLineEdge::operator < (const ScanLineEdge & other) const { +	if(other.p1.y == other.p2.y) { +		if(p1.y == p2.y) { +			if(p1.y < other.p1.y) return true; +			else return false; +		} +		if(IsConvex(p1,p2,other.p1)) return true; +		else return false; +	} else if(p1.y == p2.y) { +		if(IsConvex(other.p1,other.p2,p1)) return false; +		else return true; +	} else if(p1.y < other.p1.y) { +		if(IsConvex(other.p1,other.p2,p1)) return false; +		else return true; +	} else { +		if(IsConvex(p1,p2,other.p1)) return true; +		else return false; +	} +} + +//triangulates monotone polygon +//O(n) time, O(n) space complexity +int TriangulatorPartition::TriangulateMonotone(TriangulatorPoly *inPoly, List<TriangulatorPoly> *triangles) { +	long i,i2,j,topindex,bottomindex,leftindex,rightindex,vindex; +	Vector2 *points; +	long numpoints; +	TriangulatorPoly triangle; + +	numpoints = inPoly->GetNumPoints(); +	points = inPoly->GetPoints(); + +	//trivial calses +	if(numpoints < 3) return 0; +	if(numpoints == 3) { +		triangles->push_back(*inPoly); +	} + +	topindex = 0; bottomindex=0; +	for(i=1;i<numpoints;i++) { +		if(Below(points[i],points[bottomindex])) bottomindex = i; +		if(Below(points[topindex],points[i])) topindex = i; +	} + +	//check if the poly is really monotone +	i = topindex; +	while(i!=bottomindex) { +		i2 = i+1; if(i2>=numpoints) i2 = 0; +		if(!Below(points[i2],points[i])) return 0; +		i = i2; +	} +	i = bottomindex; +	while(i!=topindex) { +		i2 = i+1; if(i2>=numpoints) i2 = 0; +		if(!Below(points[i],points[i2])) return 0; +		i = i2; +	} + +	char *vertextypes = new char[numpoints]; +	long *priority = new long[numpoints]; + +	//merge left and right vertex chains +	priority[0] = topindex; +	vertextypes[topindex] = 0; +	leftindex = topindex+1; if(leftindex>=numpoints) leftindex = 0; +	rightindex = topindex-1; if(rightindex<0) rightindex = numpoints-1; +	for(i=1;i<(numpoints-1);i++) { +		if(leftindex==bottomindex) { +			priority[i] = rightindex; +			rightindex--; if(rightindex<0) rightindex = numpoints-1; +			vertextypes[priority[i]] = -1; +		} else if(rightindex==bottomindex) { +			priority[i] = leftindex; +			leftindex++;  if(leftindex>=numpoints) leftindex = 0; +			vertextypes[priority[i]] = 1; +		} else { +			if(Below(points[leftindex],points[rightindex])) { +				priority[i] = rightindex; +				rightindex--; if(rightindex<0) rightindex = numpoints-1; +				vertextypes[priority[i]] = -1; +			} else { +				priority[i] = leftindex; +				leftindex++;  if(leftindex>=numpoints) leftindex = 0; +				vertextypes[priority[i]] = 1; +			} +		} +	} +	priority[i] = bottomindex; +	vertextypes[bottomindex] = 0; + +	long *stack = new long[numpoints]; +	long stackptr = 0; + +	stack[0] = priority[0]; +	stack[1] = priority[1]; +	stackptr = 2; + +	//for each vertex from top to bottom trim as many triangles as possible +	for(i=2;i<(numpoints-1);i++) { +		vindex = priority[i]; +		if(vertextypes[vindex]!=vertextypes[stack[stackptr-1]]) { +			for(j=0;j<(stackptr-1);j++) { +				if(vertextypes[vindex]==1) { +					triangle.Triangle(points[stack[j+1]],points[stack[j]],points[vindex]); +				} else { +					triangle.Triangle(points[stack[j]],points[stack[j+1]],points[vindex]); +				} +				triangles->push_back(triangle); +			} +			stack[0] = priority[i-1]; +			stack[1] = priority[i]; +			stackptr = 2; +		} else { +			stackptr--; +			while(stackptr>0) { +				if(vertextypes[vindex]==1) { +					if(IsConvex(points[vindex],points[stack[stackptr-1]],points[stack[stackptr]])) { +						triangle.Triangle(points[vindex],points[stack[stackptr-1]],points[stack[stackptr]]); +						triangles->push_back(triangle); +						stackptr--; +					} else { +						break; +					} +				} else { +					if(IsConvex(points[vindex],points[stack[stackptr]],points[stack[stackptr-1]])) { +						triangle.Triangle(points[vindex],points[stack[stackptr]],points[stack[stackptr-1]]); +						triangles->push_back(triangle); +						stackptr--; +					} else { +						break; +					} +				} +			} +			stackptr++; +			stack[stackptr] = vindex; +			stackptr++; +		} +	} +	vindex = priority[i]; +	for(j=0;j<(stackptr-1);j++) { +		if(vertextypes[stack[j+1]]==1) { +			triangle.Triangle(points[stack[j]],points[stack[j+1]],points[vindex]); +		} else { +			triangle.Triangle(points[stack[j+1]],points[stack[j]],points[vindex]); +		} +		triangles->push_back(triangle); +	} + +	delete [] priority; +	delete [] vertextypes; +	delete [] stack; + +	return 1; +} + +int TriangulatorPartition::Triangulate_MONO(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles) { +	List<TriangulatorPoly> monotone; +	List<TriangulatorPoly>::Element* iter; + +	if(!MonotonePartition(inpolys,&monotone)) return 0; +	for(iter = monotone.front(); iter;iter=iter->next()) { +		if(!TriangulateMonotone(&(iter->get()),triangles)) return 0; +	} +	return 1; +} + +int TriangulatorPartition::Triangulate_MONO(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles) { +	List<TriangulatorPoly> polys; +	polys.push_back(*poly); + +	return Triangulate_MONO(&polys, triangles); +} diff --git a/core/math/triangulator.h b/core/math/triangulator.h new file mode 100644 index 0000000000..b6dd7e8236 --- /dev/null +++ b/core/math/triangulator.h @@ -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 diff --git a/core/os/input.cpp b/core/os/input.cpp index a827e75896..5d4b3a834d 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -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 ); diff --git a/core/resource.cpp b/core/resource.cpp index 987bd772b0..560ca9a1f2 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -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); diff --git a/core/set.h b/core/set.h index d87f635577..95f38d7108 100644 --- a/core/set.h +++ b/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 { diff --git a/core/ustring.cpp b/core/ustring.cpp index 581cc29440..476ab3f936 100644 --- a/core/ustring.cpp +++ b/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; +} diff --git a/core/ustring.h b/core/ustring.h index e1d6761742..af5ffb7c35 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -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; diff --git a/core/variant.cpp b/core/variant.cpp index 2f0eca9e91..667a7d8648 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -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) { + +	r_value=Variant(); +} -String Variant::get_construct_string() const { + +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; diff --git a/core/variant.h b/core/variant.h index 47fc3f43ac..d5d4792422 100644 --- a/core/variant.h +++ b/core/variant.h @@ -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); diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 3f2800494d..50a60390e5 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -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()); diff --git a/core/variant_construct_string.cpp b/core/variant_construct_string.cpp new file mode 100644 index 0000000000..0308fd3180 --- /dev/null +++ b/core/variant_construct_string.cpp @@ -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); +} + + diff --git a/core/variant_op.cpp b/core/variant_op.cpp index ec43b1275c..d6129e150c 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -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: { diff --git a/demos/2d/hexamap/.fscache b/demos/2d/hexamap/.fscache deleted file mode 100644 index 60aa69b645..0000000000 --- a/demos/2d/hexamap/.fscache +++ /dev/null @@ -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:: diff --git a/demos/2d/navpoly/agent.png b/demos/2d/navpoly/agent.png Binary files differnew file mode 100644 index 0000000000..23e396c478 --- /dev/null +++ b/demos/2d/navpoly/agent.png diff --git a/demos/2d/navpoly/engine.cfg b/demos/2d/navpoly/engine.cfg new file mode 100644 index 0000000000..51eefd7b77 --- /dev/null +++ b/demos/2d/navpoly/engine.cfg @@ -0,0 +1,4 @@ +[application] + +name="Navigation Polygon (2D)" +main_scene="res://navigation.scn" diff --git a/demos/2d/navpoly/navigation.gd b/demos/2d/navpoly/navigation.gd new file mode 100644 index 0000000000..9c3dc2921d --- /dev/null +++ b/demos/2d/navpoly/navigation.gd @@ -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 + + diff --git a/demos/2d/navpoly/navigation.scn b/demos/2d/navpoly/navigation.scn Binary files differnew file mode 100644 index 0000000000..1bb7de391b --- /dev/null +++ b/demos/2d/navpoly/navigation.scn diff --git a/demos/2d/navpoly/navigation2.scn b/demos/2d/navpoly/navigation2.scn Binary files differnew file mode 100644 index 0000000000..224aed73f5 --- /dev/null +++ b/demos/2d/navpoly/navigation2.scn diff --git a/demos/2d/navpoly/path.png b/demos/2d/navpoly/path.png Binary files differnew file mode 100644 index 0000000000..52a6d507c3 --- /dev/null +++ b/demos/2d/navpoly/path.png diff --git a/demos/2d/platformer/stage.xml b/demos/2d/platformer/stage.xml index e2943d8fcf..35517f747d 100644 --- a/demos/2d/platformer/stage.xml +++ b/demos/2d/platformer/stage.xml @@ -1,17 +1,17 @@  <?xml version="1.0" encoding="UTF-8" ?>  <resource_file type="PackedScene" subresource_count="9" version="1.0" version_name="Godot Engine v1.0.stable.custom_build"> -	<ext_resource path="res://tileset.xml" type="TileSet"></ext_resource>  	<ext_resource path="res://music.ogg" type="AudioStream"></ext_resource> -	<ext_resource path="res://parallax_bg.xml" type="PackedScene"></ext_resource> +	<ext_resource path="res://tileset.xml" type="TileSet"></ext_resource> +	<ext_resource path="res://coin.xml" type="PackedScene"></ext_resource> +	<ext_resource path="res://seesaw.xml" type="PackedScene"></ext_resource>  	<ext_resource path="res://player.xml" type="PackedScene"></ext_resource>  	<ext_resource path="res://moving_platform.xml" type="PackedScene"></ext_resource>  	<ext_resource path="res://enemy.xml" type="PackedScene"></ext_resource> -	<ext_resource path="res://seesaw.xml" type="PackedScene"></ext_resource> -	<ext_resource path="res://coin.xml" type="PackedScene"></ext_resource> +	<ext_resource path="res://parallax_bg.xml" type="PackedScene"></ext_resource>  	<main_resource>  		<dictionary name="_bundled" shared="false">  			<string> "names" </string> -			<string_array  len="125"> +			<string_array  len="127">  				<string> "stage" </string>  				<string> "Node" </string>  				<string> "_import_path" </string> @@ -21,16 +21,18 @@  				<string> "visibility/visible" </string>  				<string> "visibility/opacity" </string>  				<string> "visibility/self_opacity" </string> -				<string> "visibility/behind_parent" </string>  				<string> "transform/pos" </string>  				<string> "transform/rot" </string>  				<string> "transform/scale" </string> +				<string> "z/z" </string> +				<string> "z/relative" </string>  				<string> "mode" </string>  				<string> "tile_set" </string>  				<string> "cell/size" </string>  				<string> "cell/quadrant_size" </string>  				<string> "cell/custom_transform" </string>  				<string> "cell/half_offset" </string> +				<string> "collision/body_mode" </string>  				<string> "collision/friction" </string>  				<string> "collision/bounce" </string>  				<string> "collision/layers" </string> @@ -167,11 +169,11 @@  							<string> "pixel_snap" </string>  							<bool> False </bool>  							<string> "zoom" </string> -							<real> 0.54036 </real> +							<real> 0.814506 </real>  							<string> "use_snap" </string>  							<bool> False </bool>  							<string> "ofs" </string> -							<vector2> -177.089, 415.221 </vector2> +							<vector2> -121.031, 464.121 </vector2>  							<string> "snap" </string>  							<int> 10 </int>  						</dictionary> @@ -276,22 +278,21 @@  						<int> 0 </int>  					</dictionary>  					<string> "__editor_plugin_screen__" </string> -					<string> "Script" </string> +					<string> "2D" </string>  				</dictionary>  				<bool> True </bool>  				<real> 1 </real> -				<bool> False </bool>  				<vector2> 0, 0 </vector2>  				<real> 0 </real>  				<vector2> 1, 1 </vector2>  				<int> 0 </int>  				<resource  resource_type="TileSet" path="res://tileset.xml">  </resource>  				<vector2> 64, 64 </vector2> -				<int> 16 </int> +				<int> 8 </int>  				<matrix32> 1, 0, 0, 1, 0, 0 </matrix32>  				<int> 2 </int>  				<int> 1 </int> -				<int_array  len="1998"> 					0, 2, 70, 536870914, 71, 10, 72, 10, 73, 10, 74, 10, 75, 10, 76, 10, 77, 10, 78, 10, 65536, 2, 65606, 536870914, 65607, 10, 65608, 10, 65609, 10, 65610, 10, 65611, 10, 65612, 10, 65613, 10, 65614, 10, 131072, 2, 131142, 536870914, 131143, 10, 131144, 10, 131145, 10, 131146, 10, 131147, 10, 131148, 10, 131149, 10, 131150, 10, 196608, 2, 196626, 9, 196678, 536870914, 196679, 10, 196680, 10, 196681, 10, 196682, 10, 196683, 10, 196684, 10, 196685, 10, 196686, 10, 262144, 2, 262162, 8, 262214, 536870914, 262215, 10, 262216, 10, 262217, 10, 262218, 10, 262219, 10, 262220, 10, 262221, 10, 262222, 10, 327680, 2, 327697, 536870921, 327698, 7, 327733, 9, 327750, 536870914, 327751, 10, 327752, 10, 327753, 10, 327754, 10, 327755, 10, 327756, 10, 327757, 10, 327758, 10, 393216, 2, 393233, 536870920, 393234, 7, 393257, 9, 393269, 7, 393286, 536870914, 393287, 10, 393288, 10, 393289, 10, 393290, 10, 393291, 10, 393292, 10, 393293, 10, 393294, 10, 458752, 2, 458769, 7, 458770, 8, 458790, 9, 458793, 8, 458805, 8, 458822, 536870914, 458823, 10, 458824, 10, 458825, 10, 458826, 10, 458827, 10, 458828, 10, 458829, 10, 458830, 10, 524288, 4, 524289, 1, 524304, 536870913, 524305, 536870918, 524306, 6, 524307, 5, 524308, 1, 524326, 8, 524329, 7, 524341, 7, 524358, 536870914, 524359, 10, 524360, 10, 524361, 10, 524362, 10, 524363, 10, 524364, 10, 524365, 10, 524366, 10, 589824, 10, 589825, 13, 589840, 536870914, 589841, 10, 589842, 10, 589843, 10, 589844, 2, 589862, 7, 589865, 7, 589876, 536870913, 589877, 6, 589878, 1, 589894, 536870914, 589895, 10, 589896, 10, 589897, 10, 589898, 10, 589899, 10, 589900, 10, 589901, 10, 589902, 10, 655360, 2, 655376, 536870914, 655377, 10, 655378, 10, 655379, 10, 655380, 2, 655398, 7, 655401, 8, 655412, 536870925, 655413, 11, 655414, 13, 655430, 536870914, 655431, 10, 655432, 10, 655433, 10, 655434, 10, 655435, 10, 655436, 10, 655437, 10, 655438, 10, 720896, 2, 720912, 536870914, 720913, 10, 720914, 10, 720915, 10, 720916, 2, 720934, 8, 720937, 7, 720958, 536870913, 720959, 5, 720960, 536870917, 720961, 5, 720962, 5, 720963, 536870917, 720964, 5, 720965, 0, 720966, 536870916, 720967, 10, 720968, 10, 720969, 10, 720970, 10, 720971, 10, 720972, 10, 720973, 10, 720974, 10, 786432, 2, 786437, 9, 786448, 536870914, 786449, 10, 786450, 10, 786451, 10, 786452, 2, 786464, 536870913, 786465, 1, 786470, 7, 786473, 7, 786474, 536870924, 786475, 1, 786494, 536870914, 786495, 10, 786496, 10, 786497, 10, 786498, 10, 786499, 10, 786500, 10, 786501, 10, 786502, 10, 786503, 10, 786504, 10, 786505, 10, 786506, 10, 786507, 10, 786508, 10, 786509, 10, 851968, 2, 851973, 7, 851984, 536870914, 851985, 10, 851986, 10, 851987, 10, 851988, 2, 851996, 536870913, 851997, 1, 852000, 536870914, 852001, 3, 852006, 7, 852009, 536870913, 852011, 2, 852030, 536870914, 852031, 10, 852032, 10, 852033, 10, 852034, 10, 852035, 10, 852036, 10, 852037, 10, 852038, 10, 852039, 10, 852040, 10, 852041, 10, 852042, 10, 852043, 10, 852044, 10, 852045, 10, 917504, 2, 917506, 9, 917509, 7, 917512, 536870921, 917520, 536870925, 917521, 11, 917522, 11, 917523, 11, 917524, 13, 917532, 536870925, 917533, 13, 917536, 536870914, 917537, 4, 917538, 1, 917540, 536870913, 917541, 0, 917542, 1, 917545, 536870914, 917546, 10, 917547, 4, 917548, 1, 917566, 536870914, 917567, 10, 917568, 10, 917569, 10, 917570, 10, 917571, 10, 917572, 10, 917573, 10, 917574, 10, 917575, 10, 917576, 10, 917577, 10, 917578, 10, 917579, 10, 917580, 10, 917581, 10, 983040, 2, 983042, 7, 983045, 7, 983048, 536870920, 983050, 536870913, 983051, 1, 983064, 536870913, 983065, 1, 983072, 536870914, 983073, 10, 983074, 4, 983075, 0, 983076, 536870916, 983077, 10, 983078, 4, 983079, 536870912, 983080, 536870912, 983081, 536870916, 983082, 10, 983083, 10, 983084, 2, 983095, 9, 983102, 536870914, 983103, 10, 983104, 10, 983105, 10, 983106, 10, 983107, 10, 983108, 10, 983109, 10, 983110, 10, 983111, 10, 983112, 10, 983113, 10, 983114, 10, 983115, 10, 983116, 10, 983117, 10, 1048576, 2, 1048578, 8, 1048581, 8, 1048584, 536870919, 1048586, 536870925, 1048587, 13, 1048600, 536870925, 1048601, 13, 1048604, 9, 1048608, 536870925, 1048609, 536870923, 1048610, 536870923, 1048611, 536870923, 1048612, 10, 1048613, 10, 1048614, 10, 1048615, 10, 1048616, 10, 1048617, 10, 1048618, 10, 1048619, 10, 1048620, 4, 1048621, 1, 1048630, 536870921, 1048631, 8, 1048638, 536870914, 1048639, 10, 1048640, 10, 1048641, 10, 1048642, 10, 1048643, 10, 1048644, 10, 1048645, 10, 1048646, 10, 1048647, 10, 1048648, 10, 1048649, 10, 1048650, 10, 1048651, 10, 1048652, 10, 1048653, 10, 1114112, 4, 1114113, 0, 1114114, 6, 1114115, 0, 1114116, 0, 1114117, 6, 1114118, 1, 1114120, 536870920, 1114128, 536870913, 1114129, 5, 1114130, 536870917, 1114131, 5, 1114132, 0, 1114133, 1, 1114140, 7, 1114141, 536870921, 1114148, 536870914, 1114149, 10, 1114150, 10, 1114151, 10, 1114152, 10, 1114153, 10, 1114154, 10, 1114155, 10, 1114156, 10, 1114157, 2, 1114166, 536870920, 1114167, 8, 1114174, 536870914, 1114175, 10, 1114176, 10, 1114177, 10, 1114178, 10, 1114179, 10, 1114180, 10, 1114181, 10, 1114182, 10, 1114183, 10, 1114184, 10, 1114185, 10, 1114186, 10, 1114187, 10, 1114188, 10, 1179648, 10, 1179649, 10, 1179650, 10, 1179651, 10, 1179652, 10, 1179653, 10, 1179654, 2, 1179656, 536870919, 1179663, 536870915, 1179665, 10, 1179666, 10, 1179667, 10, 1179668, 10, 1179669, 4, 1179670, 12, 1179675, 9, 1179676, 8, 1179677, 8, 1179684, 536870914, 1179685, 10, 1179686, 10, 1179687, 10, 1179688, 10, 1179689, 10, 1179690, 10, 1179691, 10, 1179692, 10, 1179693, 4, 1179694, 1, 1179701, 9, 1179702, 536870919, 1179703, 7, 1179710, 536870914, 1179711, 10, 1179712, 10, 1179713, 10, 1179714, 10, 1179715, 10, 1179716, 10, 1179717, 10, 1179718, 10, 1179719, 10, 1179720, 10, 1179721, 10, 1179722, 10, 1245184, 10, 1245185, 10, 1245186, 10, 1245187, 10, 1245188, 10, 1245189, 10, 1245190, 2, 1245192, 536870919, 1245199, 536870913, 1245200, 536870916, 1245201, 10, 1245202, 10, 1245203, 10, 1245204, 10, 1245205, 10, 1245207, 1, 1245211, 7, 1245212, 7, 1245213, 536870920, 1245220, 536870914, 1245221, 10, 1245222, 10, 1245223, 10, 1245224, 10, 1245225, 10, 1245226, 10, 1245227, 10, 1245228, 10, 1245229, 10, 1245230, 2, 1245237, 8, 1245238, 536870919, 1245239, 8, 1245240, 536870921, 1245246, 536870914, 1245247, 10, 1245248, 10, 1245249, 10, 1245250, 10, 1245251, 10, 1245252, 10, 1245253, 10, 1245254, 10, 1245255, 10, 1245256, 10, 1245257, 10, 1245258, 10, 1310720, 10, 1310721, 10, 1310722, 10, 1310723, 10, 1310724, 10, 1310725, 10, 1310726, 2, 1310728, 536870920, 1310730, 536870913, 1310731, 1, 1310734, 536870913, 1310735, 536870916, 1310736, 10, 1310737, 10, 1310738, 10, 1310739, 10, 1310740, 10, 1310741, 10, 1310742, 10, 1310743, 4, 1310744, 1, 1310747, 8, 1310748, 7, 1310749, 536870919, 1310756, 536870914, 1310757, 10, 1310758, 10, 1310759, 10, 1310760, 10, 1310761, 10, 1310762, 10, 1310763, 10, 1310764, 10, 1310765, 10, 1310766, 4, 1310767, 5, 1310768, 12, 1310773, 7, 1310774, 536870919, 1310775, 7, 1310776, 536870919, 1310782, 536870914, 1310783, 10, 1310784, 10, 1310785, 10, 1310786, 10, 1310787, 10, 1310788, 10, 1310789, 10, 1310790, 10, 1310791, 10, 1310792, 10, 1310793, 10, 1376256, 10, 1376257, 10, 1376258, 10, 1376259, 10, 1376260, 10, 1376261, 10, 1376262, 4, 1376263, 0, 1376264, 536870918, 1376265, 0, 1376266, 536870916, 1376267, 4, 1376268, 0, 1376269, 0, 1376270, 536870916, 1376271, 10, 1376272, 10, 1376273, 10, 1376274, 10, 1376275, 10, 1376276, 10, 1376277, 10, 1376278, 10, 1376279, 10, 1376280, 4, 1376281, 12, 1376283, 8, 1376284, 8, 1376285, 536870920, 1376287, 536870924, 1376288, 0, 1376289, 5, 1376290, 536870917, 1376291, 0, 1376292, 536870916, 1376293, 10, 1376294, 10, 1376295, 10, 1376296, 10, 1376297, 10, 1376298, 10, 1376299, 10, 1376300, 10, 1376301, 10, 1376302, 10, 1376303, 10, 1376305, 12, 1376309, 7, 1376310, 536870920, 1376311, 7, 1376312, 536870920, 1376318, 536870914, 1376319, 10, 1376320, 10, 1376321, 10, 1376322, 10, 1376323, 10, 1376324, 10, 1376325, 10, 1376326, 10, 1376327, 10, 1376328, 10, 1441792, 10, 1441793, 10, 1441794, 10, 1441795, 10, 1441796, 10, 1441797, 10, 1441798, 10, 1441799, 10, 1441800, 10, 1441801, 10, 1441802, 10, 1441803, 10, 1441804, 10, 1441805, 10, 1441806, 10, 1441807, 10, 1441808, 10, 1441809, 10, 1441810, 10, 1441811, 10, 1441812, 10, 1441813, 10, 1441814, 10, 1441815, 10, 1441816, 10, 1441818, 0, 1441819, 6, 1441820, 6, 1441821, 536870918, 1441822, 5, 1441824, 10, 1441825, 10, 1441826, 10, 1441827, 10, 1441828, 10, 1441829, 10, 1441830, 10, 1441831, 10, 1441832, 10, 1441833, 10, 1441834, 10, 1441835, 10, 1441836, 10, 1441837, 10, 1441838, 10, 1441839, 10, 1441840, 10, 1441842, 0, 1441843, 0, 1441844, 0, 1441845, 6, 1441846, 536870918, 1441847, 6, 1441848, 536870918, 1441849, 0, 1441850, 5, 1441851, 536870917, 1441852, 5, 1441853, 0, 1441854, 536870916, 1441855, 10, 1441856, 10, 1441857, 10, 1441858, 10, 1441859, 10, 1441860, 10, 1441861, 10, 1441862, 10, 1441863, 10, 1507328, 10, 1507329, 10, 1507330, 10, 1507331, 10, 1507332, 10, 1507333, 10, 1507334, 10, 1507335, 10, 1507336, 10, 1507337, 10, 1507338, 10, 1507339, 10, 1507340, 10, 1507341, 10, 1507342, 10, 1507343, 10, 1507344, 10, 1507345, 10, 1507346, 10, 1507347, 10, 1507348, 10, 1507349, 10, 1507350, 10, 1507351, 10, 1507352, 10, 1507353, 10, 1507354, 10, 1507355, 10, 1507356, 10, 1507357, 10, 1507358, 10, 1507359, 10, 1507360, 10, 1507361, 10, 1507362, 10, 1507363, 10, 1507364, 10, 1507365, 10, 1507366, 10, 1507367, 10, 1507368, 10, 1507369, 10, 1507370, 10, 1507371, 10, 1507372, 10, 1507373, 10, 1507374, 10, 1507375, 10, 1507376, 10, 1507377, 10, 1507378, 10, 1507379, 10, 1507380, 10, 1507381, 10, 1507382, 10, 1507383, 10, 1507384, 10, 1507385, 10, 1507386, 10, 1507387, 10, 1507388, 10, 1507389, 10, 1507390, 10, 1507391, 10, 1507392, 10, 1507393, 10, 1507394, 10, 1507395, 10, 1507396, 10, 1507397, 10, 1507398, 10, 1507399, 10, 1572864, 10, 1572865, 10, 1572866, 10, 1572867, 10, 1572868, 10, 1572869, 10, 1572870, 10, 1572871, 10, 1572872, 10, 1572873, 10, 1572874, 10, 1572875, 10, 1572876, 10, 1572877, 10, 1572878, 10, 1572879, 10, 1572880, 10, 1572881, 10, 1572882, 10, 1572883, 10, 1572884, 10, 1572885, 10, 1572886, 10, 1572887, 10, 1572888, 10, 1572889, 10, 1572890, 10, 1572891, 10, 1572892, 10, 1572893, 10, 1572894, 10, 1572895, 10, 1572896, 10, 1572897, 10, 1572898, 10, 1572899, 10, 1572900, 10, 1572901, 10, 1572902, 10, 1572903, 10, 1572904, 10, 1572905, 10, 1572906, 10, 1572907, 10, 1572908, 10, 1572909, 10, 1572910, 10, 1572911, 10, 1572912, 10, 1572913, 10, 1572914, 10, 1572915, 10, 1572916, 10, 1572917, 10, 1572918, 10, 1572919, 10, 1572920, 10, 1572921, 10, 1572922, 10, 1572923, 10, 1572924, 10, 1572925, 10, 1572926, 10, 1572927, 10, 1572928, 10, 1572929, 10, 1572930, 10, 1572931, 10, 1572932, 10, 1572933, 10, 1572934, 10, 1572935, 10, 1638400, 10, 1638401, 10, 1638402, 10, 1638403, 10, 1638404, 10, 1638405, 10, 1638406, 10, 1638407, 10, 1638408, 10, 1638409, 10, 1638410, 10, 1638411, 10, 1638412, 10, 1638413, 10, 1638414, 10, 1638415, 10, 1638416, 10, 1638417, 10, 1638418, 10, 1638419, 10, 1638420, 10, 1638421, 10, 1638422, 10, 1638423, 10, 1638424, 10, 1638425, 10, 1638426, 10, 1638427, 10, 1638428, 10, 1638429, 10, 1638430, 10, 1638431, 10, 1638432, 10, 1638433, 10, 1638434, 10, 1638435, 10, 1638436, 10, 1638437, 10, 1638438, 10, 1638439, 10, 1638440, 10, 1638441, 10, 1638442, 10, 1638443, 10, 1638444, 10, 1638445, 10, 1638446, 10, 1638447, 10, 1638448, 10, 1638449, 10, 1638450, 10, 1638451, 10, 1638452, 10, 1638453, 10, 1638454, 10, 1638455, 10, 1638456, 10, 1638457, 10, 1638458, 10, 1638459, 10, 1638460, 10, 1638461, 10, 1638462, 10, 1638463, 10, 1638464, 10, 1638465, 10, 1638466, 10, 1638467, 10, 1638468, 10, 1638469, 10, 1638470, 10, 1638471, 10, 1703952, 10, 1703953, 10, 1703954, 10, 1703955, 10, 1703956, 10, 1703957, 10, 1703958, 10, 1703959, 10, 1703960, 10, 1703961, 10, 1703962, 10, 1703963, 10, 1703964, 10, 1703965, 10, 1703966, 10, 1703967, 10, 1703968, 10, 1703969, 10, 1703970, 10, 1703971, 10, 1703972, 10, 1703973, 10, 1703974, 10, 1703975, 10, 1703976, 10, 1703977, 10, 1703978, 10, 1703979, 10, 1703980, 10, 1703981, 10, 1703982, 10, 1703983, 10, 1703984, 10, 1703985, 10, 1703986, 10, 1703987, 10, 1703988, 10, 1703989, 10, 1703990, 10, 1703991, 10, 1703992, 10, 1703993, 10, 1703994, 10, 1703995, 10, 1703996, 10, 1703997, 10, 1703998, 10, 1703999, 10, 1704000, 10, 1704001, 10, 1704002, 10, 1704003, 10, 1704004, 10, 1704005, 10, 1704006, 10, 1704007, 10, 1769488, 10, 1769489, 10, 1769490, 10, 1769491, 10, 1769492, 10, 1769493, 10, 1769494, 10, 1769495, 10, 1769496, 10, 1769497, 10, 1769498, 10, 1769499, 10, 1769500, 10, 1769501, 10, 1769502, 10, 1769503, 10, 1769504, 10, 1769505, 10, 1769506, 10, 1769507, 10, 1769508, 10, 1769509, 10, 1769510, 10, 1769511, 10, 1769512, 10, 1769513, 10, 1769514, 10, 1769515, 10, 1769516, 10, 1769517, 10, 1769518, 10, 1769519, 10, 1769520, 10, 1769521, 10, 1769522, 10, 1769523, 10, 1769524, 10, 1769525, 10, 1769526, 10, 1769527, 10, 1769528, 10, 1769529, 10, 1769530, 10, 1769531, 10, 1769532, 10, 1769533, 10, 1769534, 10, 1769535, 10, 1769536, 10, 1769537, 10, 1769538, 10, 1769539, 10, 1769540, 10, 1769541, 10 </int_array> +				<int_array  len="1998"> 					0, 2, 70, 536870914, 71, 10, 72, 10, 73, 10, 74, 10, 75, 10, 76, 10, 77, 10, 78, 10, 65536, 2, 65606, 536870914, 65607, 10, 65608, 10, 65609, 10, 65610, 10, 65611, 10, 65612, 10, 65613, 10, 65614, 10, 131072, 2, 131142, 536870914, 131143, 10, 131144, 10, 131145, 10, 131146, 10, 131147, 10, 131148, 10, 131149, 10, 131150, 10, 196608, 2, 196626, 9, 196678, 536870914, 196679, 10, 196680, 10, 196681, 10, 196682, 10, 196683, 10, 196684, 10, 196685, 10, 196686, 10, 262144, 2, 262162, 8, 262214, 536870914, 262215, 10, 262216, 10, 262217, 10, 262218, 10, 262219, 10, 262220, 10, 262221, 10, 262222, 10, 327680, 2, 327697, 536870921, 327698, 7, 327733, 9, 327750, 536870914, 327751, 10, 327752, 10, 327753, 10, 327754, 10, 327755, 10, 327756, 10, 327757, 10, 327758, 10, 393216, 2, 393233, 536870920, 393234, 7, 393257, 9, 393269, 7, 393286, 536870914, 393287, 10, 393288, 10, 393289, 10, 393290, 10, 393291, 10, 393292, 10, 393293, 10, 393294, 10, 458752, 2, 458769, 7, 458770, 8, 458790, 9, 458793, 8, 458805, 8, 458822, 536870914, 458823, 10, 458824, 10, 458825, 10, 458826, 10, 458827, 10, 458828, 10, 458829, 10, 458830, 10, 524288, 4, 524289, 1, 524304, 536870913, 524305, 536870918, 524306, 6, 524307, 5, 524308, 1, 524326, 8, 524329, 7, 524341, 7, 524358, 536870914, 524359, 10, 524360, 10, 524361, 10, 524362, 10, 524363, 10, 524364, 10, 524365, 10, 524366, 10, 589824, 10, 589825, 13, 589840, 536870914, 589841, 10, 589842, 10, 589843, 10, 589844, 2, 589862, 7, 589865, 7, 589876, 536870913, 589877, 6, 589878, 1, 589894, 536870914, 589895, 10, 589896, 10, 589897, 10, 589898, 10, 589899, 10, 589900, 10, 589901, 10, 589902, 10, 655360, 2, 655376, 536870914, 655377, 10, 655378, 10, 655379, 10, 655380, 2, 655398, 7, 655401, 8, 655412, 536870925, 655413, 11, 655414, 13, 655430, 536870914, 655431, 10, 655432, 10, 655433, 10, 655434, 10, 655435, 10, 655436, 10, 655437, 10, 655438, 10, 720896, 2, 720912, 536870914, 720913, 10, 720914, 10, 720915, 10, 720916, 2, 720934, 8, 720937, 7, 720958, 536870913, 720959, 5, 720960, 536870917, 720961, 5, 720962, 5, 720963, 536870917, 720964, 5, 720965, 0, 720966, 536870916, 720967, 10, 720968, 10, 720969, 10, 720970, 10, 720971, 10, 720972, 10, 720973, 10, 720974, 10, 786432, 2, 786437, 9, 786448, 536870914, 786449, 10, 786450, 10, 786451, 10, 786452, 2, 786464, 536870913, 786465, 1, 786470, 7, 786473, 7, 786474, 536870924, 786475, 1, 786494, 536870914, 786495, 10, 786496, 10, 786497, 10, 786498, 10, 786499, 10, 786500, 10, 786501, 10, 786502, 10, 786503, 10, 786504, 10, 786505, 10, 786506, 10, 786507, 10, 786508, 10, 786509, 10, 851968, 2, 851973, 7, 851984, 536870914, 851985, 10, 851986, 10, 851987, 10, 851988, 2, 851996, 536870913, 851997, 1, 852000, 536870914, 852001, 3, 852006, 7, 852009, 536870913, 852011, 2, 852030, 536870914, 852031, 10, 852032, 10, 852033, 10, 852034, 10, 852035, 10, 852036, 10, 852037, 10, 852038, 10, 852039, 10, 852040, 10, 852041, 10, 852042, 10, 852043, 10, 852044, 10, 852045, 10, 917504, 2, 917506, 9, 917509, 7, 917512, 536870921, 917520, 536870925, 917521, 11, 917522, 11, 917523, 11, 917524, 13, 917532, 536870925, 917533, 13, 917536, 536870914, 917537, 4, 917538, 1, 917540, 536870913, 917541, 0, 917542, 1, 917545, 536870914, 917546, 10, 917547, 4, 917548, 1, 917566, 536870914, 917567, 10, 917568, 10, 917569, 10, 917570, 10, 917571, 10, 917572, 10, 917573, 10, 917574, 10, 917575, 10, 917576, 10, 917577, 10, 917578, 10, 917579, 10, 917580, 10, 917581, 10, 983040, 2, 983042, 7, 983045, 7, 983048, 536870920, 983050, 536870913, 983051, 1, 983064, 536870913, 983065, 1, 983072, 536870914, 983073, 10, 983074, 4, 983075, 0, 983076, 536870916, 983077, 10, 983078, 4, 983079, 536870912, 983080, 536870912, 983081, 536870916, 983082, 10, 983083, 10, 983084, 2, 983095, 9, 983102, 536870914, 983103, 10, 983104, 10, 983105, 10, 983106, 10, 983107, 10, 983108, 10, 983109, 10, 983110, 10, 983111, 10, 983112, 10, 983113, 10, 983114, 10, 983115, 10, 983116, 10, 983117, 10, 1048576, 2, 1048578, 8, 1048581, 8, 1048584, 536870919, 1048586, 536870925, 1048587, 13, 1048600, 536870925, 1048601, 13, 1048604, 9, 1048608, 536870925, 1048609, 536870923, 1048610, 536870923, 1048611, 536870923, 1048612, 10, 1048613, 10, 1048614, 10, 1048615, 10, 1048616, 10, 1048617, 10, 1048618, 10, 1048619, 10, 1048620, 4, 1048621, 1, 1048630, 536870921, 1048631, 8, 1048638, 536870914, 1048639, 10, 1048640, 10, 1048641, 10, 1048642, 10, 1048643, 10, 1048644, 10, 1048645, 10, 1048646, 10, 1048647, 10, 1048648, 10, 1048649, 10, 1048650, 10, 1048651, 10, 1048652, 10, 1048653, 10, 1114112, 4, 1114113, 0, 1114114, 6, 1114115, 0, 1114116, 0, 1114117, 6, 1114118, 1, 1114120, 536870920, 1114128, 536870913, 1114129, 5, 1114130, 536870917, 1114131, 5, 1114132, 0, 1114133, 1, 1114140, 7, 1114141, 536870921, 1114148, 536870914, 1114149, 10, 1114150, 10, 1114151, 10, 1114152, 10, 1114153, 10, 1114154, 10, 1114155, 10, 1114156, 10, 1114157, 2, 1114166, 536870920, 1114167, 8, 1114174, 536870914, 1114175, 10, 1114176, 10, 1114177, 10, 1114178, 10, 1114179, 10, 1114180, 10, 1114181, 10, 1114182, 10, 1114183, 10, 1114184, 10, 1114185, 10, 1114186, 10, 1114187, 10, 1114188, 10, 1179648, 10, 1179649, 10, 1179650, 10, 1179651, 10, 1179652, 10, 1179653, 10, 1179654, 2, 1179656, 536870919, 1179663, 536870915, 1179665, 10, 1179666, 10, 1179667, 10, 1179668, 10, 1179669, 4, 1179670, 12, 1179675, 9, 1179676, 8, 1179677, 8, 1179684, 536870914, 1179685, 10, 1179686, 10, 1179687, 10, 1179688, 10, 1179689, 10, 1179690, 10, 1179691, 10, 1179692, 10, 1179693, 4, 1179694, 1, 1179701, 9, 1179702, 536870919, 1179703, 7, 1179710, 536870914, 1179711, 10, 1179712, 10, 1179713, 10, 1179714, 10, 1179715, 10, 1179716, 10, 1179717, 10, 1179718, 10, 1179719, 10, 1179720, 10, 1179721, 10, 1179722, 10, 1245184, 10, 1245185, 10, 1245186, 10, 1245187, 10, 1245188, 10, 1245189, 10, 1245190, 2, 1245192, 536870919, 1245199, 536870913, 1245200, 536870916, 1245201, 10, 1245202, 10, 1245203, 10, 1245204, 10, 1245205, 10, 1245207, 1, 1245211, 7, 1245212, 7, 1245213, 536870920, 1245220, 536870914, 1245221, 10, 1245222, 10, 1245223, 10, 1245224, 10, 1245225, 10, 1245226, 10, 1245227, 10, 1245228, 10, 1245229, 10, 1245230, 2, 1245237, 8, 1245238, 536870919, 1245239, 8, 1245240, 536870921, 1245246, 536870914, 1245247, 10, 1245248, 10, 1245249, 10, 1245250, 10, 1245251, 10, 1245252, 10, 1245253, 10, 1245254, 10, 1245255, 10, 1245256, 10, 1245257, 10, 1245258, 10, 1310720, 10, 1310721, 10, 1310722, 10, 1310723, 10, 1310724, 10, 1310725, 10, 1310726, 2, 1310728, 536870920, 1310730, 536870913, 1310731, 1, 1310734, 536870913, 1310735, 536870916, 1310736, 10, 1310737, 10, 1310738, 10, 1310739, 10, 1310740, 10, 1310741, 10, 1310742, 10, 1310743, 4, 1310744, 1, 1310747, 8, 1310748, 7, 1310749, 536870919, 1310756, 536870914, 1310757, 10, 1310758, 10, 1310759, 10, 1310760, 10, 1310761, 10, 1310762, 10, 1310763, 10, 1310764, 10, 1310765, 10, 1310766, 4, 1310767, 5, 1310768, 12, 1310773, 7, 1310774, 536870919, 1310775, 7, 1310776, 536870919, 1310782, 536870914, 1310783, 10, 1310784, 10, 1310785, 10, 1310786, 10, 1310787, 10, 1310788, 10, 1310789, 10, 1310790, 10, 1310791, 10, 1310792, 10, 1310793, 10, 1376256, 10, 1376257, 10, 1376258, 10, 1376259, 10, 1376260, 10, 1376261, 10, 1376262, 4, 1376263, 0, 1376264, 0, 1376265, 0, 1376266, 536870916, 1376267, 4, 1376268, 0, 1376269, 0, 1376270, 536870916, 1376271, 10, 1376272, 10, 1376273, 10, 1376274, 10, 1376275, 10, 1376276, 10, 1376277, 10, 1376278, 10, 1376279, 10, 1376280, 4, 1376281, 12, 1376283, 8, 1376284, 8, 1376285, 536870920, 1376287, 536870924, 1376288, 0, 1376289, 5, 1376290, 536870917, 1376291, 0, 1376292, 536870916, 1376293, 10, 1376294, 10, 1376295, 10, 1376296, 10, 1376297, 10, 1376298, 10, 1376299, 10, 1376300, 10, 1376301, 10, 1376302, 10, 1376303, 10, 1376305, 12, 1376309, 7, 1376310, 536870920, 1376311, 7, 1376312, 536870920, 1376318, 536870914, 1376319, 10, 1376320, 10, 1376321, 10, 1376322, 10, 1376323, 10, 1376324, 10, 1376325, 10, 1376326, 10, 1376327, 10, 1376328, 10, 1441792, 10, 1441793, 10, 1441794, 10, 1441795, 10, 1441796, 10, 1441797, 10, 1441798, 10, 1441799, 10, 1441800, 10, 1441801, 10, 1441802, 10, 1441803, 10, 1441804, 10, 1441805, 10, 1441806, 10, 1441807, 10, 1441808, 10, 1441809, 10, 1441810, 10, 1441811, 10, 1441812, 10, 1441813, 10, 1441814, 10, 1441815, 10, 1441816, 10, 1441818, 0, 1441819, 6, 1441820, 6, 1441821, 536870918, 1441822, 5, 1441824, 10, 1441825, 10, 1441826, 10, 1441827, 10, 1441828, 10, 1441829, 10, 1441830, 10, 1441831, 10, 1441832, 10, 1441833, 10, 1441834, 10, 1441835, 10, 1441836, 10, 1441837, 10, 1441838, 10, 1441839, 10, 1441840, 10, 1441842, 0, 1441843, 0, 1441844, 0, 1441845, 6, 1441846, 536870918, 1441847, 6, 1441848, 536870918, 1441849, 0, 1441850, 5, 1441851, 536870917, 1441852, 5, 1441853, 0, 1441854, 536870916, 1441855, 10, 1441856, 10, 1441857, 10, 1441858, 10, 1441859, 10, 1441860, 10, 1441861, 10, 1441862, 10, 1441863, 10, 1507328, 10, 1507329, 10, 1507330, 10, 1507331, 10, 1507332, 10, 1507333, 10, 1507334, 10, 1507335, 10, 1507336, 10, 1507337, 10, 1507338, 10, 1507339, 10, 1507340, 10, 1507341, 10, 1507342, 10, 1507343, 10, 1507344, 10, 1507345, 10, 1507346, 10, 1507347, 10, 1507348, 10, 1507349, 10, 1507350, 10, 1507351, 10, 1507352, 10, 1507353, 10, 1507354, 10, 1507355, 10, 1507356, 10, 1507357, 10, 1507358, 10, 1507359, 10, 1507360, 10, 1507361, 10, 1507362, 10, 1507363, 10, 1507364, 10, 1507365, 10, 1507366, 10, 1507367, 10, 1507368, 10, 1507369, 10, 1507370, 10, 1507371, 10, 1507372, 10, 1507373, 10, 1507374, 10, 1507375, 10, 1507376, 10, 1507377, 10, 1507378, 10, 1507379, 10, 1507380, 10, 1507381, 10, 1507382, 10, 1507383, 10, 1507384, 10, 1507385, 10, 1507386, 10, 1507387, 10, 1507388, 10, 1507389, 10, 1507390, 10, 1507391, 10, 1507392, 10, 1507393, 10, 1507394, 10, 1507395, 10, 1507396, 10, 1507397, 10, 1507398, 10, 1507399, 10, 1572864, 10, 1572865, 10, 1572866, 10, 1572867, 10, 1572868, 10, 1572869, 10, 1572870, 10, 1572871, 10, 1572872, 10, 1572873, 10, 1572874, 10, 1572875, 10, 1572876, 10, 1572877, 10, 1572878, 10, 1572879, 10, 1572880, 10, 1572881, 10, 1572882, 10, 1572883, 10, 1572884, 10, 1572885, 10, 1572886, 10, 1572887, 10, 1572888, 10, 1572889, 10, 1572890, 10, 1572891, 10, 1572892, 10, 1572893, 10, 1572894, 10, 1572895, 10, 1572896, 10, 1572897, 10, 1572898, 10, 1572899, 10, 1572900, 10, 1572901, 10, 1572902, 10, 1572903, 10, 1572904, 10, 1572905, 10, 1572906, 10, 1572907, 10, 1572908, 10, 1572909, 10, 1572910, 10, 1572911, 10, 1572912, 10, 1572913, 10, 1572914, 10, 1572915, 10, 1572916, 10, 1572917, 10, 1572918, 10, 1572919, 10, 1572920, 10, 1572921, 10, 1572922, 10, 1572923, 10, 1572924, 10, 1572925, 10, 1572926, 10, 1572927, 10, 1572928, 10, 1572929, 10, 1572930, 10, 1572931, 10, 1572932, 10, 1572933, 10, 1572934, 10, 1572935, 10, 1638400, 10, 1638401, 10, 1638402, 10, 1638403, 10, 1638404, 10, 1638405, 10, 1638406, 10, 1638407, 10, 1638408, 10, 1638409, 10, 1638410, 10, 1638411, 10, 1638412, 10, 1638413, 10, 1638414, 10, 1638415, 10, 1638416, 10, 1638417, 10, 1638418, 10, 1638419, 10, 1638420, 10, 1638421, 10, 1638422, 10, 1638423, 10, 1638424, 10, 1638425, 10, 1638426, 10, 1638427, 10, 1638428, 10, 1638429, 10, 1638430, 10, 1638431, 10, 1638432, 10, 1638433, 10, 1638434, 10, 1638435, 10, 1638436, 10, 1638437, 10, 1638438, 10, 1638439, 10, 1638440, 10, 1638441, 10, 1638442, 10, 1638443, 10, 1638444, 10, 1638445, 10, 1638446, 10, 1638447, 10, 1638448, 10, 1638449, 10, 1638450, 10, 1638451, 10, 1638452, 10, 1638453, 10, 1638454, 10, 1638455, 10, 1638456, 10, 1638457, 10, 1638458, 10, 1638459, 10, 1638460, 10, 1638461, 10, 1638462, 10, 1638463, 10, 1638464, 10, 1638465, 10, 1638466, 10, 1638467, 10, 1638468, 10, 1638469, 10, 1638470, 10, 1638471, 10, 1703952, 10, 1703953, 10, 1703954, 10, 1703955, 10, 1703956, 10, 1703957, 10, 1703958, 10, 1703959, 10, 1703960, 10, 1703961, 10, 1703962, 10, 1703963, 10, 1703964, 10, 1703965, 10, 1703966, 10, 1703967, 10, 1703968, 10, 1703969, 10, 1703970, 10, 1703971, 10, 1703972, 10, 1703973, 10, 1703974, 10, 1703975, 10, 1703976, 10, 1703977, 10, 1703978, 10, 1703979, 10, 1703980, 10, 1703981, 10, 1703982, 10, 1703983, 10, 1703984, 10, 1703985, 10, 1703986, 10, 1703987, 10, 1703988, 10, 1703989, 10, 1703990, 10, 1703991, 10, 1703992, 10, 1703993, 10, 1703994, 10, 1703995, 10, 1703996, 10, 1703997, 10, 1703998, 10, 1703999, 10, 1704000, 10, 1704001, 10, 1704002, 10, 1704003, 10, 1704004, 10, 1704005, 10, 1704006, 10, 1704007, 10, 1769488, 10, 1769489, 10, 1769490, 10, 1769491, 10, 1769492, 10, 1769493, 10, 1769494, 10, 1769495, 10, 1769496, 10, 1769497, 10, 1769498, 10, 1769499, 10, 1769500, 10, 1769501, 10, 1769502, 10, 1769503, 10, 1769504, 10, 1769505, 10, 1769506, 10, 1769507, 10, 1769508, 10, 1769509, 10, 1769510, 10, 1769511, 10, 1769512, 10, 1769513, 10, 1769514, 10, 1769515, 10, 1769516, 10, 1769517, 10, 1769518, 10, 1769519, 10, 1769520, 10, 1769521, 10, 1769522, 10, 1769523, 10, 1769524, 10, 1769525, 10, 1769526, 10, 1769527, 10, 1769528, 10, 1769529, 10, 1769530, 10, 1769531, 10, 1769532, 10, 1769533, 10, 1769534, 10, 1769535, 10, 1769536, 10, 1769537, 10, 1769538, 10, 1769539, 10, 1769540, 10, 1769541, 10 </int_array>  				<dictionary  shared="false">  					<string> "_edit_lock_" </string>  					<bool> True </bool> @@ -482,6 +483,12 @@  						</dictionary>  						<string> "3D" </string>  						<dictionary  shared="false"> +							<string> "deflight_rot_y" </string> +							<real> 0.628319 </real> +							<string> "zfar" </string> +							<real> 500 </real> +							<string> "fov" </string> +							<real> 45 </real>  							<string> "viewports" </string>  							<array  len="4" shared="false">  								<dictionary  shared="false"> @@ -549,12 +556,6 @@  									<vector3> 0, 0, 0 </vector3>  								</dictionary>  							</array> -							<string> "zfar" </string> -							<real> 500 </real> -							<string> "deflight_rot_y" </string> -							<real> 0.628319 </real> -							<string> "fov" </string> -							<real> 45 </real>  							<string> "default_light" </string>  							<bool> True </bool>  							<string> "viewport_mode" </string> @@ -805,6 +806,7 @@  					<string> "2D" </string>  				</dictionary>  				<resource  resource_type="AudioStream" path="res://music.ogg">  </resource> +				<bool> False </bool>  				<real> 2 </real>  				<resource  resource_type="PackedScene" path="res://enemy.xml">  </resource>  				<vector2> 834.664, 1309.6 </vector2> @@ -998,7 +1000,7 @@  				<real> -1 </real>  			</array>  			<string> "nodes" </string> -			<int_array  len="950"> 				-1, -1, 1, 0, -1, 2, 2, 0, 3, 1, 0, 0, 0, 5, 4, -1, 19, 2, 0, 6, 2, 7, 3, 8, 3, 9, 4, 10, 5, 11, 6, 12, 7, 13, 8, 14, 9, 15, 10, 16, 11, 17, 12, 18, 13, 19, 3, 20, 6, 21, 14, 22, 15, 3, 16, 0, 0, 0, 1, 23, -1, 2, 2, 0, 3, 17, 0, 2, 0, 25, 24, 18, 3, 2, 0, 10, 19, 3, 20, 0, 2, 0, 25, 26, 18, 3, 2, 0, 10, 21, 3, 20, 0, 2, 0, 25, 27, 18, 3, 2, 0, 10, 22, 3, 20, 0, 2, 0, 25, 28, 18, 3, 2, 0, 10, 23, 3, 20, 0, 2, 0, 25, 29, 18, 3, 2, 0, 10, 24, 3, 20, 0, 2, 0, 25, 30, 18, 3, 2, 0, 10, 25, 3, 20, 0, 2, 0, 25, 31, 18, 3, 2, 0, 10, 26, 3, 20, 0, 2, 0, 25, 32, 18, 3, 2, 0, 10, 27, 3, 20, 0, 2, 0, 25, 33, 18, 3, 2, 0, 10, 28, 3, 20, 0, 2, 0, 25, 34, 18, 3, 2, 0, 10, 29, 3, 20, 0, 2, 0, 25, 35, 18, 3, 2, 0, 10, 30, 3, 20, 0, 2, 0, 25, 36, 18, 3, 2, 0, 10, 31, 3, 20, 0, 2, 0, 25, 37, 18, 3, 2, 0, 10, 32, 3, 20, 0, 2, 0, 25, 38, 18, 3, 2, 0, 10, 33, 3, 20, 0, 2, 0, 25, 39, 18, 3, 2, 0, 10, 34, 3, 20, 0, 2, 0, 25, 40, 18, 3, 2, 0, 10, 35, 3, 20, 0, 2, 0, 25, 41, 18, 3, 2, 0, 10, 36, 3, 20, 0, 2, 0, 25, 42, 18, 3, 2, 0, 10, 37, 3, 20, 0, 2, 0, 25, 43, 18, 3, 2, 0, 10, 38, 3, 20, 0, 2, 0, 25, 44, 18, 3, 2, 0, 10, 39, 3, 20, 0, 2, 0, 25, 45, 18, 3, 2, 0, 10, 40, 3, 20, 0, 2, 0, 25, 46, 18, 3, 2, 0, 10, 41, 3, 20, 0, 2, 0, 25, 47, 18, 3, 2, 0, 10, 42, 3, 20, 0, 2, 0, 25, 48, 18, 3, 2, 0, 10, 43, 3, 20, 0, 2, 0, 25, 49, 18, 3, 2, 0, 10, 44, 3, 20, 0, 2, 0, 25, 50, 18, 3, 2, 0, 10, 45, 3, 20, 0, 2, 0, 25, 51, 18, 3, 2, 0, 10, 46, 3, 20, 0, 2, 0, 25, 52, 18, 3, 2, 0, 10, 47, 3, 20, 0, 2, 0, 25, 53, 18, 3, 2, 0, 10, 48, 3, 20, 0, 2, 0, 25, 54, 18, 3, 2, 0, 10, 49, 3, 20, 0, 2, 0, 25, 55, 18, 3, 2, 0, 10, 50, 3, 20, 0, 2, 0, 25, 56, 18, 3, 2, 0, 10, 51, 3, 20, 0, 2, 0, 25, 57, 18, 3, 2, 0, 10, 52, 3, 20, 0, 2, 0, 25, 58, 18, 3, 2, 0, 10, 53, 3, 20, 0, 2, 0, 25, 59, 18, 3, 2, 0, 10, 54, 3, 20, 0, 2, 0, 25, 60, 18, 3, 2, 0, 10, 55, 3, 20, 0, 2, 0, 25, 61, 18, 3, 2, 0, 10, 56, 3, 20, 0, 2, 0, 25, 62, 18, 3, 2, 0, 10, 57, 3, 20, 0, 2, 0, 25, 63, 18, 3, 2, 0, 10, 58, 3, 20, 0, 2, 0, 25, 64, 18, 3, 2, 0, 10, 59, 3, 20, 0, 2, 0, 25, 65, 18, 3, 2, 0, 10, 60, 3, 20, 0, 2, 0, 25, 66, 18, 3, 2, 0, 10, 61, 3, 20, 0, 0, 0, 68, 67, 62, 3, 2, 0, 10, 63, 3, 64, 0, 0, 0, 1, 69, -1, 1, 2, 0, 0, 46, 0, 71, 70, 65, 5, 2, 0, 10, 66, 3, 67, 72, 68, 73, 69, 0, 46, 0, 71, 74, 65, 5, 2, 0, 10, 70, 3, 67, 72, 71, 73, 72, 0, 46, 0, 71, 75, 65, 5, 2, 0, 10, 73, 3, 67, 72, 74, 73, 72, 0, 46, 0, 71, 76, 75, 3, 2, 0, 10, 76, 3, 77, 0, 0, 0, 78, 77, -1, 7, 2, 0, 79, 78, 80, 4, 81, 2, 82, 79, 83, 2, 84, 4, 0, 0, 0, 1, 85, -1, 1, 2, 0, 0, 52, 0, 68, 86, 80, 3, 2, 0, 10, 81, 3, 82, 0, 52, 0, 68, 87, 80, 3, 2, 0, 10, 83, 3, 82, 0, 52, 0, 68, 88, 80, 3, 2, 0, 10, 84, 3, 82, 0, 52, 0, 68, 89, 80, 3, 2, 0, 10, 85, 3, 82, 0, 52, 0, 68, 90, 80, 3, 2, 0, 10, 86, 3, 82, 0, 52, 0, 68, 91, 80, 3, 2, 0, 10, 87, 3, 82, 0, 52, 0, 68, 92, 80, 3, 2, 0, 10, 88, 3, 82, 0, 52, 0, 68, 93, 80, 3, 2, 0, 10, 89, 3, 82, 0, 52, 0, 68, 94, 80, 3, 2, 0, 10, 90, 3, 82, 0, 52, 0, 68, 95, 80, 3, 2, 0, 10, 91, 3, 82, 0, 52, 0, 68, 96, 80, 3, 2, 0, 10, 92, 3, 82, 0, 0, 0, 98, 97, 93, 2, 2, 0, 3, 94, 0, 0, 0, 99, 99, -1, 30, 2, 0, 6, 2, 7, 3, 8, 3, 9, 4, 100, 95, 101, 96, 102, 97, 103, 98, 104, 0, 105, 0, 106, 0, 107, 0, 108, 2, 109, 2, 110, 13, 111, 3, 112, 6, 113, 99, 114, 3, 115, 100, 116, 6, 117, 4, 118, 4, 119, 101, 120, 8, 121, 8, 122, 2, 123, 4, 124, 102, 0 </int_array> +			<int_array  len="952"> 				-1, -1, 1, 0, -1, 2, 2, 0, 3, 1, 0, 0, 0, 5, 4, -1, 21, 2, 0, 6, 2, 7, 3, 8, 3, 9, 4, 10, 5, 11, 6, 12, 7, 13, 2, 14, 7, 15, 8, 16, 9, 17, 10, 18, 11, 19, 12, 20, 7, 21, 3, 22, 5, 23, 13, 24, 14, 3, 15, 0, 0, 0, 1, 25, -1, 2, 2, 0, 3, 16, 0, 2, 0, 27, 26, 17, 3, 2, 0, 9, 18, 3, 19, 0, 2, 0, 27, 28, 17, 3, 2, 0, 9, 20, 3, 19, 0, 2, 0, 27, 29, 17, 3, 2, 0, 9, 21, 3, 19, 0, 2, 0, 27, 30, 17, 3, 2, 0, 9, 22, 3, 19, 0, 2, 0, 27, 31, 17, 3, 2, 0, 9, 23, 3, 19, 0, 2, 0, 27, 32, 17, 3, 2, 0, 9, 24, 3, 19, 0, 2, 0, 27, 33, 17, 3, 2, 0, 9, 25, 3, 19, 0, 2, 0, 27, 34, 17, 3, 2, 0, 9, 26, 3, 19, 0, 2, 0, 27, 35, 17, 3, 2, 0, 9, 27, 3, 19, 0, 2, 0, 27, 36, 17, 3, 2, 0, 9, 28, 3, 19, 0, 2, 0, 27, 37, 17, 3, 2, 0, 9, 29, 3, 19, 0, 2, 0, 27, 38, 17, 3, 2, 0, 9, 30, 3, 19, 0, 2, 0, 27, 39, 17, 3, 2, 0, 9, 31, 3, 19, 0, 2, 0, 27, 40, 17, 3, 2, 0, 9, 32, 3, 19, 0, 2, 0, 27, 41, 17, 3, 2, 0, 9, 33, 3, 19, 0, 2, 0, 27, 42, 17, 3, 2, 0, 9, 34, 3, 19, 0, 2, 0, 27, 43, 17, 3, 2, 0, 9, 35, 3, 19, 0, 2, 0, 27, 44, 17, 3, 2, 0, 9, 36, 3, 19, 0, 2, 0, 27, 45, 17, 3, 2, 0, 9, 37, 3, 19, 0, 2, 0, 27, 46, 17, 3, 2, 0, 9, 38, 3, 19, 0, 2, 0, 27, 47, 17, 3, 2, 0, 9, 39, 3, 19, 0, 2, 0, 27, 48, 17, 3, 2, 0, 9, 40, 3, 19, 0, 2, 0, 27, 49, 17, 3, 2, 0, 9, 41, 3, 19, 0, 2, 0, 27, 50, 17, 3, 2, 0, 9, 42, 3, 19, 0, 2, 0, 27, 51, 17, 3, 2, 0, 9, 43, 3, 19, 0, 2, 0, 27, 52, 17, 3, 2, 0, 9, 44, 3, 19, 0, 2, 0, 27, 53, 17, 3, 2, 0, 9, 45, 3, 19, 0, 2, 0, 27, 54, 17, 3, 2, 0, 9, 46, 3, 19, 0, 2, 0, 27, 55, 17, 3, 2, 0, 9, 47, 3, 19, 0, 2, 0, 27, 56, 17, 3, 2, 0, 9, 48, 3, 19, 0, 2, 0, 27, 57, 17, 3, 2, 0, 9, 49, 3, 19, 0, 2, 0, 27, 58, 17, 3, 2, 0, 9, 50, 3, 19, 0, 2, 0, 27, 59, 17, 3, 2, 0, 9, 51, 3, 19, 0, 2, 0, 27, 60, 17, 3, 2, 0, 9, 52, 3, 19, 0, 2, 0, 27, 61, 17, 3, 2, 0, 9, 53, 3, 19, 0, 2, 0, 27, 62, 17, 3, 2, 0, 9, 54, 3, 19, 0, 2, 0, 27, 63, 17, 3, 2, 0, 9, 55, 3, 19, 0, 2, 0, 27, 64, 17, 3, 2, 0, 9, 56, 3, 19, 0, 2, 0, 27, 65, 17, 3, 2, 0, 9, 57, 3, 19, 0, 2, 0, 27, 66, 17, 3, 2, 0, 9, 58, 3, 19, 0, 2, 0, 27, 67, 17, 3, 2, 0, 9, 59, 3, 19, 0, 2, 0, 27, 68, 17, 3, 2, 0, 9, 60, 3, 19, 0, 0, 0, 70, 69, 61, 3, 2, 0, 9, 62, 3, 63, 0, 0, 0, 1, 71, -1, 1, 2, 0, 0, 46, 0, 73, 72, 64, 5, 2, 0, 9, 65, 3, 66, 74, 67, 75, 68, 0, 46, 0, 73, 76, 64, 5, 2, 0, 9, 69, 3, 66, 74, 70, 75, 71, 0, 46, 0, 73, 77, 64, 5, 2, 0, 9, 72, 3, 66, 74, 73, 75, 71, 0, 46, 0, 73, 78, 74, 3, 2, 0, 9, 75, 3, 76, 0, 0, 0, 80, 79, -1, 7, 2, 0, 81, 77, 82, 78, 83, 2, 84, 79, 85, 2, 86, 78, 0, 0, 0, 1, 87, -1, 1, 2, 0, 0, 52, 0, 70, 88, 80, 3, 2, 0, 9, 81, 3, 82, 0, 52, 0, 70, 89, 80, 3, 2, 0, 9, 83, 3, 82, 0, 52, 0, 70, 90, 80, 3, 2, 0, 9, 84, 3, 82, 0, 52, 0, 70, 91, 80, 3, 2, 0, 9, 85, 3, 82, 0, 52, 0, 70, 92, 80, 3, 2, 0, 9, 86, 3, 82, 0, 52, 0, 70, 93, 80, 3, 2, 0, 9, 87, 3, 82, 0, 52, 0, 70, 94, 80, 3, 2, 0, 9, 88, 3, 82, 0, 52, 0, 70, 95, 80, 3, 2, 0, 9, 89, 3, 82, 0, 52, 0, 70, 96, 80, 3, 2, 0, 9, 90, 3, 82, 0, 52, 0, 70, 97, 80, 3, 2, 0, 9, 91, 3, 82, 0, 52, 0, 70, 98, 80, 3, 2, 0, 9, 92, 3, 82, 0, 0, 0, 100, 99, 93, 2, 2, 0, 3, 94, 0, 0, 0, 101, 101, -1, 29, 2, 0, 6, 2, 7, 3, 8, 3, 102, 95, 103, 96, 104, 97, 105, 98, 106, 0, 107, 0, 108, 0, 109, 0, 110, 2, 111, 2, 112, 12, 113, 3, 114, 5, 115, 99, 116, 3, 117, 100, 118, 5, 119, 78, 120, 78, 121, 101, 122, 7, 123, 7, 124, 2, 125, 78, 126, 102, 0 </int_array>  			<string> "conns" </string>  			<int_array  len="0"> 				 </int_array>  		</dictionary> diff --git a/demos/2d/platformer/tiles_demo.png b/demos/2d/platformer/tiles_demo.png Binary files differindex a7a5000906..bc738e6d38 100644 --- a/demos/2d/platformer/tiles_demo.png +++ b/demos/2d/platformer/tiles_demo.png diff --git a/demos/2d/platformer/tileset.xml b/demos/2d/platformer/tileset.xml index 2e4ecc8c04..d8f9a651ee 100644 --- a/demos/2d/platformer/tileset.xml +++ b/demos/2d/platformer/tileset.xml @@ -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>
\ No newline at end of file diff --git a/demos/2d/platformer/tileset_edit.xml b/demos/2d/platformer/tileset_edit.xml index 2473656a6a..db289433ab 100644 --- a/demos/2d/platformer/tileset_edit.xml +++ b/demos/2d/platformer/tileset_edit.xml @@ -1,71 +1,83 @@  <?xml version="1.0" encoding="UTF-8" ?> -<resource_file type="PackedScene" subresource_count="12" version="1.0" version_name="Godot Engine v1.0.3917-beta1"> +<resource_file type="PackedScene" 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://1">  		<real name="custom_solver_bias"> 0 </real> -		<vector2_array name="points" len="4"> 			0, 8, 64, 8, 64, 64, 0, 64 </vector2_array> +		<vector2_array name="points" len="4"> 			-32, -24, 32, -24, 32, 32, -32, 32 </vector2_array>  	</resource>  	<resource type="ConvexPolygonShape2D" path="local://2">  		<real name="custom_solver_bias"> 0 </real> -		<vector2_array name="points" len="4"> 			0, 64, 0, 8, 56, 8, 56, 64 </vector2_array> +		<vector2_array name="points" len="4"> 			-32, 32, -32, -24, 24, -24, 24, 32 </vector2_array>  	</resource>  	<resource type="ConvexPolygonShape2D" path="local://3">  		<real name="custom_solver_bias"> 0 </real> -		<vector2_array name="points" len="4"> 			0, 64, 0, 0, 56, 0, 56, 64 </vector2_array> +		<vector2_array name="points" len="4"> 			-32, 32, -32, -32, 24, -32, 24, 32 </vector2_array>  	</resource>  	<resource type="ConvexPolygonShape2D" path="local://4">  		<real name="custom_solver_bias"> 0 </real> -		<vector2_array name="points" len="4"> 			0, 64, 0, 0, 56, 0, 56, 64 </vector2_array> +		<vector2_array name="points" len="4"> 			-64, 32, -64, -32, -8, -32, -8, 32 </vector2_array>  	</resource>  	<resource type="ConvexPolygonShape2D" path="local://5">  		<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> +		<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">  		<real name="custom_solver_bias"> 0 </real> -		<vector2_array name="points" len="4"> 			0, 8, 64, 72, 64, 128, 0, 128 </vector2_array> +		<vector2_array name="points" len="4"> 			-32, 32, -32, -24, 32, -24, 32, 32 </vector2_array>  	</resource>  	<resource type="ConvexPolygonShape2D" path="local://7">  		<real name="custom_solver_bias"> 0 </real> -		<vector2_array name="points" len="4"> 			0, 64, 0, 8, 64, 8, 64, 64 </vector2_array> +		<vector2_array name="points" len="4"> 			-32, 32, -32, -24, 32, -24, 32, 32 </vector2_array>  	</resource>  	<resource type="ConvexPolygonShape2D" path="local://8">  		<real name="custom_solver_bias"> 0 </real> -		<vector2_array name="points" len="4"> 			0, 64, 0, 8, 64, 8, 64, 64 </vector2_array> +		<vector2_array name="points" len="4"> 			-32, -32, 32, -32, 32, 32, -32, 32 </vector2_array>  	</resource>  	<resource type="ConvexPolygonShape2D" path="local://9">  		<real name="custom_solver_bias"> 0 </real> -		<vector2_array name="points" len="4"> 			0, 0, 64, 0, 64, 64, 0, 64 </vector2_array> +		<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"> 			0, 64, 0, 0, 56, 0, 56, 64 </vector2_array> +		<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>  		<dictionary name="_bundled" shared="false">  			<string> "names" </string> -			<string_array  len="75"> +			<string_array  len="77">  				<string> "Node" </string> +				<string> "_import_path" </string>  				<string> "__meta__" </string>  				<string> "floor" </string>  				<string> "Sprite" </string>  				<string> "visibility/visible" </string>  				<string> "visibility/opacity" </string>  				<string> "visibility/self_opacity" </string> -				<string> "visibility/behind_parent" </string>  				<string> "transform/pos" </string>  				<string> "transform/rot" </string>  				<string> "transform/scale" </string> +				<string> "z/z" </string> +				<string> "z/relative" </string>  				<string> "texture" </string>  				<string> "centered" </string>  				<string> "offset" </string> @@ -83,6 +95,7 @@  				<string> "shapes/0/shape" </string>  				<string> "shapes/0/transform" </string>  				<string> "shapes/0/trigger" </string> +				<string> "layers" </string>  				<string> "constant_linear_velocity" </string>  				<string> "constant_angular_velocity" </string>  				<string> "friction" </string> @@ -90,11 +103,11 @@  				<string> "CollisionPolygon2D" </string>  				<string> "build_mode" </string>  				<string> "polygon" </string> +				<string> "trigger" </string>  				<string> "edge" </string>  				<string> "wall" </string>  				<string> "wall_deco" </string>  				<string> "corner" </string> -				<string> "ramp" </string>  				<string> "flowers" </string>  				<string> "tree_base" </string>  				<string> "tree_mid" </string> @@ -102,13 +115,10 @@  				<string> "tree_top" </string>  				<string> "solid" </string>  				<string> "ceiling" </string> +				<string> "ramp" </string>  				<string> "ceiling2wall" </string>  				<string> "help" </string>  				<string> "Label" </string> -				<string> "margin/left" </string> -				<string> "margin/top" </string> -				<string> "margin/right" </string> -				<string> "margin/bottom" </string>  				<string> "focus_neighbour/left" </string>  				<string> "focus_neighbour/top" </string>  				<string> "focus_neighbour/right" </string> @@ -130,29 +140,38 @@  				<string> "autowrap" </string>  				<string> "uppercase" </string>  				<string> "percent_visible" </string> +				<string> "platform_floor" </string> +				<string> "platform_edge" </string>  			</string_array>  			<string> "version" </string>  			<int> 1 </int>  			<string> "conn_count" </string>  			<int> 0 </int>  			<string> "node_count" </string> -			<int> 36 </int> +			<int> 42 </int>  			<string> "variants" </string> -			<array  len="65" shared="false"> +			<array  len="69" shared="false"> +				<node_path> "" </node_path>  				<dictionary  shared="false">  					<string> "__editor_plugin_states__" </string>  					<dictionary  shared="false">  						<string> "2D" </string>  						<dictionary  shared="false">  							<string> "pixel_snap" </string> -							<bool> False </bool> +							<bool> True </bool>  							<string> "zoom" </string> -							<real> 1.670182 </real> +							<real> 1.670183 </real> +							<string> "use_snap" </string> +							<bool> True </bool>  							<string> "ofs" </string> -							<vector2> -58.9115, 60.1605 </vector2> +							<vector2> -446.534, -87.6905 </vector2> +							<string> "snap" </string> +							<int> 8 </int>  						</dictionary>  						<string> "3D" </string>  						<dictionary  shared="false"> +							<string> "deflight_rot_y" </string> +							<real> 0.628319 </real>  							<string> "zfar" </string>  							<real> 500 </real>  							<string> "fov" </string> @@ -166,10 +185,12 @@  									<real> 0 </real>  									<string> "y_rot" </string>  									<real> 0 </real> -									<string> "use_orthogonal" </string> -									<bool> False </bool> +									<string> "listener" </string> +									<bool> True </bool>  									<string> "use_environment" </string>  									<bool> False </bool> +									<string> "use_orthogonal" </string> +									<bool> False </bool>  									<string> "pos" </string>  									<vector3> 0, 0, 0 </vector3>  								</dictionary> @@ -180,10 +201,12 @@  									<real> 0 </real>  									<string> "y_rot" </string>  									<real> 0 </real> -									<string> "use_orthogonal" </string> +									<string> "listener" </string>  									<bool> False </bool>  									<string> "use_environment" </string>  									<bool> False </bool> +									<string> "use_orthogonal" </string> +									<bool> False </bool>  									<string> "pos" </string>  									<vector3> 0, 0, 0 </vector3>  								</dictionary> @@ -194,10 +217,12 @@  									<real> 0 </real>  									<string> "y_rot" </string>  									<real> 0 </real> -									<string> "use_orthogonal" </string> +									<string> "listener" </string>  									<bool> False </bool>  									<string> "use_environment" </string>  									<bool> False </bool> +									<string> "use_orthogonal" </string> +									<bool> False </bool>  									<string> "pos" </string>  									<vector3> 0, 0, 0 </vector3>  								</dictionary> @@ -208,10 +233,12 @@  									<real> 0 </real>  									<string> "y_rot" </string>  									<real> 0 </real> -									<string> "use_orthogonal" </string> +									<string> "listener" </string>  									<bool> False </bool>  									<string> "use_environment" </string>  									<bool> False </bool> +									<string> "use_orthogonal" </string> +									<bool> False </bool>  									<string> "pos" </string>  									<vector3> 0, 0, 0 </vector3>  								</dictionary> @@ -220,12 +247,18 @@  							<int> 1 </int>  							<string> "default_light" </string>  							<bool> True </bool> +							<string> "ambient_light_color" </string> +							<color> 0.15, 0.15, 0.15, 1 </color>  							<string> "show_grid" </string>  							<bool> True </bool>  							<string> "show_origin" </string>  							<bool> True </bool>  							<string> "znear" </string>  							<real> 0.1 </real> +							<string> "default_srgb" </string> +							<bool> False </bool> +							<string> "deflight_rot_x" </string> +							<real> 0.942478 </real>  						</dictionary>  					</dictionary>  					<string> "__editor_run_settings__" </string> @@ -239,45 +272,42 @@  					<string> "2D" </string>  				</dictionary>  				<bool> True </bool> -				<nil>  </nil> -				<nil>  </nil> +				<real> 1 </real>  				<vector2> 0, 0 </vector2> -				<nil>  </nil> +				<real> 0 </real>  				<vector2> 1, 1 </vector2> +				<int> 0 </int>  				<resource  resource_type="Texture" path="res://tiles_demo.png">  </resource> +				<bool> False </bool>  				<int> 1 </int> -				<nil>  </nil>  				<color> 1, 1, 1, 1 </color>  				<rect2> 0, 0, 64, 64 </rect2>  				<resource  resource_type="Shape2D" path="local://1">  </resource>  				<matrix32> 1, -0, 0, 1, 0, 0 </matrix32> -				<vector2_array  len="4"> 					64, 8, 64, 64, 0, 64, 0, 8 </vector2_array> +				<vector2_array  len="4"> 					32, -24, 32, 32, -32, 32, -32, -24 </vector2_array>  				<vector2> 64, 0 </vector2>  				<rect2> 64, 0, 64, 64 </rect2>  				<resource  resource_type="Shape2D" path="local://2">  </resource> -				<vector2_array  len="4"> 					0, 8, 56, 8, 56, 64, 0, 64 </vector2_array> +				<vector2_array  len="4"> 					-32, -24, 24, -24, 24, 32, -32, 32 </vector2_array>  				<vector2> 64, 64 </vector2>  				<rect2> 64, 64, 64, 64 </rect2>  				<resource  resource_type="Shape2D" path="local://3">  </resource> -				<vector2_array  len="4"> 					0, 0, 56, 0, 56, 64, 0, 64 </vector2_array> -				<vector2> 64, 128 </vector2> +				<vector2_array  len="4"> 					-32, -32, 24, -32, 24, 32, -32, 32 </vector2_array> +				<vector2> 96, 128 </vector2>  				<rect2> 320, 128, 128, 64 </rect2>  				<resource  resource_type="Shape2D" path="local://4">  </resource> +				<vector2_array  len="4"> 					-64, -32, -8, -32, -8, 32, -64, 32 </vector2_array>  				<vector2> 64, 192 </vector2>  				<rect2> 64, 128, 64, 64 </rect2>  				<resource  resource_type="Shape2D" path="local://5">  </resource> -				<vector2_array  len="5"> 					0, 0, 56, 0, 64, 8, 64, 64, 0, 64 </vector2_array> -				<vector2> 256, 192 </vector2> -				<rect2> 128, 128, 64, 128 </rect2> -				<resource  resource_type="Shape2D" path="local://6">  </resource> -				<vector2_array  len="4"> 					0, 8, 64, 72, 64, 128, 0, 128 </vector2_array> +				<vector2_array  len="5"> 					-32, -32, 24, -32, 32, -24, 32, 32, -32, 32 </vector2_array>  				<vector2> 128, 192 </vector2>  				<rect2> 192, 192, 64, 64 </rect2> -				<resource  resource_type="Shape2D" path="local://7">  </resource> -				<vector2_array  len="4"> 					0, 64, 64, 64, 64, 8, 0, 8 </vector2_array> +				<resource  resource_type="Shape2D" path="local://6">  </resource> +				<vector2_array  len="4"> 					-32, 32, 32, 32, 32, -24, -32, -24 </vector2_array>  				<vector2> 192, 192 </vector2>  				<rect2> 256, 192, 64, 64 </rect2> -				<resource  resource_type="Shape2D" path="local://8">  </resource> +				<resource  resource_type="Shape2D" path="local://7">  </resource>  				<vector2> 192, 128 </vector2>  				<rect2> 256, 128, 64, 64 </rect2>  				<vector2> 192, 64 </vector2> @@ -288,23 +318,29 @@  				<rect2> 0, 64, 64, 64 </rect2>  				<vector2> 0, 128 </vector2>  				<rect2> 384, 64, 64, 64 </rect2> +				<resource  resource_type="Shape2D" path="local://8">  </resource> +				<vector2_array  len="4"> 					32, -32, 32, 32, -32, 32, -32, -32 </vector2_array> +				<vector2> 256, 224 </vector2> +				<rect2> 128, 128, 64, 128 </rect2>  				<resource  resource_type="Shape2D" path="local://9">  </resource> -				<vector2_array  len="4"> 					64, 0, 64, 64, 0, 64, 0, 0 </vector2_array> +				<vector2_array  len="4"> 					-32, -56, 32, 8, 32, 64, -32, 64 </vector2_array>  				<vector2> 0, 192 </vector2>  				<rect2> 448, 64, 64, 64 </rect2>  				<resource  resource_type="Shape2D" path="local://10">  </resource> -				<nil>  </nil> -				<nil>  </nil> -				<nil>  </nil> -				<nil>  </nil> -				<nil>  </nil>  				<int> 2 </int> -				<nil>  </nil> -				<string> "This scene serves as a tool for editing the tileset.
Nodes (sprites) and their respective collisions
are edited here. 

To create a tileset from this, a "TileSet" resoucre 
must be created. Use the helper in:

 Scene -< Convert To -< TileSet

This will save a tileset. Saving over it will merge your changes.

Finally, the saved tileset resource (tileset.xml in this
 case), can be opened to be used into a TileMap node
 for editing a tile map.
" </string> +				<string> "This scene serves as a tool for editing the tileset.
Nodes (sprites) and their respective collisions
are edited here. 

To create a tileset from this, a "TileSet" resoucre 
must be created. Use the helper in:

 Scene -< Convert To -< TileSet

This will save a tileset. Saving over it will merge your changes.

Finally, the saved tileset resource (tileset.xml in this
 case), can be opened to be used into a TileMap node
 for editing a tile map.
" </string>  				<real> -1 </real> +				<vector2> 0, 256 </vector2> +				<rect2> 128, 0, 64, 64 </rect2> +				<resource  resource_type="Shape2D" path="local://11">  </resource> +				<vector2_array  len="4"> 					32, -24, 32, 24, -32, 24, -32, -24 </vector2_array> +				<vector2> 64, 256 </vector2> +				<rect2> 192, 0, 64, 64 </rect2> +				<resource  resource_type="Shape2D" path="local://12">  </resource> +				<vector2_array  len="4"> 					24, -24, 24, 24, -32, 24, -32, -24 </vector2_array>  			</array>  			<string> "nodes" </string> -			<int_array  len="1296"> 				-1, -1, 0, 0, -1, 1, 1, 0, 0, 0, 0, 3, 2, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 11, 0, 1, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 12, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 2, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 14, 0, 0, 0, 3, 35, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 15, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 16, 0, 4, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 17, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 5, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 18, 0, 0, 0, 3, 36, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 19, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 20, 0, 7, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 21, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 8, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 22, 0, 0, 0, 3, 37, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 23, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 24, 0, 10, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 25, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 11, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 22, 0, 0, 0, 3, 38, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 26, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 27, 0, 13, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 28, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 14, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 29, 0, 0, 0, 3, 39, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 30, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 31, 0, 16, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 32, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 17, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 33, 0, 0, 0, 3, 40, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 34, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 35, 0, 19, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 36, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 20, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 37, 0, 0, 0, 3, 41, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 38, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 39, 0, 22, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 40, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 23, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 37, 0, 0, 0, 3, 42, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 41, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 42, 0, 0, 0, 3, 43, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 43, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 44, 0, 0, 0, 3, 44, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 45, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 46, 0, 0, 0, 3, 45, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 47, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 48, 0, 0, 0, 3, 46, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 49, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 50, 0, 29, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 51, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 30, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 52, 0, 0, 0, 3, 47, -1, 18, 4, 1, 5, 2, 6, 2, 7, 3, 8, 53, 9, 5, 10, 6, 11, 7, 12, 3, 13, 4, 14, 3, 15, 3, 16, 8, 17, 8, 18, 9, 19, 10, 20, 1, 21, 54, 0, 32, 0, 23, 22, -1, 15, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 24, 8, 25, 55, 26, 13, 27, 3, 28, 4, 29, 5, 30, 2, 31, 5, 0, 33, 0, 32, 32, -1, 9, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 33, 9, 34, 22, 0, 0, 0, 49, 48, -1, 29, 4, 1, 5, 2, 6, 2, 7, 3, 50, 56, 51, 57, 52, 58, 53, 59, 54, 60, 55, 60, 56, 60, 57, 60, 58, 1, 59, 1, 60, 61, 61, 2, 62, 5, 63, 62, 64, 2, 65, 62, 66, 5, 67, 3, 68, 3, 69, 63, 70, 9, 71, 9, 72, 3, 73, 3, 74, 64, 0 </int_array> +			<int_array  len="1708"> 				-1, -1, 0, 0, -1, 2, 1, 0, 2, 1, 0, 0, 0, 4, 3, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 12, 0, 1, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 13, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 2, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 15, 38, 9, 0, 0, 0, 4, 39, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 16, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 17, 0, 4, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 18, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 5, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 19, 38, 9, 0, 0, 0, 4, 40, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 20, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 21, 0, 7, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 22, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 8, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 23, 38, 9, 0, 0, 0, 4, 41, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 24, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 25, 0, 10, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 26, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 11, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 27, 38, 9, 0, 0, 0, 4, 42, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 28, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 29, 0, 13, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 30, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 14, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 31, 38, 9, 0, 0, 0, 4, 43, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 32, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 33, 0, 16, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 34, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 17, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 35, 38, 9, 0, 0, 0, 4, 44, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 36, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 37, 0, 19, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 38, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 20, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 35, 38, 9, 0, 0, 0, 4, 45, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 39, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 40, 0, 0, 0, 4, 46, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 41, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 42, 0, 0, 0, 4, 47, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 43, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 44, 0, 0, 0, 4, 48, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 45, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 46, 0, 0, 0, 4, 49, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 47, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 48, 0, 26, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 49, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 27, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 50, 38, 9, 0, 0, 0, 4, 50, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 51, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 52, 0, 29, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 53, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 30, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 54, 38, 9, 0, 0, 0, 4, 51, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 55, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 56, 0, 32, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 57, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 33, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 23, 38, 9, 0, 0, 0, 53, 52, -1, 25, 1, 0, 5, 2, 6, 3, 7, 3, 54, 0, 55, 0, 56, 0, 57, 0, 58, 2, 59, 2, 60, 58, 61, 3, 62, 5, 63, 3, 64, 3, 65, 3, 66, 5, 67, 9, 68, 9, 69, 59, 70, 7, 71, 7, 72, 9, 73, 9, 74, 60, 0, 0, 0, 4, 75, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 61, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 62, 0, 36, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 63, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 37, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 64, 38, 9, 0, 0, 0, 4, 76, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 65, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 66, 0, 39, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 67, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 40, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 68, 38, 9, 0 </int_array>  			<string> "conns" </string>  			<int_array  len="0"> 				 </int_array>  		</dictionary> diff --git a/demos/2d/polygon_path_finder_demo/.fscache b/demos/2d/polygon_path_finder_demo/.fscache deleted file mode 100644 index f699ca5849..0000000000 --- a/demos/2d/polygon_path_finder_demo/.fscache +++ /dev/null @@ -1,4 +0,0 @@ -::res://::1421147952 -icon.png::ImageTexture::1420046079:: -new_scene_poly_with_holes.scn::PackedScene::1421147952:: -polygonpathfinder.gd::GDScript::1421146502:: diff --git a/demos/3d/kinematic_char/cubelib.res b/demos/3d/kinematic_char/cubelib.res Binary files differindex 66b999d78d..27f2b9b3bd 100644 --- a/demos/3d/kinematic_char/cubelib.res +++ b/demos/3d/kinematic_char/cubelib.res diff --git a/demos/3d/kinematic_char/level.scn b/demos/3d/kinematic_char/level.scn Binary files differindex a276fe22e1..7ccb2430c1 100644 --- a/demos/3d/kinematic_char/level.scn +++ b/demos/3d/kinematic_char/level.scn diff --git a/demos/3d/platformer/stage.xml b/demos/3d/platformer/stage.xml index f3a5caffa9..37a11068c9 100644 --- a/demos/3d/platformer/stage.xml +++ b/demos/3d/platformer/stage.xml @@ -1,10 +1,10 @@  <?xml version="1.0" encoding="UTF-8" ?> -<resource_file type="PackedScene" subresource_count="7" version="1.0" version_name="Godot Engine v1.0.3917-beta1"> +<resource_file type="PackedScene" subresource_count="7" version="1.0" version_name="Godot Engine v1.0.stable.custom_build">  	<ext_resource path="res://sb.cube" type="CubeMap"></ext_resource>  	<ext_resource path="res://tiles.res" type="MeshLibrary"></ext_resource>  	<ext_resource path="res://enemy.scn" type="PackedScene"></ext_resource> -	<ext_resource path="res://coin.scn" type="PackedScene"></ext_resource>  	<ext_resource path="res://player.xml" type="PackedScene"></ext_resource> +	<ext_resource path="res://coin.scn" type="PackedScene"></ext_resource>  	<resource type="Environment" path="local://1">  		<bool name="ambient_light/enabled"> True </bool>  		<color name="ambient_light/color"> 0, 0.409429, 0.596681, 1 </color> @@ -29,8 +29,9 @@  		<real name="dof_blur/begin"> 100 </real>  		<real name="dof_blur/range"> 10 </real>  		<bool name="hdr/enabled"> True </bool> +		<int name="hdr/tonemapper"> 0 </int>  		<real name="hdr/exposure"> 0.4 </real> -		<real name="hdr/scalar"> 1 </real> +		<real name="hdr/white"> 1 </real>  		<real name="hdr/glow_treshold"> 0.9 </real>  		<real name="hdr/glow_scale"> 0.5 </real>  		<real name="hdr/min_luminance"> 0.4 </real> @@ -52,11 +53,12 @@  	<main_resource>  		<dictionary name="_bundled" shared="false">  			<string> "names" </string> -			<string_array  len="92"> +			<string_array  len="94">  				<string> "world" </string>  				<string> "Spatial" </string>  				<string> "_import_path" </string>  				<string> "_import_transform" </string> +				<string> "visibility/visible" </string>  				<string> "__meta__" </string>  				<string> "GridMap" </string>  				<string> "theme/theme" </string> @@ -73,6 +75,7 @@  				<string> "transform/local" </string>  				<string> "layers" </string>  				<string> "params/enabled" </string> +				<string> "params/editor_only" </string>  				<string> "params/bake_mode" </string>  				<string> "params/energy" </string>  				<string> "colors/diffuse" </string> @@ -153,9 +156,10 @@  			<string> "node_count" </string>  			<int> 55 </int>  			<string> "variants" </string> -			<array  len="79" shared="false"> +			<array  len="82" shared="false">  				<node_path> "" </node_path>  				<transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 </transform> +				<bool> True </bool>  				<dictionary  shared="false">  					<string> "__editor_plugin_states__" </string>  					<dictionary  shared="false"> @@ -174,23 +178,27 @@  						</dictionary>  						<string> "3D" </string>  						<dictionary  shared="false"> +							<string> "deflight_rot_y" </string> +							<real> 0.628319 </real>  							<string> "zfar" </string>  							<real> 500 </real>  							<string> "fov" </string> -							<real> 400 </real> +							<real> 179 </real>  							<string> "viewports" </string>  							<array  len="4" shared="false">  								<dictionary  shared="false">  									<string> "distance" </string> -									<real> 0.261354 </real> +									<real> 9.009935 </real>  									<string> "x_rot" </string>  									<real> 0.458294 </real>  									<string> "y_rot" </string>  									<real> -1.2 </real> -									<string> "use_orthogonal" </string> -									<bool> False </bool> +									<string> "listener" </string> +									<bool> True </bool>  									<string> "use_environment" </string>  									<bool> False </bool> +									<string> "use_orthogonal" </string> +									<bool> False </bool>  									<string> "pos" </string>  									<vector3> 13.4535, 5.75047, 13.8175 </vector3>  								</dictionary> @@ -201,10 +209,12 @@  									<real> 0 </real>  									<string> "y_rot" </string>  									<real> 0 </real> -									<string> "use_orthogonal" </string> +									<string> "listener" </string>  									<bool> False </bool>  									<string> "use_environment" </string>  									<bool> False </bool> +									<string> "use_orthogonal" </string> +									<bool> False </bool>  									<string> "pos" </string>  									<vector3> 0, 0, 0 </vector3>  								</dictionary> @@ -215,10 +225,12 @@  									<real> 0 </real>  									<string> "y_rot" </string>  									<real> 0 </real> -									<string> "use_orthogonal" </string> +									<string> "listener" </string>  									<bool> False </bool>  									<string> "use_environment" </string>  									<bool> False </bool> +									<string> "use_orthogonal" </string> +									<bool> False </bool>  									<string> "pos" </string>  									<vector3> 0, 0, 0 </vector3>  								</dictionary> @@ -229,10 +241,12 @@  									<real> 0 </real>  									<string> "y_rot" </string>  									<real> 0 </real> -									<string> "use_orthogonal" </string> +									<string> "listener" </string>  									<bool> False </bool>  									<string> "use_environment" </string>  									<bool> False </bool> +									<string> "use_orthogonal" </string> +									<bool> False </bool>  									<string> "pos" </string>  									<vector3> 0, 0, 0 </vector3>  								</dictionary> @@ -241,12 +255,18 @@  							<int> 1 </int>  							<string> "default_light" </string>  							<bool> False </bool> +							<string> "ambient_light_color" </string> +							<color> 0.15, 0.15, 0.15, 1 </color>  							<string> "show_grid" </string>  							<bool> True </bool>  							<string> "show_origin" </string>  							<bool> True </bool>  							<string> "znear" </string>  							<real> 0.1 </real> +							<string> "default_srgb" </string> +							<bool> False </bool> +							<string> "deflight_rot_x" </string> +							<real> 0.942478 </real>  						</dictionary>  					</dictionary>  					<string> "__editor_run_settings__" </string> @@ -263,7 +283,6 @@  				<bool> False </bool>  				<real> 2 </real>  				<int> 4 </int> -				<bool> True </bool>  				<real> 1.001 </real>  				<dictionary  shared="false">  					<string> "cells" </string> @@ -295,6 +314,112 @@  				</dictionary>  				<resource  resource_type="PackedScene" path="res://coin.scn">  </resource>  				<transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 18.5311, 2.85075, 5.24675 </transform> +				<dictionary  shared="false"> +					<string> "__editor_plugin_states__" </string> +					<dictionary  shared="false"> +						<string> "Script" </string> +						<dictionary  shared="false"> +							<string> "current" </string> +							<int> 0 </int> +							<string> "sources" </string> +							<array  len="1" shared="false"> +								<string> "res://coin.gd" </string> +							</array> +						</dictionary> +						<string> "2D" </string> +						<dictionary  shared="false"> +							<string> "zoom" </string> +							<real> 1 </real> +							<string> "ofs" </string> +							<vector2> 1, 1 </vector2> +						</dictionary> +						<string> "3D" </string> +						<dictionary  shared="false"> +							<string> "fov" </string> +							<real> 400 </real> +							<string> "zfar" </string> +							<real> 500 </real> +							<string> "viewports" </string> +							<array  len="4" shared="false"> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 1.361845 </real> +									<string> "x_rot" </string> +									<real> 0.0125 </real> +									<string> "y_rot" </string> +									<real> 12.050008 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> -0.00892573, 0.51052, -0.216081 </vector3> +								</dictionary> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 4 </real> +									<string> "x_rot" </string> +									<real> 0 </real> +									<string> "y_rot" </string> +									<real> 0 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> 0, 0, 0 </vector3> +								</dictionary> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 4 </real> +									<string> "x_rot" </string> +									<real> 0 </real> +									<string> "y_rot" </string> +									<real> 0 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> 0, 0, 0 </vector3> +								</dictionary> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 4 </real> +									<string> "x_rot" </string> +									<real> 0 </real> +									<string> "y_rot" </string> +									<real> 0 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> 0, 0, 0 </vector3> +								</dictionary> +							</array> +							<string> "viewport_mode" </string> +							<int> 1 </int> +							<string> "default_light" </string> +							<bool> True </bool> +							<string> "show_grid" </string> +							<bool> True </bool> +							<string> "znear" </string> +							<real> 0.1 </real> +							<string> "show_origin" </string> +							<bool> True </bool> +						</dictionary> +					</dictionary> +					<string> "__editor_run_settings__" </string> +					<dictionary  shared="false"> +						<string> "custom_args" </string> +						<string> "-l $scene" </string> +						<string> "run_mode" </string> +						<int> 0 </int> +					</dictionary> +					<string> "__editor_plugin_screen__" </string> +					<string> "3D" </string> +				</dictionary>  				<transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 18.5311, 2.85075, 7.24675 </transform>  				<transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 20.5311, 2.85075, 5.24675 </transform>  				<transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 20.5311, 2.85075, 7.24675 </transform> @@ -340,14 +465,230 @@  				<transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 51.5614, 4.60515, 25.1836 </transform>  				<resource  resource_type="PackedScene" path="res://enemy.scn">  </resource>  				<transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 18.3062, 5.40827, 5.96938 </transform> +				<dictionary  shared="false"> +					<string> "__editor_plugin_states__" </string> +					<dictionary  shared="false"> +						<string> "Script" </string> +						<dictionary  shared="false"> +							<string> "current" </string> +							<int> 0 </int> +							<string> "sources" </string> +							<array  len="2" shared="false"> +								<string> "res://enemy.gd" </string> +								<string> "res://player.gd" </string> +							</array> +						</dictionary> +						<string> "2D" </string> +						<dictionary  shared="false"> +							<string> "zoom" </string> +							<real> 1 </real> +							<string> "ofs" </string> +							<vector2> 1, 1 </vector2> +						</dictionary> +						<string> "3D" </string> +						<dictionary  shared="false"> +							<string> "fov" </string> +							<real> 400 </real> +							<string> "zfar" </string> +							<real> 500 </real> +							<string> "viewports" </string> +							<array  len="4" shared="false"> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 7.403724 </real> +									<string> "x_rot" </string> +									<real> 0.25 </real> +									<string> "y_rot" </string> +									<real> 3.312502 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> 0.898236, 0.953557, 0.742913 </vector3> +								</dictionary> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 4 </real> +									<string> "x_rot" </string> +									<real> 0 </real> +									<string> "y_rot" </string> +									<real> 0 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> 0, 0, 0 </vector3> +								</dictionary> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 4 </real> +									<string> "x_rot" </string> +									<real> 0 </real> +									<string> "y_rot" </string> +									<real> 0 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> 0, 0, 0 </vector3> +								</dictionary> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 4 </real> +									<string> "x_rot" </string> +									<real> 0 </real> +									<string> "y_rot" </string> +									<real> 0 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> 0, 0, 0 </vector3> +								</dictionary> +							</array> +							<string> "viewport_mode" </string> +							<int> 1 </int> +							<string> "default_light" </string> +							<bool> True </bool> +							<string> "show_grid" </string> +							<bool> True </bool> +							<string> "znear" </string> +							<real> 0.1 </real> +							<string> "show_origin" </string> +							<bool> True </bool> +						</dictionary> +					</dictionary> +					<string> "__editor_run_settings__" </string> +					<dictionary  shared="false"> +						<string> "custom_args" </string> +						<string> "-l $scene" </string> +						<string> "run_mode" </string> +						<int> 0 </int> +					</dictionary> +					<string> "__editor_plugin_screen__" </string> +					<string> "Script" </string> +				</dictionary>  				<transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.1292, 5.40827, 17.1396 </transform>  				<transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.1292, 5.40827, 32.6128 </transform>  				<transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 55.5702, 5.40827, 32.6128 </transform>  				<resource  resource_type="PackedScene" path="res://player.xml">  </resource>  				<transform> 0.0160676, 0, -0.999871, 0, 1, 0, 0.999871, 0, 0.0160676, 8.50167, 4.15811, 15.9334 </transform> +				<dictionary  shared="false"> +					<string> "__editor_plugin_states__" </string> +					<dictionary  shared="false"> +						<string> "Script" </string> +						<dictionary  shared="false"> +							<string> "current" </string> +							<int> 1 </int> +							<string> "sources" </string> +							<array  len="2" shared="false"> +								<string> "res://follow_camera.gd" </string> +								<string> "res://player.gd" </string> +							</array> +						</dictionary> +						<string> "2D" </string> +						<dictionary  shared="false"> +							<string> "pixel_snap" </string> +							<bool> False </bool> +							<string> "zoom" </string> +							<real> 1 </real> +							<string> "ofs" </string> +							<vector2> -241, -19 </vector2> +						</dictionary> +						<string> "3D" </string> +						<dictionary  shared="false"> +							<string> "fov" </string> +							<real> 400 </real> +							<string> "zfar" </string> +							<real> 500 </real> +							<string> "viewports" </string> +							<array  len="4" shared="false"> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 2.161076 </real> +									<string> "x_rot" </string> +									<real> 0.520797 </real> +									<string> "y_rot" </string> +									<real> 26.741669 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> -0.415811, 0.486899, 0.089334 </vector3> +								</dictionary> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 4 </real> +									<string> "x_rot" </string> +									<real> 0 </real> +									<string> "y_rot" </string> +									<real> 0 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> 0, 0, 0 </vector3> +								</dictionary> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 4 </real> +									<string> "x_rot" </string> +									<real> 0 </real> +									<string> "y_rot" </string> +									<real> 0 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> 0, 0, 0 </vector3> +								</dictionary> +								<dictionary  shared="false"> +									<string> "distance" </string> +									<real> 4 </real> +									<string> "x_rot" </string> +									<real> 0 </real> +									<string> "y_rot" </string> +									<real> 0 </real> +									<string> "use_orthogonal" </string> +									<bool> False </bool> +									<string> "use_environment" </string> +									<bool> False </bool> +									<string> "pos" </string> +									<vector3> 0, 0, 0 </vector3> +								</dictionary> +							</array> +							<string> "viewport_mode" </string> +							<int> 1 </int> +							<string> "default_light" </string> +							<bool> True </bool> +							<string> "show_grid" </string> +							<bool> True </bool> +							<string> "znear" </string> +							<real> 0.1 </real> +							<string> "show_origin" </string> +							<bool> True </bool> +						</dictionary> +					</dictionary> +					<string> "__editor_run_settings__" </string> +					<dictionary  shared="false"> +						<string> "custom_args" </string> +						<string> "-l $scene" </string> +						<string> "run_mode" </string> +						<int> 0 </int> +					</dictionary> +					<string> "__editor_plugin_screen__" </string> +					<string> "3D" </string> +				</dictionary>  			</array>  			<string> "nodes" </string> -			<int_array  len="569"> 				-1, -1, 1, 0, -1, 3, 2, 0, 3, 1, 4, 2, 0, 0, 0, 5, 5, -1, 13, 2, 0, 3, 1, 6, 3, 7, 4, 8, 4, 9, 5, 10, 6, 11, 7, 12, 7, 13, 7, 14, 8, 15, 9, 4, 10, 0, 0, 0, 16, 16, -1, 21, 2, 0, 3, 1, 17, 11, 18, 12, 19, 7, 20, 13, 21, 14, 22, 15, 23, 15, 24, 7, 25, 16, 26, 17, 27, 18, 28, 19, 29, 20, 30, 21, 31, 13, 32, 22, 33, 23, 34, 24, 35, 5, 0, 0, 0, 37, 36, -1, 3, 2, 0, 3, 1, 36, 25, 0, 0, 0, 39, 38, -1, 2, 2, 0, 4, 26, 0, 4, 0, 41, 40, 27, 1, 17, 28, 0, 4, 0, 41, 42, 27, 1, 17, 29, 0, 4, 0, 41, 43, 27, 1, 17, 30, 0, 4, 0, 41, 44, 27, 1, 17, 31, 0, 4, 0, 41, 45, 27, 1, 17, 32, 0, 4, 0, 41, 46, 27, 1, 17, 33, 0, 4, 0, 41, 47, 27, 1, 17, 34, 0, 4, 0, 41, 48, 27, 1, 17, 35, 0, 4, 0, 41, 49, 27, 1, 17, 36, 0, 4, 0, 41, 50, 27, 1, 17, 37, 0, 4, 0, 41, 51, 27, 1, 17, 38, 0, 4, 0, 41, 52, 27, 1, 17, 39, 0, 4, 0, 41, 53, 27, 1, 17, 40, 0, 4, 0, 41, 54, 27, 1, 17, 41, 0, 4, 0, 41, 55, 27, 1, 17, 42, 0, 4, 0, 41, 56, 27, 1, 17, 43, 0, 4, 0, 41, 57, 27, 1, 17, 44, 0, 4, 0, 41, 58, 27, 1, 17, 45, 0, 4, 0, 41, 59, 27, 1, 17, 46, 0, 4, 0, 41, 60, 27, 1, 17, 47, 0, 4, 0, 41, 61, 27, 1, 17, 48, 0, 4, 0, 41, 62, 27, 1, 17, 49, 0, 4, 0, 41, 63, 27, 1, 17, 50, 0, 4, 0, 41, 64, 27, 1, 17, 51, 0, 4, 0, 41, 65, 27, 1, 17, 52, 0, 4, 0, 41, 66, 27, 1, 17, 53, 0, 4, 0, 41, 67, 27, 1, 17, 54, 0, 4, 0, 41, 68, 27, 1, 17, 55, 0, 4, 0, 41, 69, 27, 1, 17, 56, 0, 4, 0, 41, 70, 27, 1, 17, 57, 0, 4, 0, 41, 71, 27, 1, 17, 58, 0, 4, 0, 41, 72, 27, 1, 17, 59, 0, 4, 0, 41, 73, 27, 1, 17, 60, 0, 4, 0, 41, 74, 27, 1, 17, 61, 0, 4, 0, 41, 75, 27, 1, 17, 62, 0, 4, 0, 41, 76, 27, 1, 17, 63, 0, 4, 0, 41, 77, 27, 1, 17, 64, 0, 4, 0, 41, 78, 27, 1, 17, 65, 0, 4, 0, 41, 79, 27, 1, 17, 66, 0, 4, 0, 41, 80, 27, 1, 17, 67, 0, 4, 0, 41, 81, 27, 1, 17, 68, 0, 4, 0, 41, 82, 27, 1, 17, 69, 0, 4, 0, 41, 83, 27, 1, 17, 70, 0, 4, 0, 41, 84, 27, 1, 17, 71, 0, 0, 0, 39, 85, -1, 1, 2, 0, 0, 49, 0, 87, 86, 72, 1, 17, 73, 0, 49, 0, 87, 88, 72, 1, 17, 74, 0, 49, 0, 87, 89, 72, 1, 17, 75, 0, 49, 0, 87, 90, 72, 1, 17, 76, 0, 0, 0, 87, 91, 77, 1, 17, 78, 0 </int_array> +			<int_array  len="873"> 				-1, -1, 1, 0, -1, 4, 2, 0, 3, 1, 4, 2, 5, 3, 0, 0, 0, 6, 6, -1, 14, 2, 0, 3, 1, 4, 2, 7, 4, 8, 5, 9, 5, 10, 6, 11, 7, 12, 2, 13, 2, 14, 2, 15, 8, 16, 9, 5, 10, 0, 0, 0, 17, 17, -1, 23, 2, 0, 3, 1, 18, 11, 4, 2, 19, 12, 20, 2, 21, 5, 22, 13, 23, 14, 24, 15, 25, 15, 26, 2, 27, 16, 28, 17, 29, 18, 30, 19, 31, 20, 32, 21, 33, 13, 34, 22, 35, 23, 36, 24, 37, 6, 0, 0, 0, 39, 38, -1, 4, 2, 0, 3, 1, 4, 2, 38, 25, 0, 0, 0, 41, 40, -1, 2, 2, 0, 5, 26, 0, 4, 0, 43, 42, 27, 4, 2, 0, 3, 1, 18, 28, 5, 29, 0, 4, 0, 43, 44, 27, 4, 2, 0, 3, 1, 18, 30, 5, 29, 0, 4, 0, 43, 45, 27, 4, 2, 0, 3, 1, 18, 31, 5, 29, 0, 4, 0, 43, 46, 27, 4, 2, 0, 3, 1, 18, 32, 5, 29, 0, 4, 0, 43, 47, 27, 4, 2, 0, 3, 1, 18, 33, 5, 29, 0, 4, 0, 43, 48, 27, 4, 2, 0, 3, 1, 18, 34, 5, 29, 0, 4, 0, 43, 49, 27, 4, 2, 0, 3, 1, 18, 35, 5, 29, 0, 4, 0, 43, 50, 27, 4, 2, 0, 3, 1, 18, 36, 5, 29, 0, 4, 0, 43, 51, 27, 4, 2, 0, 3, 1, 18, 37, 5, 29, 0, 4, 0, 43, 52, 27, 4, 2, 0, 3, 1, 18, 38, 5, 29, 0, 4, 0, 43, 53, 27, 4, 2, 0, 3, 1, 18, 39, 5, 29, 0, 4, 0, 43, 54, 27, 4, 2, 0, 3, 1, 18, 40, 5, 29, 0, 4, 0, 43, 55, 27, 4, 2, 0, 3, 1, 18, 41, 5, 29, 0, 4, 0, 43, 56, 27, 4, 2, 0, 3, 1, 18, 42, 5, 29, 0, 4, 0, 43, 57, 27, 4, 2, 0, 3, 1, 18, 43, 5, 29, 0, 4, 0, 43, 58, 27, 4, 2, 0, 3, 1, 18, 44, 5, 29, 0, 4, 0, 43, 59, 27, 4, 2, 0, 3, 1, 18, 45, 5, 29, 0, 4, 0, 43, 60, 27, 4, 2, 0, 3, 1, 18, 46, 5, 29, 0, 4, 0, 43, 61, 27, 4, 2, 0, 3, 1, 18, 47, 5, 29, 0, 4, 0, 43, 62, 27, 4, 2, 0, 3, 1, 18, 48, 5, 29, 0, 4, 0, 43, 63, 27, 4, 2, 0, 3, 1, 18, 49, 5, 29, 0, 4, 0, 43, 64, 27, 4, 2, 0, 3, 1, 18, 50, 5, 29, 0, 4, 0, 43, 65, 27, 4, 2, 0, 3, 1, 18, 51, 5, 29, 0, 4, 0, 43, 66, 27, 4, 2, 0, 3, 1, 18, 52, 5, 29, 0, 4, 0, 43, 67, 27, 4, 2, 0, 3, 1, 18, 53, 5, 29, 0, 4, 0, 43, 68, 27, 4, 2, 0, 3, 1, 18, 54, 5, 29, 0, 4, 0, 43, 69, 27, 4, 2, 0, 3, 1, 18, 55, 5, 29, 0, 4, 0, 43, 70, 27, 4, 2, 0, 3, 1, 18, 56, 5, 29, 0, 4, 0, 43, 71, 27, 4, 2, 0, 3, 1, 18, 57, 5, 29, 0, 4, 0, 43, 72, 27, 4, 2, 0, 3, 1, 18, 58, 5, 29, 0, 4, 0, 43, 73, 27, 4, 2, 0, 3, 1, 18, 59, 5, 29, 0, 4, 0, 43, 74, 27, 4, 2, 0, 3, 1, 18, 60, 5, 29, 0, 4, 0, 43, 75, 27, 4, 2, 0, 3, 1, 18, 61, 5, 29, 0, 4, 0, 43, 76, 27, 4, 2, 0, 3, 1, 18, 62, 5, 29, 0, 4, 0, 43, 77, 27, 4, 2, 0, 3, 1, 18, 63, 5, 29, 0, 4, 0, 43, 78, 27, 4, 2, 0, 3, 1, 18, 64, 5, 29, 0, 4, 0, 43, 79, 27, 4, 2, 0, 3, 1, 18, 65, 5, 29, 0, 4, 0, 43, 80, 27, 4, 2, 0, 3, 1, 18, 66, 5, 29, 0, 4, 0, 43, 81, 27, 4, 2, 0, 3, 1, 18, 67, 5, 29, 0, 4, 0, 43, 82, 27, 4, 2, 0, 3, 1, 18, 68, 5, 29, 0, 4, 0, 43, 83, 27, 4, 2, 0, 3, 1, 18, 69, 5, 29, 0, 4, 0, 43, 84, 27, 4, 2, 0, 3, 1, 18, 70, 5, 29, 0, 4, 0, 43, 85, 27, 4, 2, 0, 3, 1, 18, 71, 5, 29, 0, 4, 0, 43, 86, 27, 4, 2, 0, 3, 1, 18, 72, 5, 29, 0, 0, 0, 41, 87, -1, 1, 2, 0, 0, 49, 0, 89, 88, 73, 4, 2, 0, 3, 1, 18, 74, 5, 75, 0, 49, 0, 89, 90, 73, 4, 2, 0, 3, 1, 18, 76, 5, 75, 0, 49, 0, 89, 91, 73, 4, 2, 0, 3, 1, 18, 77, 5, 75, 0, 49, 0, 89, 92, 73, 4, 2, 0, 3, 1, 18, 78, 5, 75, 0, 0, 0, 89, 93, 79, 4, 2, 0, 3, 1, 18, 80, 5, 81, 0 </int_array>  			<string> "conns" </string>  			<int_array  len="0"> 				 </int_array>  		</dictionary> diff --git a/drivers/SCsub b/drivers/SCsub index 46334468ba..a1a2191cbc 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -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');
 diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 9cee702c05..e167b647e7 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -971,7 +971,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu -	if ((!texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) { +	if (!(texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) {  		texture->has_alpha=true;  	} @@ -2525,7 +2525,7 @@ Error RasterizerGLES2::_surface_set_arrays(Surface *p_surface, uint8_t *p_mem,ui  void RasterizerGLES2::mesh_add_custom_surface(RID p_mesh,const Variant& p_dat) {  	ERR_EXPLAIN("OpenGL Rasterizer does not support custom surfaces. Running on wrong platform?"); -	ERR_FAIL_V(); +	ERR_FAIL();  }  Array RasterizerGLES2::mesh_get_surface_arrays(RID p_mesh,int p_surface) const { @@ -4038,8 +4038,16 @@ void RasterizerGLES2::render_target_set_size(RID p_render_target,int p_width,int  	glGenTextures(1, &rt->color);  	glBindTexture(GL_TEXTURE_2D, rt->color);  	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,  rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + +	if (rt->texture_ptr->flags&VS::TEXTURE_FLAG_FILTER) { + +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +	} else { + +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +	}  	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); @@ -4108,6 +4116,10 @@ void RasterizerGLES2::begin_frame() {  	shadow_filter=ShadowFilterTechnique(int(Globals::get_singleton()->get("rasterizer/shadow_filter")));  #endif +	canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_PCF5,shadow_filter==SHADOW_FILTER_PCF5); +	canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_PCF13,shadow_filter==SHADOW_FILTER_PCF13); +	canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_ESM,shadow_filter==SHADOW_FILTER_ESM); +  	window_size = Size2( OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height );  	double time = (OS::get_singleton()->get_ticks_usec()/1000); // get msec @@ -4272,7 +4284,7 @@ void RasterizerGLES2::clear_viewport(const Color& p_color) {  	}  	glEnable(GL_SCISSOR_TEST); -	glClearColor(p_color.r,p_color.g,p_color.b,1.0); +	glClearColor(p_color.r,p_color.g,p_color.b,p_color.a);  	glClear(GL_COLOR_BUFFER_BIT); //should not clear if anything else cleared..  	glDisable(GL_SCISSOR_TEST);  }; @@ -4588,6 +4600,9 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {  			enablers.push_back("#define USE_TEXPIXEL_SIZE\n");  		} +		if (vertex_flags.uses_worldvec) { +			enablers.push_back("#define USE_WORLD_VEC\n"); +		}  		canvas_shader.set_custom_shader_code(p_shader->custom_code_id,vertex_code, vertex_globals,fragment_code, light_code, fragment_globals,uniform_names,enablers);  		//postprocess_shader.set_custom_shader_code(p_shader->custom_code_id,vertex_code, vertex_globals,fragment_code, fragment_globals,uniform_names); @@ -5108,8 +5123,10 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material  		int texcoord=0;  		for (Map<StringName,Material::UniformData>::Element *E=p_material->shader_params.front();E;E=E->next()) { +  			if (E->get().index<0)  				continue; +//			print_line(String(E->key())+": "+E->get().value);  			if (E->get().istexture) {  				//clearly a texture..  				RID rid = E->get().value; @@ -5489,13 +5506,15 @@ Error RasterizerGLES2::_setup_geometry(const Geometry *p_geometry, const Materia  				base = surf->array_local;  				glBindBuffer(GL_ARRAY_BUFFER, 0);  				bool can_copy_to_local=surf->local_stride * surf->array_len <= skinned_buffer_size; +				if (p_morphs && surf->stride * surf->array_len > skinned_buffer_size) +					can_copy_to_local=false; + +  				if (!can_copy_to_local)  					skeleton_valid=false; -  				/* compute morphs */ -  				if (p_morphs && surf->morph_target_count && can_copy_to_local) { @@ -6383,7 +6402,12 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans  					 case VS::MATERIAL_BLEND_MODE_MIX: {  						glBlendEquation(GL_FUNC_ADD); -						glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); +						if (current_rt && current_rt_transparent) { +							glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +						} +						else { +							glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +						}  					 } break;  					 case VS::MATERIAL_BLEND_MODE_ADD: { @@ -6394,12 +6418,17 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans  					 } break;  					 case VS::MATERIAL_BLEND_MODE_SUB: { -						glBlendEquation(GL_FUNC_SUBTRACT); +						glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);  						glBlendFunc(GL_SRC_ALPHA,GL_ONE);  					 } break;  					case VS::MATERIAL_BLEND_MODE_MUL: {  						glBlendEquation(GL_FUNC_ADD); -						glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); +						if (current_rt && current_rt_transparent) { +							glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +						} +						else { +							glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +						}  					} break; @@ -6666,7 +6695,12 @@ void RasterizerGLES2::_copy_to_texscreen() {  #endif  	glDisable(GL_BLEND);  	glBlendEquation(GL_FUNC_ADD); -	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +	if (current_rt && current_rt_transparent) { +		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +	} +	else { +		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +	}  	//glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);  	glBindBuffer(GL_ARRAY_BUFFER,0);  	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); @@ -7140,7 +7174,12 @@ void RasterizerGLES2::end_scene() {  	current_depth_mask=true;  	texscreen_copied=false;  	glBlendEquation(GL_FUNC_ADD); -	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +	if (current_rt && current_rt_transparent) { +		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +	} +	else { +		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +	}  	glDisable(GL_BLEND);  	current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX; @@ -7157,7 +7196,12 @@ void RasterizerGLES2::end_scene() {  	}  	glBlendEquation(GL_FUNC_ADD); -	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +	if (current_rt && current_rt_transparent) { +		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +	} +	else { +		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +	}  	glDisable(GL_BLEND);  	current_blend_mode=VS::MATERIAL_BLEND_MODE_MIX;  	material_shader.set_conditional(MaterialShaderGLES2::USE_GLOW,false); @@ -7794,7 +7838,12 @@ void RasterizerGLES2::canvas_begin() {  #endif  	glEnable(GL_BLEND);  	glBlendEquation(GL_FUNC_ADD); -	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +	if (current_rt && current_rt_transparent) { +		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +	} +	else { +		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +	}  	//glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);  	glLineWidth(1.0);  	glBindBuffer(GL_ARRAY_BUFFER,0); @@ -7809,8 +7858,10 @@ void RasterizerGLES2::canvas_begin() {  	//material_shader.unbind();  	canvas_shader.unbind();  	canvas_shader.set_custom_shader(0); +	canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,false);  	canvas_shader.bind();  	canvas_shader.set_uniform(CanvasShaderGLES2::TEXTURE, 0); +	canvas_use_modulate=false;  	_set_color_attrib(Color(1,1,1));  	canvas_transform=Transform();  	canvas_transform.translate(-(viewport.width / 2.0f), -(viewport.height / 2.0f), 0.0f); @@ -7825,10 +7876,10 @@ void RasterizerGLES2::canvas_begin() {  	canvas_opacity=1.0;  	canvas_blend_mode=VS::MATERIAL_BLEND_MODE_MIX; -  	canvas_texscreen_used=false;  	uses_texpixel_size=false; -	canvas_last_shader=RID(); + +	canvas_last_material=NULL;  } @@ -7850,7 +7901,12 @@ void RasterizerGLES2::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) {  		 case VS::MATERIAL_BLEND_MODE_MIX: {  			glBlendEquation(GL_FUNC_ADD); -			glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); +			if (current_rt && current_rt_transparent) { +				glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +			} +			else { +				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +			}  		 } break;  		 case VS::MATERIAL_BLEND_MODE_ADD: { @@ -7861,7 +7917,7 @@ void RasterizerGLES2::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) {  		 } break;  		 case VS::MATERIAL_BLEND_MODE_SUB: { -			glBlendEquation(GL_FUNC_SUBTRACT); +			glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);  			glBlendFunc(GL_SRC_ALPHA,GL_ONE);  		 } break;  		case VS::MATERIAL_BLEND_MODE_MUL: { @@ -8088,7 +8144,7 @@ void RasterizerGLES2::_draw_gui_primitive2(int p_points, const Vector2 *p_vertic  	_rinfo.ci_draw_commands++;  } -void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip, bool p_v_flip ) { +void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_src_region, const Size2& p_tex_size,bool p_h_flip, bool p_v_flip, bool p_transpose ) {  	Vector2 texcoords[4]= {  		Vector2( p_src_region.pos.x/p_tex_size.width, @@ -8104,6 +8160,9 @@ void RasterizerGLES2::_draw_textured_quad(const Rect2& p_rect, const Rect2& p_sr  		(p_src_region.pos.y+p_src_region.size.height)/p_tex_size.height)  	}; +	if (p_transpose) { +		SWAP( texcoords[1], texcoords[3] ); +	}  	if (p_h_flip) {  		SWAP( texcoords[0], texcoords[1] );  		SWAP( texcoords[2], texcoords[3] ); @@ -8151,11 +8210,11 @@ void RasterizerGLES2::canvas_draw_rect(const Rect2& p_rect, int p_flags, const R  		if (!(p_flags&CANVAS_RECT_REGION)) {  			Rect2 region = Rect2(0,0,texture->width,texture->height); -			_draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V); +			_draw_textured_quad(p_rect,region,region.size,p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V,p_flags&CANVAS_RECT_TRANSPOSE);  		} else { -			_draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V ); +			_draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V,p_flags&CANVAS_RECT_TRANSPOSE);  		}  	} else { @@ -8310,13 +8369,739 @@ void RasterizerGLES2::canvas_set_transform(const Matrix32& p_transform) {  	//canvas_transform = Variant(p_transform);  } +RID RasterizerGLES2::canvas_light_occluder_create() { + +	CanvasOccluder *co = memnew( CanvasOccluder ); +	co->index_id=0; +	co->vertex_id=0; +	co->len=0; + +	return canvas_occluder_owner.make_rid(co); +} + +void RasterizerGLES2::canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines) { + +	CanvasOccluder *co = canvas_occluder_owner.get(p_occluder); +	ERR_FAIL_COND(!co); + +	co->lines=p_lines; + +	if (p_lines.size()!=co->len) { + +		if (co->index_id) +			glDeleteBuffers(1,&co->index_id); +		if (co->vertex_id) +			glDeleteBuffers(1,&co->vertex_id); + +		co->index_id=0; +		co->vertex_id=0; +		co->len=0; + +	} + +	if (p_lines.size()) { + + + +		DVector<float> geometry; +		DVector<uint16_t> indices; +		int lc = p_lines.size(); + +		geometry.resize(lc*6); +		indices.resize(lc*3); + +		DVector<float>::Write vw=geometry.write(); +		DVector<uint16_t>::Write iw=indices.write(); + + +		DVector<Vector2>::Read lr=p_lines.read(); + +		const int POLY_HEIGHT = 16384; + +		for(int i=0;i<lc/2;i++) { + +			vw[i*12+0]=lr[i*2+0].x; +			vw[i*12+1]=lr[i*2+0].y; +			vw[i*12+2]=POLY_HEIGHT; + +			vw[i*12+3]=lr[i*2+1].x; +			vw[i*12+4]=lr[i*2+1].y; +			vw[i*12+5]=POLY_HEIGHT; + +			vw[i*12+6]=lr[i*2+1].x; +			vw[i*12+7]=lr[i*2+1].y; +			vw[i*12+8]=-POLY_HEIGHT; + +			vw[i*12+9]=lr[i*2+0].x; +			vw[i*12+10]=lr[i*2+0].y; +			vw[i*12+11]=-POLY_HEIGHT; + +			iw[i*6+0]=i*4+0; +			iw[i*6+1]=i*4+1; +			iw[i*6+2]=i*4+2; + +			iw[i*6+3]=i*4+2; +			iw[i*6+4]=i*4+3; +			iw[i*6+5]=i*4+0; + +		} + +		//if same buffer len is being set, just use BufferSubData to avoid a pipeline flush + + +		if (!co->vertex_id) { +			glGenBuffers(1,&co->vertex_id); +			glBindBuffer(GL_ARRAY_BUFFER,co->vertex_id); +			glBufferData(GL_ARRAY_BUFFER,lc*6*sizeof(real_t),vw.ptr(),GL_STATIC_DRAW); +		} else { + +			glBindBuffer(GL_ARRAY_BUFFER,co->vertex_id); +			glBufferSubData(GL_ARRAY_BUFFER,0,lc*6*sizeof(real_t),vw.ptr()); + +		} + +		glBindBuffer(GL_ARRAY_BUFFER,0); //unbind + +		if (!co->index_id) { + +			glGenBuffers(1,&co->index_id); +			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,co->index_id); +			glBufferData(GL_ELEMENT_ARRAY_BUFFER,lc*3*sizeof(uint16_t),iw.ptr(),GL_STATIC_DRAW); +		} else { + + +			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,co->index_id); +			glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,lc*3*sizeof(uint16_t),iw.ptr()); +		} + +		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); //unbind + +		co->len=lc; + +	} + + + +} + +RID RasterizerGLES2::canvas_light_shadow_buffer_create(int p_width) { + +	CanvasLightShadow *cls = memnew( CanvasLightShadow ); +	if (p_width>max_texture_size) +		p_width=max_texture_size; + +	cls->size=p_width; +	glActiveTexture(GL_TEXTURE0); + +	glGenFramebuffers(1, &cls->fbo); +	glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + +	// Create a render buffer +	glGenRenderbuffers(1, &cls->rbo); +	glBindRenderbuffer(GL_RENDERBUFFER, cls->rbo); + +	// Create a texture for storing the depth +	glGenTextures(1, &cls->depth); +	glBindTexture(GL_TEXTURE_2D, cls->depth); +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + +	// Remove artifact on the edges of the shadowmap +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + +	cls->height=16; + +	//print_line("ERROR? "+itos(glGetError())); +	if ( read_depth_supported ) { + +		// We'll use a depth texture to store the depths in the shadow map +		glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, cls->size, cls->height, 0, +			     GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + +#ifdef GLEW_ENABLED +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#endif + +		// Attach the depth texture to FBO depth attachment point +		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, +				       GL_TEXTURE_2D, cls->depth, 0); + +#ifdef GLEW_ENABLED +		glDrawBuffer(GL_NONE); +#endif +	} else { +		// We'll use a RGBA texture into which we pack the depth info +		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0, +			     GL_RGBA, GL_UNSIGNED_BYTE, NULL); -void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) { +		// Attach the RGBA texture to FBO color attachment point +		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, +				       GL_TEXTURE_2D, cls->depth, 0); + +		// Allocate 16-bit depth buffer +		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height); + +		// Attach the render buffer as depth buffer - will be ignored +		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, +					  GL_RENDERBUFFER, cls->rbo); + + +	} + +	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); +	//printf("errnum: %x\n",status); +#ifdef GLEW_ENABLED +	if (read_depth_supported) { +		glDrawBuffer(GL_BACK); +	} +#endif +	glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer); +	DEBUG_TEST_ERROR("2D Shadow Buffer Init"); +	ERR_FAIL_COND_V( status != GL_FRAMEBUFFER_COMPLETE, RID() ); + +#ifdef GLEW_ENABLED +	if (read_depth_supported) { +		glDrawBuffer(GL_BACK); +	} +#endif + +	return canvas_light_shadow_owner.make_rid(cls); +} + +void RasterizerGLES2::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) { + +	CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_buffer); +	ERR_FAIL_COND(!cls); + + +	glDisable(GL_BLEND); +	glDisable(GL_SCISSOR_TEST); +	glDisable(GL_DITHER); +	glDisable(GL_CULL_FACE); +	glDepthFunc(GL_LEQUAL); +	glEnable(GL_DEPTH_TEST); +	glDepthMask(true); + +	glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + +	if (!use_rgba_shadowmaps) +		glColorMask(0, 0, 0, 0); + +	glEnableVertexAttribArray(VS::ARRAY_VERTEX); +	canvas_shadow_shader.bind(); + +	const int vp_height = 10; + +	glViewport(0, 0, cls->size,cls->height); +	_glClearDepth(1.0f); +	glClearColor(1,1,1,1); +	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + +	VS::CanvasOccluderPolygonCullMode cull=VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; + + +	for(int i=0;i<4;i++) { + +		//make sure it remains orthogonal, makes easy to read angle later + +		Transform light; +		light.origin[0]=p_light_xform[2][0]; +		light.origin[1]=p_light_xform[2][1]; +		light.basis[0][0]=p_light_xform[0][0]; +		light.basis[0][1]=p_light_xform[1][0]; +		light.basis[1][0]=p_light_xform[0][1]; +		light.basis[1][1]=p_light_xform[1][1]; + +		//light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); + +	///	p_near=1; +		CameraMatrix projection; +		{ +			real_t fov =  90; +			real_t near = p_near; +			real_t far = p_far; +			real_t aspect = 1.0; + +			real_t ymax = near * Math::tan( Math::deg2rad( fov * 0.5 ) ); +			real_t ymin = - ymax; +			real_t xmin = ymin * aspect; +			real_t xmax = ymax * aspect; + +			projection.set_frustum( xmin, xmax, ymin, ymax, near, far ); +		} + +		Vector3 cam_target=Matrix3(Vector3(0,0,Math_PI*2*(i/4.0))).xform(Vector3(0,1,0)); +		projection = projection * CameraMatrix(Transform().looking_at(cam_target,Vector3(0,0,-1)).affine_inverse()); + +		//print_line("near: "+rtos(p_near)); +		//print_line("far: "+rtos(p_far)); +		//projection.set_perspective(60,size/float(vp_height),p_near,p_far); + +	//	CameraMatrix light_mat = projection * CameraMatrix(camera); + +		canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::PROJECTION_MATRIX,projection); +		canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::LIGHT_MATRIX,light); + +		if (i==0) +			*p_xform_cache=projection; + +		glViewport(0, (cls->height/4)*i, cls->size,cls->height/4); + +		CanvasLightOccluderInstance *instance=p_occluders; + +		while(instance) { + +			CanvasOccluder *cc = canvas_occluder_owner.get(instance->polygon_buffer); +			if (!cc || cc->len==0 || !(p_light_mask&instance->light_mask)) { + +				instance=instance->next; +				continue; +			} + +			canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::WORLD_MATRIX,instance->xform_cache); +			if (cull!=instance->cull_cache) { + +				cull=instance->cull_cache; +				switch(cull) { +					case VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: { + +						glDisable(GL_CULL_FACE); + +					} break; +					case VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: { + +						glEnable(GL_CULL_FACE); +						glCullFace(GL_FRONT); +					} break; +					case VS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: { + +						glEnable(GL_CULL_FACE); +						glCullFace(GL_BACK); + +					} break; +				} +			} +/* +			if (i==0) { +				for(int i=0;i<cc->lines.size();i++) { +					Vector2 p = instance->xform_cache.xform(cc->lines.get(i)); +					Plane pp(Vector3(p.x,p.y,0),1); +					pp.normal = light.xform(pp.normal); +					pp = projection.xform4(pp); +					print_line(itos(i)+": "+pp.normal/pp.d); +					//pp=light_mat.xform4(pp); +					//print_line(itos(i)+": "+pp.normal/pp.d); +				} +			} +*/ +			glBindBuffer(GL_ARRAY_BUFFER,cc->vertex_id); +			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,cc->index_id); +			glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0); +			glDrawElements(GL_TRIANGLES,cc->len*3,GL_UNSIGNED_SHORT,0); + + +			instance=instance->next; +		} + + +	} + +	glDisableVertexAttribArray(VS::ARRAY_VERTEX); +	glBindBuffer(GL_ARRAY_BUFFER,0); +	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); + +	if (shadow_filter==SHADOW_FILTER_ESM) { +		//blur the buffer +#if 0 +	//this is ignord, it did not make any difference.. +		if (read_depth_supported) { +			glDepthFunc(GL_ALWAYS); +		} else { +			glDisable(GL_DEPTH_TEST); +			glDepthMask(false); +		} +		glDisable(GL_CULL_FACE); +		glViewport(0, 0, cls->size,cls->height); + +		int passes=1; +		CanvasLightShadow *blur = canvas_light_shadow_owner.get(canvas_shadow_blur); + +		copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,true); +		copy_shader.bind(); +		copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SCALE,1); +		copy_shader.set_uniform(CopyShaderGLES2::BLUR_MAGNITUDE,1); +		glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0); + +		for(int i=0;i<passes;i++) { + +			glBindFramebuffer(GL_FRAMEBUFFER, blur->fbo); +			glActiveTexture(GL_TEXTURE0); + +			if (read_depth_supported) +				glBindTexture(GL_TEXTURE_2D,cls->depth); +			else +				glBindTexture(GL_TEXTURE_2D,cls->rgba); + + +			{ +				Vector2 src_sb_uv[4]={ +					Vector2( 0, 1), +					Vector2( 1, 1), +					Vector2( 1, 0), +					Vector2( 0, 0) +				}; +				static const Vector2 dst_pos[4]={ +					Vector2(-1, 1), +					Vector2( 1, 1), +					Vector2( 1,-1), +					Vector2(-1,-1) +				}; + + + +				copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Vector2(1.0,1.0)/cls->size); +				_draw_gui_primitive(4,dst_pos,NULL,src_sb_uv); +			} + +			glActiveTexture(GL_TEXTURE0); +			if (read_depth_supported) +				glBindTexture(GL_TEXTURE_2D,blur->depth); +			else +				glBindTexture(GL_TEXTURE_2D,blur->rgba); + +			glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + +			{ +				float hlimit = float(cls->size) / blur->size; +				//hlimit*=2.0; +				Vector2 src_sb_uv[4]={ +					Vector2( 0, 1), +					Vector2( hlimit, 1), +					Vector2( hlimit, 0), +					Vector2( 0, 0) +				}; +				static const Vector2 dst_pos[4]={ +					Vector2(-1, 1), +					Vector2( 1, 1), +					Vector2( 1,-1), +					Vector2(-1,-1) +				}; + + +				copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,Vector2(1.0,1.0)/blur->size); +				_draw_gui_primitive(4,dst_pos,NULL,src_sb_uv); +			} + +		} +		copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,false); +		glDepthFunc(GL_LEQUAL); +#endif +	} + +	glBindFramebuffer(GL_FRAMEBUFFER, current_rt?current_rt->fbo:base_framebuffer); +	glColorMask(1, 1, 1, 1); + + + +} + + +void RasterizerGLES2::canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow) { + +	CanvasLight* light=p_lights_with_shadow; + +	canvas_begin(); //reset + +	int h = 10; +	int w = viewport.width; +	int ofs = h; +	while(light) { + +		if (light->shadow_buffer.is_valid()) { + +			CanvasLightShadow * sb = canvas_light_shadow_owner.get(light->shadow_buffer); +			if (sb) { +				glActiveTexture(GL_TEXTURE0); +				if (read_depth_supported) +					glBindTexture(GL_TEXTURE_2D,sb->depth); +				else +					glBindTexture(GL_TEXTURE_2D,sb->rgba); +				_draw_textured_quad(Rect2(h,ofs,w-h*2,h),Rect2(0,0,sb->size,10),Size2(sb->size,10),false,false); +				ofs+=h*2; + +			} +		} + +		light=light->shadows_next_ptr; +	} + +} + +void RasterizerGLES2::_canvas_normal_set_flip(const Vector2& p_flip) { + +	if (p_flip==normal_flip) +		return; +	normal_flip=p_flip; +	canvas_shader.set_uniform(CanvasShaderGLES2::NORMAL_FLIP,normal_flip); +} + + +template<bool use_normalmap> +void RasterizerGLES2::_canvas_item_render_commands(CanvasItem *p_item,CanvasItem *current_clip,bool &reclip) { + +	int cc=p_item->commands.size(); +	CanvasItem::Command **commands = p_item->commands.ptr(); + + +	for(int i=0;i<cc;i++) { + +		CanvasItem::Command *c=commands[i]; + +		switch(c->type) { +			case CanvasItem::Command::TYPE_LINE: { + +				CanvasItem::CommandLine* line = static_cast<CanvasItem::CommandLine*>(c); +				canvas_draw_line(line->from,line->to,line->color,line->width); +			} break; +			case CanvasItem::Command::TYPE_RECT: { + +				CanvasItem::CommandRect* rect = static_cast<CanvasItem::CommandRect*>(c); +//						canvas_draw_rect(rect->rect,rect->region,rect->source,rect->flags&CanvasItem::CommandRect::FLAG_TILE,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V,rect->texture,rect->modulate); +#if 0 +				int flags=0; + +				if (rect->flags&CanvasItem::CommandRect::FLAG_REGION) { +					flags|=Rasterizer::CANVAS_RECT_REGION; +				} +				if (rect->flags&CanvasItem::CommandRect::FLAG_TILE) { +					flags|=Rasterizer::CANVAS_RECT_TILE; +				} +				if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H) { + +					flags|=Rasterizer::CANVAS_RECT_FLIP_H; +				} +				if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V) { + +					flags|=Rasterizer::CANVAS_RECT_FLIP_V; +				} +#else + +				int flags=rect->flags; +#endif +				if (use_normalmap) +					_canvas_normal_set_flip(Vector2((flags&CANVAS_RECT_FLIP_H)?-1:1,(flags&CANVAS_RECT_FLIP_V)?-1:1)); +				canvas_draw_rect(rect->rect,flags,rect->source,rect->texture,rect->modulate); + +			} break; +			case CanvasItem::Command::TYPE_STYLE: { + +				CanvasItem::CommandStyle* style = static_cast<CanvasItem::CommandStyle*>(c); +				if (use_normalmap) +					_canvas_normal_set_flip(Vector2(1,1)); +				canvas_draw_style_box(style->rect,style->texture,style->margin,style->draw_center,style->color); + +			} break; +			case CanvasItem::Command::TYPE_PRIMITIVE: { + +				if (use_normalmap) +					_canvas_normal_set_flip(Vector2(1,1)); +				CanvasItem::CommandPrimitive* primitive = static_cast<CanvasItem::CommandPrimitive*>(c); +				canvas_draw_primitive(primitive->points,primitive->colors,primitive->uvs,primitive->texture,primitive->width); +			} break; +			case CanvasItem::Command::TYPE_POLYGON: { + +				if (use_normalmap) +					_canvas_normal_set_flip(Vector2(1,1)); +				CanvasItem::CommandPolygon* polygon = static_cast<CanvasItem::CommandPolygon*>(c); +				canvas_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1); + +			} break; + +			case CanvasItem::Command::TYPE_POLYGON_PTR: { + +				if (use_normalmap) +					_canvas_normal_set_flip(Vector2(1,1)); +				CanvasItem::CommandPolygonPtr* polygon = static_cast<CanvasItem::CommandPolygonPtr*>(c); +				canvas_draw_polygon(polygon->count,polygon->indices,polygon->points,polygon->uvs,polygon->colors,polygon->texture,false); +			} break; +			case CanvasItem::Command::TYPE_CIRCLE: { + +				CanvasItem::CommandCircle* circle = static_cast<CanvasItem::CommandCircle*>(c); +				static const int numpoints=32; +				Vector2 points[numpoints+1]; +				points[numpoints]=circle->pos; +				int indices[numpoints*3]; + +				for(int i=0;i<numpoints;i++) { + +					points[i]=circle->pos+Vector2( Math::sin(i*Math_PI*2.0/numpoints),Math::cos(i*Math_PI*2.0/numpoints) )*circle->radius; +					indices[i*3+0]=i; +					indices[i*3+1]=(i+1)%numpoints; +					indices[i*3+2]=numpoints; +				} +				canvas_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true); +				//canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1); +			} break; +			case CanvasItem::Command::TYPE_TRANSFORM: { + +				CanvasItem::CommandTransform* transform = static_cast<CanvasItem::CommandTransform*>(c); +				canvas_set_transform(transform->xform); +			} break; +			case CanvasItem::Command::TYPE_BLEND_MODE: { + +				CanvasItem::CommandBlendMode* bm = static_cast<CanvasItem::CommandBlendMode*>(c); +				canvas_set_blend_mode(bm->blend_mode); + +			} break; +			case CanvasItem::Command::TYPE_CLIP_IGNORE: { + +				CanvasItem::CommandClipIgnore* ci = static_cast<CanvasItem::CommandClipIgnore*>(c); +				if (current_clip) { + +					if (ci->ignore!=reclip) { +						if (ci->ignore) { + +							glDisable(GL_SCISSOR_TEST); +							reclip=true; +						} else  { + +							glEnable(GL_SCISSOR_TEST); +							glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)), +							current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height); +							reclip=false; +						} +					} +				} + + + +			} break; +		} +	} + +} + +void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *material,Shader* shader) { + +	if (canvas_shader.bind()) +		rebind_texpixel_size=true; + +	if (material->shader_version!=shader->version) { +		//todo optimize uniforms +		material->shader_version=shader->version; +	} + +	if (shader->has_texscreen && framebuffer.active) { + +		int x = viewport.x; +		int y = window_size.height-(viewport.height+viewport.y); + +		canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height)); +		canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height)); +		canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_TEX,max_texture_units-1); +		glActiveTexture(GL_TEXTURE0+max_texture_units-1); +		glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color); +		if (framebuffer.scale==1 && !canvas_texscreen_used) { +#ifdef GLEW_ENABLED +			glReadBuffer(GL_COLOR_ATTACHMENT0); +#endif +			glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,viewport.width,viewport.height); +//			if (current_clip) { +//			//	print_line(" a clip "); +//			} + +			canvas_texscreen_used=true; +		} + +		glActiveTexture(GL_TEXTURE0); + +	} + +	if (shader->has_screen_uv) { +		canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_UV_MULT,Vector2(1.0/viewport.width,1.0/viewport.height)); +	} + + +	uses_texpixel_size=shader->uses_texpixel_size; + +} + +void RasterizerGLES2::_canvas_item_setup_shader_uniforms(CanvasItemMaterial *material,Shader* shader) { + +	//this can be optimized.. +	int tex_id=1; +	int idx=0; +	for(Map<StringName,ShaderLanguage::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) { + +		Map<StringName,Variant>::Element *F=material->shader_param.find(E->key()); + +		if ((E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP)) { + +			RID rid; +			if (F) { +				rid=F->get(); +			} + +			if (!rid.is_valid()) { + +				Map<StringName,RID>::Element *DT=shader->default_textures.find(E->key()); +				if (DT) { +					rid=DT->get(); +				} +			} + +			if (rid.is_valid()) { + +				int loc = canvas_shader.get_custom_uniform_location(idx); //should be automatic.. + +				glActiveTexture(GL_TEXTURE0+tex_id); +				Texture *t=texture_owner.get(rid); +				if (!t) +					glBindTexture(GL_TEXTURE_2D,white_tex); +				else +					glBindTexture(t->target,t->tex_id); + +				glUniform1i(loc,tex_id); +				tex_id++; +			} +		} else { +			Variant &v=F?F->get():E->get().default_value; +			canvas_shader.set_custom_uniform(idx,v); +		} + +		idx++; +	} + +	if (tex_id>1) { +		glActiveTexture(GL_TEXTURE0); +	} + +	if (shader->uses_time) { +		canvas_shader.set_uniform(CanvasShaderGLES2::TIME,Math::fmod(last_time,300.0)); +		draw_next_frame=true; +	} +		//if uses TIME - draw_next_frame=true + + +} + +void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light) {  	CanvasItem *current_clip=NULL; +	Shader *shader_cache=NULL; + +	bool rebind_shader=true;  	canvas_opacity=1.0; +	canvas_use_modulate=p_modulate!=Color(1,1,1,1); +	canvas_modulate=p_modulate; +	canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate); + +	bool reset_modulate=false; +  	while(p_item_list) {  		CanvasItem *ci=p_item_list; @@ -8326,8 +9111,15 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {  				draw_viewport_func(ci->vp_render->owner,ci->vp_render->udata,ci->vp_render->rect);  			}  			memdelete(ci->vp_render); -			ci->vp_render=NULL; -			canvas_last_shader=RID(); +			ci->vp_render=NULL;			 +			canvas_last_material=NULL; +			canvas_use_modulate=p_modulate!=Color(1,1,1,1); +			canvas_modulate=p_modulate; +			canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate); +			rebind_shader=true; +			reset_modulate=true; + +  		}  		if (current_clip!=ci->final_clip_owner) { @@ -8348,98 +9140,26 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {  		//begin rect -		CanvasItem *shader_owner = ci->shader_owner?ci->shader_owner:ci; +		CanvasItem *material_owner = ci->material_owner?ci->material_owner:ci; +		CanvasItemMaterial *material = material_owner->material; -		if (shader_owner->shader!=canvas_last_shader) { +		if (material!=canvas_last_material || rebind_shader) {  			Shader *shader = NULL; -			if (shader_owner->shader.is_valid()) { -				shader = this->shader_owner.get(shader_owner->shader); +			if (material && material->shader.is_valid()) { +				shader = shader_owner.get(material->shader);  				if (shader && !shader->valid) {  					shader=NULL;  				}  			} +			shader_cache=shader; +  			if (shader) {  				canvas_shader.set_custom_shader(shader->custom_code_id); -				if (canvas_shader.bind()) -					rebind_texpixel_size=true; - -				if (shader_owner->shader_version!=shader->version) { -					//todo optimize uniforms -					shader_owner->shader_version=shader->version; -				} -				//this can be optimized.. -				int tex_id=1; -				int idx=0; -				for(Map<StringName,ShaderLanguage::Uniform>::Element *E=shader->uniforms.front();E;E=E->next()) { - - -					Map<StringName,Variant>::Element *F=shader_owner->shader_param.find(E->key()); -					Variant &v=F?F->get():E->get().default_value; -					if (v.get_type()==Variant::_RID || v.get_type()==Variant::OBJECT) { -						int loc = canvas_shader.get_custom_uniform_location(idx); //should be automatic.. - -						glActiveTexture(GL_TEXTURE0+tex_id); -						RID tex = v; -						Texture *t=texture_owner.get(tex); -						if (!t) -							glBindTexture(GL_TEXTURE_2D,white_tex); -						else -							glBindTexture(t->target,t->tex_id); - -						glUniform1i(loc,tex_id); -						tex_id++; - -					} else { -						canvas_shader.set_custom_uniform(idx,v); -					} - -					idx++; -				} - - -				if (shader->has_texscreen && framebuffer.active) { - -					int x = viewport.x; -					int y = window_size.height-(viewport.height+viewport.y); - -					canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height)); -					canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_SCREEN_CLAMP,Color(float(x)/framebuffer.width,float(y)/framebuffer.height,float(x+viewport.width)/framebuffer.width,float(y+viewport.height)/framebuffer.height)); -					canvas_shader.set_uniform(CanvasShaderGLES2::TEXSCREEN_TEX,tex_id); -					glActiveTexture(GL_TEXTURE0+tex_id); -					glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color); -					if (framebuffer.scale==1 && !canvas_texscreen_used) { -#ifdef GLEW_ENABLED -						glReadBuffer(GL_COLOR_ATTACHMENT0); -#endif -						glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,viewport.width,viewport.height); -						if (current_clip) { -							print_line(" a clip "); -						} - -						canvas_texscreen_used=true; -					} -					tex_id++; - -				} - -				if (tex_id>1) { -					glActiveTexture(GL_TEXTURE0); -				} -				if (shader->has_screen_uv) { -					canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_UV_MULT,Vector2(1.0/viewport.width,1.0/viewport.height)); -				} - -				if (shader->uses_time) { -					canvas_shader.set_uniform(CanvasShaderGLES2::TIME,Math::fmod(last_time,300.0)); -					draw_next_frame=true; -				} -					//if uses TIME - draw_next_frame=true - -				uses_texpixel_size=shader->uses_texpixel_size; - +				_canvas_item_setup_shader_params(material,shader);  			} else { +				shader_cache=NULL;  				canvas_shader.set_custom_shader(0);  				canvas_shader.bind();  				uses_texpixel_size=false; @@ -8448,9 +9168,27 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {  			canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX,canvas_transform); -			canvas_last_shader=shader_owner->shader; +			if (canvas_use_modulate) +				reset_modulate=true; +			canvas_last_material=material; +			rebind_shader=false; +		} + +		if (material && shader_cache) { + +			_canvas_item_setup_shader_uniforms(material,shader_cache); +		} + +		if (material && material->unshaded) { +			canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,Color(1,1,1,1)); +			reset_modulate=true; +		} else if (reset_modulate) { +			canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate); +			reset_modulate=false;  		} + +  		canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform);  		canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32()); @@ -8463,7 +9201,12 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {  				 case VS::MATERIAL_BLEND_MODE_MIX: {  					glBlendEquation(GL_FUNC_ADD); -					glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); +					if (current_rt && current_rt_transparent) { +						glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +					} +					else { +						glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +					}  				 } break;  				 case VS::MATERIAL_BLEND_MODE_ADD: { @@ -8474,7 +9217,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {  				 } break;  				 case VS::MATERIAL_BLEND_MODE_SUB: { -					glBlendEquation(GL_FUNC_SUBTRACT); +					glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);  					glBlendFunc(GL_SRC_ALPHA,GL_ONE);  				 } break;  				case VS::MATERIAL_BLEND_MODE_MUL: { @@ -8491,128 +9234,140 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list) {  			canvas_blend_mode=ci->blend_mode;  		} -		int cc=ci->commands.size(); -		CanvasItem::Command **commands = ci->commands.ptr(); -  		canvas_opacity = ci->final_opacity; -		for(int i=0;i<cc;i++) { +		_canvas_item_render_commands<false>(ci,current_clip,reclip); -			CanvasItem::Command *c=commands[i]; +		if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light && (!material || !material->unshaded)) { -			switch(c->type) { -				case CanvasItem::Command::TYPE_LINE: { +			CanvasLight *light = p_light; +			bool light_used=false; +			bool subtract=false; -					CanvasItem::CommandLine* line = static_cast<CanvasItem::CommandLine*>(c); -					canvas_draw_line(line->from,line->to,line->color,line->width); -				} break; -				case CanvasItem::Command::TYPE_RECT: { -					CanvasItem::CommandRect* rect = static_cast<CanvasItem::CommandRect*>(c); -//						canvas_draw_rect(rect->rect,rect->region,rect->source,rect->flags&CanvasItem::CommandRect::FLAG_TILE,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H,rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V,rect->texture,rect->modulate); -#if 0 -					int flags=0; +			while(light) { -					if (rect->flags&CanvasItem::CommandRect::FLAG_REGION) { -						flags|=Rasterizer::CANVAS_RECT_REGION; -					} -					if (rect->flags&CanvasItem::CommandRect::FLAG_TILE) { -						flags|=Rasterizer::CANVAS_RECT_TILE; -					} -					if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_H) { +				if (ci->light_mask&light->item_mask && p_z>=light->z_min && p_z<=light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache,light->rect_cache)) { + +					//intersects this light + +					if (!light_used || subtract!=light->subtract) { + +						subtract=light->subtract; + +						if (subtract) { + +							glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); +							glBlendFunc(GL_SRC_ALPHA,GL_ONE); -						flags|=Rasterizer::CANVAS_RECT_FLIP_H; +						} else { + +							glBlendEquation(GL_FUNC_ADD); +							glBlendFunc(GL_SRC_ALPHA,GL_ONE); + +						}  					} -					if (rect->flags&CanvasItem::CommandRect::FLAG_FLIP_V) { -						flags|=Rasterizer::CANVAS_RECT_FLIP_V; +					if (!light_used) { + +						canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING,true); +						canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,false); +						light_used=true; +						normal_flip=Vector2(1,1); +  					} -#else +					canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS,light->shadow_buffer.is_valid()); -					int flags=rect->flags; -#endif -					canvas_draw_rect(rect->rect,flags,rect->source,rect->texture,rect->modulate); +					bool light_rebind = canvas_shader.bind(); -				} break; -				case CanvasItem::Command::TYPE_STYLE: { +					if (light_rebind) { -					CanvasItem::CommandStyle* style = static_cast<CanvasItem::CommandStyle*>(c); -					canvas_draw_style_box(style->rect,style->texture,style->margin,style->draw_center,style->color); +						if (material && shader_cache) { +							_canvas_item_setup_shader_params(material,shader_cache); +							_canvas_item_setup_shader_uniforms(material,shader_cache); +						} -				} break; -				case CanvasItem::Command::TYPE_PRIMITIVE: { +						canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform); +						canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32()); +						canvas_shader.set_uniform(CanvasShaderGLES2::PROJECTION_MATRIX,canvas_transform); +						if (canvas_use_modulate) +							canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate); +						canvas_shader.set_uniform(CanvasShaderGLES2::NORMAL_FLIP,Vector2(1,1)); +						canvas_shader.set_uniform(CanvasShaderGLES2::SHADOWPIXEL_SIZE,1.0/light->shadow_buffer_size); -					CanvasItem::CommandPrimitive* primitive = static_cast<CanvasItem::CommandPrimitive*>(c); -					canvas_draw_primitive(primitive->points,primitive->colors,primitive->uvs,primitive->texture,primitive->width); -				} break; -				case CanvasItem::Command::TYPE_POLYGON: { -					CanvasItem::CommandPolygon* polygon = static_cast<CanvasItem::CommandPolygon*>(c); -					canvas_draw_polygon(polygon->count,polygon->indices.ptr(),polygon->points.ptr(),polygon->uvs.ptr(),polygon->colors.ptr(),polygon->texture,polygon->colors.size()==1); +					} -				} break; +					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX,light->light_shader_xform); +					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS,light->light_shader_pos); +					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR,light->color); +					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT,light->height); +					if (light->shadow_buffer.is_valid()) { -				case CanvasItem::Command::TYPE_POLYGON_PTR: { +						CanvasLightShadow *cls = canvas_light_shadow_owner.get(light->shadow_buffer); +						glActiveTexture(GL_TEXTURE0+max_texture_units-3); +						if (read_depth_supported) +							glBindTexture(GL_TEXTURE_2D,cls->depth); +						else +							glBindTexture(GL_TEXTURE_2D,cls->rgba); -					CanvasItem::CommandPolygonPtr* polygon = static_cast<CanvasItem::CommandPolygonPtr*>(c); -					canvas_draw_polygon(polygon->count,polygon->indices,polygon->points,polygon->uvs,polygon->colors,polygon->texture,false); -				} break; -				case CanvasItem::Command::TYPE_CIRCLE: { +						canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_TEXTURE,max_texture_units-3); +						canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX,light->shadow_matrix_cache); +						canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX,light->xform_cache.affine_inverse()); +						canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_ESM_MULTIPLIER,light->shadow_esm_mult); + +					} -					CanvasItem::CommandCircle* circle = static_cast<CanvasItem::CommandCircle*>(c); -					static const int numpoints=32; -					Vector2 points[numpoints+1]; -					points[numpoints]=circle->pos; -					int indices[numpoints*3]; -					for(int i=0;i<numpoints;i++) { +					glActiveTexture(GL_TEXTURE0+max_texture_units-2); +					canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_TEXTURE,max_texture_units-2); +					Texture *t = texture_owner.get(light->texture); +					if (!t) { +						glBindTexture(GL_TEXTURE_2D,white_tex); +					} else { -						points[i]=circle->pos+Vector2( Math::sin(i*Math_PI*2.0/numpoints),Math::cos(i*Math_PI*2.0/numpoints) )*circle->radius; -						indices[i*3+0]=i; -						indices[i*3+1]=(i+1)%numpoints; -						indices[i*3+2]=numpoints; +						glBindTexture(t->target,t->tex_id);  					} -					canvas_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true); -					//canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1); -				} break; -				case CanvasItem::Command::TYPE_TRANSFORM: { -					CanvasItem::CommandTransform* transform = static_cast<CanvasItem::CommandTransform*>(c); -					canvas_set_transform(transform->xform); -				} break; -				case CanvasItem::Command::TYPE_BLEND_MODE: { +					glActiveTexture(GL_TEXTURE0); +					_canvas_item_render_commands<true>(ci,current_clip,reclip); //redraw using light -					CanvasItem::CommandBlendMode* bm = static_cast<CanvasItem::CommandBlendMode*>(c); -					canvas_set_blend_mode(bm->blend_mode); +				} -				} break; -				case CanvasItem::Command::TYPE_CLIP_IGNORE: { +				light=light->next_ptr; +			} -					CanvasItem::CommandClipIgnore* ci = static_cast<CanvasItem::CommandClipIgnore*>(c); -					if (current_clip) { +			if (light_used) { -						if (ci->ignore!=reclip) { -							if (ci->ignore) { -								glDisable(GL_SCISSOR_TEST); -								reclip=true; -							} else  { +				canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING,false); +				canvas_shader.set_conditional(CanvasShaderGLES2::USE_MODULATE,canvas_use_modulate); +				canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS,false); -								glEnable(GL_SCISSOR_TEST); -								glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)), -								current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height); -								reclip=false; -							} -						} -					} +				canvas_shader.bind(); +				if (material && shader_cache) { +					_canvas_item_setup_shader_params(material,shader_cache); +					_canvas_item_setup_shader_uniforms(material,shader_cache); +				} +				canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,ci->final_transform); +				canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Matrix32()); +				if (canvas_use_modulate) +					canvas_shader.set_uniform(CanvasShaderGLES2::MODULATE,canvas_modulate); -				} break; +				glBlendEquation(GL_FUNC_ADD); +				if (current_rt && current_rt_transparent) { +					glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); +				} +				else { +					glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +				}  			} -		} +		} +  		if (reclip) {  			glEnable(GL_SCISSOR_TEST); @@ -8824,6 +9579,11 @@ bool RasterizerGLES2::is_environment(const RID& p_rid) const {  }  bool RasterizerGLES2::is_shader(const RID& p_rid) const { +	return shader_owner.owns(p_rid); +} + +bool RasterizerGLES2::is_canvas_light_occluder(const RID& p_rid) const { +  	return false;  } @@ -9001,7 +9761,30 @@ void RasterizerGLES2::free(const RID& p_rid) {  		glDeleteTextures(1,&sampled_light->texture);  		sampled_light_owner.free(p_rid);  		memdelete( sampled_light ); +	} else if (canvas_occluder_owner.owns(p_rid)) { + +		CanvasOccluder *co = canvas_occluder_owner.get(p_rid); +		if (co->index_id) +			glDeleteBuffers(1,&co->index_id); +		if (co->vertex_id) +			glDeleteBuffers(1,&co->vertex_id); + +		canvas_occluder_owner.free(p_rid); +		memdelete(co); + +	} else if (canvas_light_shadow_owner.owns(p_rid)) { + +		CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_rid); +		glDeleteFramebuffers(1,&cls->fbo); +		glDeleteRenderbuffers(1,&cls->rbo); +		glDeleteTextures(1,&cls->depth); +		if (!read_depth_supported) { +			glDeleteTextures(1,&cls->rgba); +		} + +		canvas_light_shadow_owner.free(p_rid); +		memdelete(cls);  	};  } @@ -9536,10 +10319,12 @@ void RasterizerGLES2::init() {  	material_shader.init();  	canvas_shader.init();  	copy_shader.init(); +	canvas_shadow_shader.init();  #ifdef GLEW_ENABLED  	material_shader.set_conditional(MaterialShaderGLES2::USE_GLES_OVER_GL,true);  	canvas_shader.set_conditional(CanvasShaderGLES2::USE_GLES_OVER_GL,true); +	canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_GLES_OVER_GL,true);  	copy_shader.set_conditional(CopyShaderGLES2::USE_GLES_OVER_GL,true);  #endif @@ -9561,9 +10346,6 @@ void RasterizerGLES2::init() {  	//glClearDepth(1.0);  	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); -	skinned_buffer_size = GLOBAL_DEF("rasterizer/skinned_buffer_size",DEFAULT_SKINNED_BUFFER_SIZE); -	skinned_buffer = memnew_arr( uint8_t, skinned_buffer_size ); -  	glGenTextures(1, &white_tex);  	unsigned char whitetexdata[8*8*3];  	for(int i=0;i<8*8*3;i++) { @@ -9683,8 +10465,11 @@ void RasterizerGLES2::init() {  	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units); +	glGetIntegerv(GL_MAX_TEXTURE_SIZE,&max_texture_size);  	//read_depth_supported=false; +	canvas_shadow_blur = canvas_light_shadow_buffer_create(max_texture_size); +  	{  		//shadowmaps  		OS::VideoMode vm=OS::get_singleton()->get_video_mode(); @@ -9706,6 +10491,7 @@ void RasterizerGLES2::init() {  		//material_shader  		material_shader.set_conditional(MaterialShaderGLES2::USE_DEPTH_SHADOWS,!use_rgba_shadowmaps); +		canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_DEPTH_SHADOWS,!use_rgba_shadowmaps);  	} @@ -9738,8 +10524,7 @@ void RasterizerGLES2::init() {  void RasterizerGLES2::finish() { - -	memdelete_arr(skinned_buffer); +	free(canvas_shadow_blur);  }  int RasterizerGLES2::get_render_info(VS::RenderInfo p_info) { @@ -10019,10 +10804,29 @@ RasterizerGLES2* RasterizerGLES2::get_singleton() {  	return _singleton;  }; +int RasterizerGLES2::RenderList::max_elements=RenderList::DEFAULT_MAX_ELEMENTS; +  RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,bool p_default_fragment_lighting,bool p_use_reload_hooks) {  	_singleton = this; +	RenderList::max_elements=GLOBAL_DEF("rasterizer/max_render_elements",(int)RenderList::DEFAULT_MAX_ELEMENTS); +	if (RenderList::max_elements>64000) +		RenderList::max_elements=64000; +	if (RenderList::max_elements<1024) +		RenderList::max_elements=1024; + +	opaque_render_list.init(); +	alpha_render_list.init(); + +	skinned_buffer_size = GLOBAL_DEF("rasterizer/skeleton_buffer_size_kb",DEFAULT_SKINNED_BUFFER_SIZE); +	if (skinned_buffer_size<256) +		skinned_buffer_size=256; +	if (skinned_buffer_size>16384) +		skinned_buffer_size=16384; +	skinned_buffer_size*=1024; +	skinned_buffer = memnew_arr( uint8_t, skinned_buffer_size ); +  	keep_copies=p_keep_ram_copy;  	use_reload_hooks=p_use_reload_hooks;  	pack_arrays=p_compress_arrays; @@ -10066,6 +10870,7 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo  RasterizerGLES2::~RasterizerGLES2() { +	memdelete_arr(skinned_buffer);  }; diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 0f77d18dee..f09714f50c 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -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(); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index f1ddcf8009..b2052c7cbb 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -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";  } diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h index a10fa6dfe0..87722602fd 100644 --- a/drivers/gles2/shader_compiler_gles2.h +++ b/drivers/gles2/shader_compiler_gles2.h @@ -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); diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub index c665cf9036..9679223b16 100644 --- a/drivers/gles2/shaders/SCsub +++ b/drivers/gles2/shaders/SCsub @@ -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'); diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index 464cb9e188..9022f30d7f 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.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*=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 +	} -	color.rgb=light;  //light shader code  #endif diff --git a/drivers/gles2/shaders/canvas_shadow.glsl b/drivers/gles2/shaders/canvas_shadow.glsl new file mode 100644 index 0000000000..40cf321dce --- /dev/null +++ b/drivers/gles2/shaders/canvas_shadow.glsl @@ -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 + +} + diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index 841160f941..ad0d4e00ea 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -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) { diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 2de975e5d1..d51a7c74e8 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -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(); diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index a6073cbb29..e24685432c 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -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 );  	} diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 20cd09efd0..df091fbcc9 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -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"; diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index fcfbbb04da..b616d8f228 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -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,"...")); diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h index 340763fb8c..05ff6a2e73 100644 --- a/modules/gdscript/gd_functions.h +++ b/modules/gdscript/gd_functions.h @@ -85,6 +85,8 @@ public:  		TEXT_PRINT_TABBED,  		TEXT_PRINTERR,  		TEXT_PRINTRAW, +		VAR_TO_STR, +		STR_TO_VAR,  		GEN_RANGE,  		RESOURCE_LOAD,  		INST2DICT, diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 0aa115ffbc..d3a9abf4b7 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -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; diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index 71dbf81fbf..1979577a17 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -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; diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp index 857d1a4a54..4c0c095e10 100644 --- a/platform/android/audio_driver_opensl.cpp +++ b/platform/android/audio_driver_opensl.cpp @@ -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); +		} +	}  } diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 6f1c03b593..6b91c01dfc 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -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 ); diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index 6ca54286ba..fe11b672ac 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -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; diff --git a/platform/iphone/gl_view.h b/platform/iphone/gl_view.h index 8eb96e7e98..04334991fd 100755 --- a/platform/iphone/gl_view.h +++ b/platform/iphone/gl_view.h @@ -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. diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm index 7d33c11315..3d6c48ffaf 100755 --- a/platform/iphone/gl_view.mm +++ b/platform/iphone/gl_view.mm @@ -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; diff --git a/platform/isim/detect.py b/platform/isim/detect.py index 8d60e30d25..bd0fd2fea3 100644 --- a/platform/isim/detect.py +++ b/platform/isim/detect.py @@ -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'), diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 5bc47a74c1..1c0d1f9991 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -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); diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 16dd695c59..62bab00f7b 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -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'])
 diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index ce79133664..e392a56aa8 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -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 { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 20993c6419..210e25d2d6 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -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 { diff --git a/platform/winrt/os_winrt.cpp b/platform/winrt/os_winrt.cpp index 89fa93c5c4..21a77b89cb 100644 --- a/platform/winrt/os_winrt.cpp +++ b/platform/winrt/os_winrt.cpp @@ -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 { diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 5171bc972d..fb5cdb5089 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -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') } ) diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index a40af8d2a9..ac1818d200 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -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);  	}  } diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index ae857bbce9..4a1842100a 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -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) { - -	ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode()!=Shader::MODE_CANVAS_ITEM); - -#ifdef TOOLS_ENABLED +void CanvasItem::set_material(const Ref<CanvasItemMaterial>& p_material) { -	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; -} - -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; +	return material;  } -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; diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index ed3ade9df2..0c7be261ab 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -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(); diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp new file mode 100644 index 0000000000..82dd8012a5 --- /dev/null +++ b/scene/2d/canvas_modulate.cpp @@ -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() +{ + +} + diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h new file mode 100644 index 0000000000..a6894f29c2 --- /dev/null +++ b/scene/2d/canvas_modulate.h @@ -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 diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp new file mode 100644 index 0000000000..93be0c397f --- /dev/null +++ b/scene/2d/light_2d.cpp @@ -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); +} diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h new file mode 100644 index 0000000000..89f351c3cd --- /dev/null +++ b/scene/2d/light_2d.h @@ -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 diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp new file mode 100644 index 0000000000..186ea2e248 --- /dev/null +++ b/scene/2d/light_occluder_2d.cpp @@ -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); +} + diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h new file mode 100644 index 0000000000..0343e3697e --- /dev/null +++ b/scene/2d/light_occluder_2d.h @@ -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 diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp new file mode 100644 index 0000000000..46af68444a --- /dev/null +++ b/scene/2d/navigation2d.cpp @@ -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; + +} diff --git a/scene/2d/navigation2d.h b/scene/2d/navigation2d.h new file mode 100644 index 0000000000..7ff01bb442 --- /dev/null +++ b/scene/2d/navigation2d.h @@ -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 diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp new file mode 100644 index 0000000000..fc69ea8a0d --- /dev/null +++ b/scene/2d/navigation_polygon.cpp @@ -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; + +} diff --git a/scene/2d/navigation_polygon.h b/scene/2d/navigation_polygon.h new file mode 100644 index 0000000000..01307a170b --- /dev/null +++ b/scene/2d/navigation_polygon.h @@ -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 diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 8b4196ee7f..36b6b220b3 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -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")); diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 61b8c829d6..7b059008c2 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -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(); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 9fcf34cee6..75e7957cb8 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -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; diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 4e9e2e7e97..fe1067fc1d 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -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; diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 27420f8002..1109139180 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -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); diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index a82c69e67f..45c7fa912c 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -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); diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index e9fefe1ba0..e08acbe9a2 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -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();  }; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index ce268843b1..a8070be91d 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -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"))); diff --git a/scene/gui/control.h b/scene/gui/control.h index 64b5a9b661..7e14bff098 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -380,7 +380,7 @@ public:  	void grab_click_focus(); - +	void warp_mouse(const Point2& p_to_pos);  	Control();	  	~Control(); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index a82cfc7ea6..30e0241f23 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -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 ); diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index bccd05d4fe..d58cb3da79 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -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 );  	} diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index c2e988de95..d825ea2b68 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -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);	 diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index b7b52a39dc..035dbb8cc4 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2472,6 +2472,10 @@ void Tree::_notification(int p_what) {  		}  	} +	if (p_what==NOTIFICATION_THEME_CHANGED) { +		update_cache(); +	} +  } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index e6c787cf9e..02e009866f 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -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) ) ); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 4bb5735731..d2a22401bd 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -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(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 998e0b2044..f90db42614 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -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>(); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 08c752cff9..633dd72ce3 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -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/","")+"\"");  			}  		}  	} diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index 9f691d6ad3..e8cdec66df 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -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; diff --git a/scene/resources/shader_graph.cpp b/scene/resources/shader_graph.cpp index 9703799a48..b0d9ceee0e 100644 --- a/scene/resources/shader_graph.cpp +++ b/scene/resources/shader_graph.cpp @@ -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; @@ -1988,6 +2231,129 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str  			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;  			float dv=p_node->param2; @@ -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: { diff --git a/scene/resources/shader_graph.h b/scene/resources/shader_graph.h index c515f6e101..5c34bedadd 100644 --- a/scene/resources/shader_graph.h +++ b/scene/resources/shader_graph.h @@ -66,14 +66,15 @@ public:  		NODE_VEC_TO_XFORM, // 3 vec input, 1 xform output  		NODE_SCALAR_INTERP, // scalar interpolation (with optional curve)  		NODE_VEC_INTERP, // vec3 interpolation  (with optional curve) -		/*NODE_SCALAR_CURVE_REMAP, -		NODE_VEC_CURVE_REMAP,*/ -		NODE_SCALAR_INPUT, // scalar uniform (assignable in material) +		NODE_COLOR_RAMP, //take scalar, output vec3 +		NODE_CURVE_MAP, //take scalar, otput scalar +		NODE_SCALAR_INPUT, // scalar uniform (assignable in material)		  		NODE_VEC_INPUT, // vec3 uniform (assignable in material)  		NODE_RGB_INPUT, // color uniform (assignable in material)  		NODE_XFORM_INPUT, // mat4 uniform (assignable in material)  		NODE_TEXTURE_INPUT, // texture input (assignable in material)  		NODE_CUBEMAP_INPUT, // cubemap input (assignable in material) +		NODE_DEFAULT_TEXTURE,  		NODE_OUTPUT, // output (shader type dependent)  		NODE_COMMENT, // comment  		NODE_TYPE_MAX @@ -174,6 +175,7 @@ private:  	void _update_shader();  	void _request_update(); +	void _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);  	void _add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code);  	Array _get_node_list(ShaderType p_type) const; @@ -315,6 +317,13 @@ public:  	void vec_func_node_set_function(ShaderType p_which,int p_id,VecFunc p_func);  	VecFunc vec_func_node_get_function(ShaderType p_which,int p_id) const; +	void color_ramp_node_set_ramp(ShaderType p_which,int p_id,const DVector<Color>& p_colors, const DVector<real_t>& p_offsets); +	DVector<Color> color_ramp_node_get_colors(ShaderType p_which,int p_id) const; +	DVector<real_t> color_ramp_node_get_offsets(ShaderType p_which,int p_id) const; + +	void curve_map_node_set_points(ShaderType p_which, int p_id, const DVector<Vector2>& p_points); +	DVector<Vector2> curve_map_node_get_points(ShaderType p_which,int p_id) const; +  	void input_node_set_name(ShaderType p_which,int p_id,const String& p_name);  	String input_node_get_name(ShaderType p_which,int p_id); @@ -397,7 +406,6 @@ VARIANT_ENUM_CAST( ShaderGraph::GraphError );  class MaterialShaderGraph : public ShaderGraph {  	OBJ_TYPE( MaterialShaderGraph, ShaderGraph ); -	RES_BASE_EXTENSION("sgp");  public: @@ -407,4 +415,17 @@ public:  	}  }; +class CanvasItemShaderGraph : public ShaderGraph { + +	OBJ_TYPE( CanvasItemShaderGraph, ShaderGraph ); + +public: + + +	CanvasItemShaderGraph() : ShaderGraph(MODE_CANVAS_ITEM) { + +	} +}; + +  #endif // SHADER_GRAPH_H diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 316b5e91eb..ca4bd3d253 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -85,6 +85,12 @@ void StyleBox::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("draw"),&StyleBox::draw); +	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/left", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_LEFT ); +	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/right", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_RIGHT ); +	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/top", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_TOP); +	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/bottom", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_BOTTOM ); + +  }  StyleBox::StyleBox() { diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index dae055890b..2c1502288b 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -38,19 +38,19 @@ Size2 Texture::get_size() const {  } -void Texture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const { +void Texture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const { -	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, get_size()),get_rid(),false,p_modulate); +	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, get_size()),get_rid(),false,p_modulate,p_transpose);  } -void Texture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const { +void Texture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const { -	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,get_rid(),p_tile,p_modulate); +	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,get_rid(),p_tile,p_modulate,p_transpose);  } -void Texture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const{ +void Texture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const{ -	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,get_rid(),p_src_rect,p_modulate); +	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,get_rid(),p_src_rect,p_modulate,p_transpose);  }  bool Texture::get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const { @@ -70,9 +70,9 @@ void Texture::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("has_alpha"),&Texture::has_alpha);  	ObjectTypeDB::bind_method(_MD("set_flags","flags"),&Texture::set_flags);  	ObjectTypeDB::bind_method(_MD("get_flags"),&Texture::get_flags); -	ObjectTypeDB::bind_method(_MD("draw","canvas_item","pos","modulate"),&Texture::draw,DEFVAL(Color(1,1,1))); -	ObjectTypeDB::bind_method(_MD("draw_rect","canvas_item","rect","tile","modulate"),&Texture::draw_rect,DEFVAL(Color(1,1,1))); -	ObjectTypeDB::bind_method(_MD("draw_rect_region","canvas_item","rect","src_rect","modulate"),&Texture::draw_rect_region,DEFVAL(Color(1,1,1))); +	ObjectTypeDB::bind_method(_MD("draw","canvas_item","pos","modulate"),&Texture::draw,DEFVAL(Color(1,1,1)),DEFVAL(false)); +	ObjectTypeDB::bind_method(_MD("draw_rect","canvas_item","rect","tile","modulate"),&Texture::draw_rect,DEFVAL(Color(1,1,1)),DEFVAL(false)); +	ObjectTypeDB::bind_method(_MD("draw_rect_region","canvas_item","rect","src_rect","modulate"),&Texture::draw_rect_region,DEFVAL(Color(1,1,1)),DEFVAL(false));  	BIND_CONSTANT( FLAG_MIPMAPS );  	BIND_CONSTANT( FLAG_REPEAT ); @@ -327,28 +327,27 @@ bool ImageTexture::has_alpha() const {  } -void ImageTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const { +void ImageTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {  	if ((w|h)==0)  		return; -	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, Size2(w,h)),texture,false,p_modulate); +	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,Rect2( p_pos, Size2(w,h)),texture,false,p_modulate,p_transpose);  } -void ImageTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const { +void ImageTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {  	if ((w|h)==0)  		return; -	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,texture,p_tile,p_modulate); +	VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item,p_rect,texture,p_tile,p_modulate,p_transpose);  } -void ImageTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const{ +void ImageTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const{  	if ((w|h)==0)  		return; -	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,texture,p_src_rect,p_modulate); +	VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,p_rect,texture,p_src_rect,p_modulate,p_transpose);  } -  void ImageTexture::set_size_override(const Size2& p_size) {  	Size2 s=p_size; @@ -546,7 +545,7 @@ void AtlasTexture::_bind_methods() { -void AtlasTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const { +void AtlasTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {  	Rect2 rc=region; @@ -561,10 +560,10 @@ void AtlasTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_m  		rc.size.height=atlas->get_height();  	} -	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,Rect2(p_pos+margin.pos,rc.size),atlas->get_rid(),rc,p_modulate); +	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,Rect2(p_pos+margin.pos,rc.size),atlas->get_rid(),rc,p_modulate,p_transpose);  } -void AtlasTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const { +void AtlasTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {  	Rect2 rc=region; @@ -582,10 +581,10 @@ void AtlasTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,  	Vector2 scale = p_rect.size / (region.size+margin.size);  	Rect2 dr( p_rect.pos+margin.pos*scale,rc.size*scale  ); -	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),rc,p_modulate); +	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),rc,p_modulate,p_transpose);  } -void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const { +void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const {  	//this might not necesarily work well if using a rect, needs to be fixed properly  	Rect2 rc=region; @@ -615,7 +614,7 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const      }  	Rect2 dr( p_rect.pos+ofs*scale,src_c.size*scale ); -	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),src_c,p_modulate); +	VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item,dr,atlas->get_rid(),src_c,p_modulate,p_transpose);  }  bool AtlasTexture::get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const { @@ -801,15 +800,16 @@ void LargeTexture::_bind_methods() { -void LargeTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate) const { +void LargeTexture::draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate, bool p_transpose) const {  	for(int i=0;i<pieces.size();i++) { -		pieces[i].texture->draw(p_canvas_item,pieces[i].offset+p_pos,p_modulate); +		// TODO +		pieces[i].texture->draw(p_canvas_item,pieces[i].offset+p_pos,p_modulate,p_transpose);  	}  } -void LargeTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate) const { +void LargeTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) const {  	//tiling not supported for this  	if (size.x==0 || size.y==0) @@ -819,11 +819,11 @@ void LargeTexture::draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile,  	for(int i=0;i<pieces.size();i++) { -		pieces[i].texture->draw_rect(p_canvas_item,Rect2(pieces[i].offset*scale+p_rect.pos,pieces[i].texture->get_size()*scale),false,p_modulate); +		// TODO +		pieces[i].texture->draw_rect(p_canvas_item,Rect2(pieces[i].offset*scale+p_rect.pos,pieces[i].texture->get_size()*scale),false,p_modulate,p_transpose);  	} -  } -void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) const { +void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate, bool p_transpose) const {  	//tiling not supported for this @@ -834,6 +834,7 @@ void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const  	for(int i=0;i<pieces.size();i++) { +		// TODO  		Rect2 rect( pieces[i].offset, pieces[i].texture->get_size());  		if (!p_src_rect.intersects(rect))  			continue; @@ -842,7 +843,7 @@ void LargeTexture::draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const  		target.size*=scale;  		target.pos=p_rect.pos+(p_src_rect.pos+rect.pos)*scale;  		local.pos-=rect.pos; -		pieces[i].texture->draw_rect_region(p_canvas_item,target,local,p_modulate); +		pieces[i].texture->draw_rect_region(p_canvas_item,target,local,p_modulate,p_transpose);  	}  } @@ -935,21 +936,21 @@ float CubeMap::get_lossy_storage_quality() const {  bool CubeMap::_set(const StringName& p_name, const Variant& p_value) { -	if (p_name=="side/left") +	if (p_name=="side/left") {  		set_side(SIDE_LEFT,p_value); -	if (p_name=="side/right") +	} else if (p_name=="side/right") {  		set_side(SIDE_RIGHT,p_value); -	if (p_name=="side/bottom") +	} else if (p_name=="side/bottom") {  		set_side(SIDE_BOTTOM,p_value); -	if (p_name=="side/top") +	} else if (p_name=="side/top") {  		set_side(SIDE_TOP,p_value); -	if (p_name=="side/front") +	} else if (p_name=="side/front") {  		set_side(SIDE_FRONT,p_value); -	if (p_name=="side/back") +	} else if (p_name=="side/back") {  		set_side(SIDE_BACK,p_value); -	else if (p_name=="flags") +	} else if (p_name=="flags") {  		set_flags(p_value); -	else if (p_name=="storage") { +	} else if (p_name=="storage") {  		storage=Storage(p_value.operator int());  	} else if (p_name=="lossy_quality") {  		lossy_storage_quality=p_value; @@ -962,25 +963,25 @@ bool CubeMap::_set(const StringName& p_name, const Variant& p_value) {  bool CubeMap::_get(const StringName& p_name,Variant &r_ret) const { -	if (p_name=="side/left") +	if (p_name=="side/left") {  		r_ret=get_side(SIDE_LEFT); -	if (p_name=="side/right") +	} else if (p_name=="side/right") {  		r_ret=get_side(SIDE_RIGHT); -	if (p_name=="side/bottom") +	} else if (p_name=="side/bottom") {  		r_ret=get_side(SIDE_BOTTOM); -	if (p_name=="side/top") +	} else if (p_name=="side/top") {  		r_ret=get_side(SIDE_TOP); -	if (p_name=="side/front") +	} else if (p_name=="side/front") {  		r_ret=get_side(SIDE_FRONT); -	if (p_name=="side/back") +	} else if (p_name=="side/back") {  		r_ret=get_side(SIDE_BACK); -	else if (p_name=="flags") +	} else if (p_name=="flags") {  		r_ret= flags; -	else if (p_name=="storage") +	} else if (p_name=="storage") {  		r_ret= storage; -	else if (p_name=="lossy_quality") +	} else if (p_name=="lossy_quality") {  		r_ret= lossy_storage_quality; -	else +	} else  		return false;  	return true; diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 4bb2f6d979..c1122b005d 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -69,9 +69,9 @@ public:  	virtual void set_flags(uint32_t p_flags)=0;  	virtual uint32_t get_flags() const=0; -	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const; -	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const; -	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const; +	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; +	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; +	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;  	virtual bool get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const; @@ -135,10 +135,9 @@ public:  	virtual RID get_rid() const;  	bool has_alpha() const; -	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const; -	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const; -	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const; - +	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; +	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; +	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;  	void set_storage(Storage p_storage);  	Storage get_storage() const; @@ -191,9 +190,9 @@ public:  	void set_margin(const Rect2& p_margin);  	Rect2 get_margin() const ; -	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const; -	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const; -	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const; +	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; +	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; +	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;  	virtual bool get_rect_region(const Rect2& p_rect, const Rect2& p_src_rect,Rect2& r_rect,Rect2& r_src_rect) const; @@ -241,9 +240,9 @@ public:  	Vector2 get_piece_offset(int p_idx) const;  	Ref<Texture> get_piece_texture(int p_idx) const; -	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1)) const; -	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)) const; -	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)) const; +	virtual void draw(RID p_canvas_item, const Point2& p_pos, const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; +	virtual void draw_rect(RID p_canvas_item,const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const; +	virtual void draw_rect_region(RID p_canvas_item,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false) const;  	LargeTexture(); diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index af5e6d4165..c30ff0044e 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -41,6 +41,7 @@ SceneStringNames::SceneStringNames() {  	visibility_changed=StaticCString::create("visibility_changed");  	input_event=StaticCString::create("input_event");  	shader_shader=StaticCString::create("shader/shader"); +	shader_unshaded=StaticCString::create("shader/unshaded");  	enter_tree=StaticCString::create("enter_tree");  	exit_tree=StaticCString::create("exit_tree");  	item_rect_changed=StaticCString::create("item_rect_changed"); diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 14e5e83b8d..184cbe347b 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -56,6 +56,7 @@ public:  	StringName _input_event;  	StringName item_rect_changed;  	StringName shader_shader; +	StringName shader_unshaded;  	StringName enter_tree;  	StringName exit_tree;  	StringName size_flags_changed; diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index 336eec73b5..ed63870a12 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -136,6 +136,7 @@ real_t LineShape2DSW::get_moment_of_inertia(float p_mass, const Vector2 &p_scale  	return 0;  } +  void LineShape2DSW::set_data(const Variant& p_data) {  	ERR_FAIL_COND(p_data.get_type()!=Variant::ARRAY); diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h index 51ece9fc7e..931491efd5 100644 --- a/servers/physics_2d/shape_2d_sw.h +++ b/servers/physics_2d/shape_2d_sw.h @@ -85,7 +85,6 @@ public:  	virtual bool intersect_segment(const Vector2& p_begin,const Vector2& p_end,Vector2 &r_point, Vector2 &r_normal) const=0;  	virtual real_t get_moment_of_inertia(float p_mass,const Vector2& p_scale) const=0; -  	virtual void set_data(const Variant& p_data)=0;  	virtual Variant get_data() const=0; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 92c7b8ac14..62ab8b3c56 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -564,7 +564,76 @@ public:  		CANVAS_RECT_REGION=1,  		CANVAS_RECT_TILE=2,  		CANVAS_RECT_FLIP_H=4, -		CANVAS_RECT_FLIP_V=8 +		CANVAS_RECT_FLIP_V=8, +		CANVAS_RECT_TRANSPOSE=16 +	}; + + +	struct CanvasLight { + + + +		bool enabled; +		Color color; +		Matrix32 xform; +		float height; +		int z_min; +		int z_max; +		int layer_min; +		int layer_max; +		int item_mask; +		bool subtract; +		RID texture; +		Vector2 texture_offset; +		RID canvas; +		RID shadow_buffer; +		int shadow_buffer_size; +		float shadow_esm_mult; + + +		void *texture_cache; // implementation dependent +		Rect2 rect_cache; +		Matrix32 xform_cache; +		float radius_cache; //used for shadow far plane +		CameraMatrix shadow_matrix_cache; + +		Matrix32 light_shader_xform; +		Vector2 light_shader_pos; + +		CanvasLight *shadows_next_ptr; +		CanvasLight *filter_next_ptr; +		CanvasLight *next_ptr; + +		CanvasLight() { +			enabled=true;			 +			color=Color(1,1,1); +			height=0; +			z_min=-1024; +			z_max=1024; +			layer_min=0; +			layer_max=0; +			item_mask=1; +			subtract=false; +			texture_cache=NULL; +			next_ptr=NULL; +			filter_next_ptr=NULL; +			shadow_buffer_size=2048; +			shadow_esm_mult=80; + +		} +	}; + +	struct CanvasItem; + +	struct CanvasItemMaterial  { + +		RID shader; +		Map<StringName,Variant> shader_param; +		uint32_t shader_version; +		Set<CanvasItem*> owners; +		bool unshaded; + +		CanvasItemMaterial() {unshaded=false; shader_version=0; }  	};  	struct CanvasItem { @@ -689,25 +758,25 @@ public:  		bool visible;  		bool ontop;  		VS::MaterialBlendMode blend_mode; +		int light_mask;  		Vector<Command*> commands;  		mutable bool custom_rect;  		mutable bool rect_dirty;  		mutable Rect2 rect;  		CanvasItem*next; -		RID shader; -		Map<StringName,Variant> shader_param; -		uint32_t shader_version; +		CanvasItemMaterial* material;  		float final_opacity;  		Matrix32 final_transform;  		Rect2 final_clip_rect;  		CanvasItem* final_clip_owner; -		CanvasItem* shader_owner; +		CanvasItem* material_owner;  		ViewportRender *vp_render; -		const Rect2& get_rect() const { +		Rect2 global_rect_cache; +		const Rect2& get_rect() const {  			if (custom_rect || !rect_dirty)  				return rect; @@ -830,8 +899,8 @@ public:  			return rect;  		} -		void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true; final_clip_owner=NULL;  shader_owner=NULL;} -		CanvasItem() { vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1;  blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; shader_version=0; shader_owner=NULL;} +		void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true; final_clip_owner=NULL;  material_owner=NULL;} +		CanvasItem() { light_mask=1; vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1;  blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; material_owner=NULL; material=NULL; }  		virtual ~CanvasItem() { clear(); }  	}; @@ -853,9 +922,38 @@ 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)=0;  	virtual void canvas_set_transform(const Matrix32& p_transform)=0; -	virtual void canvas_render_items(CanvasItem *p_item_list)=0; +	virtual void canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light)=0; +	virtual void canvas_debug_viewport_shadows(CanvasLight* p_lights_with_shadow)=0; +	/* LIGHT SHADOW MAPPING */ + +	virtual RID canvas_light_occluder_create()=0; +	virtual void canvas_light_occluder_set_polylines(RID p_occluder, const DVector<Vector2>& p_lines)=0; +	virtual RID canvas_light_shadow_buffer_create(int p_width)=0; + +	struct CanvasLightOccluderInstance { + + +		bool enabled; +		RID canvas; +		RID polygon; +		RID polygon_buffer; +		Rect2 aabb_cache; +		Matrix32 xform; +		Matrix32 xform_cache; +		int light_mask; +		VS::CanvasOccluderPolygonCullMode cull_cache; + +		CanvasLightOccluderInstance *next; + +		CanvasLightOccluderInstance() { enabled=true; next=NULL; light_mask=1; cull_cache=VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; } +	}; + + + +	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)=0; +  	/* ENVIRONMENT */ @@ -894,6 +992,8 @@ public:  	virtual bool is_environment(const RID& p_rid) const=0;  	virtual bool is_shader(const RID& p_rid) const=0; +	virtual bool is_canvas_light_occluder(const RID& p_rid) const=0; +  	virtual void free(const RID& p_rid)=0;  	virtual void init()=0; diff --git a/servers/visual/rasterizer_dummy.cpp b/servers/visual/rasterizer_dummy.cpp index 6c1b6697c1..7fb8eb02fc 100644 --- a/servers/visual/rasterizer_dummy.cpp +++ b/servers/visual/rasterizer_dummy.cpp @@ -1622,7 +1622,7 @@ void RasterizerDummy::canvas_set_transform(const Matrix32& p_transform) {  } -void RasterizerDummy::canvas_render_items(CanvasItem *p_item_list) { +void RasterizerDummy::canvas_render_items(CanvasItem *p_item_list,int p_z,const Color& p_modulate,CanvasLight *p_light) {  } diff --git a/servers/visual/rasterizer_dummy.h b/servers/visual/rasterizer_dummy.h index c72149f88f..baa48951d6 100644 --- a/servers/visual/rasterizer_dummy.h +++ b/servers/visual/rasterizer_dummy.h @@ -710,7 +710,7 @@ 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);  	/* ENVIRONMENT */ diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 30499ca210..f178c27ed0 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -1112,6 +1112,7 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::ci_vertex_builtins_defs[]={  	{ "SRC_VERTEX", TYPE_VEC2},  	{ "VERTEX", TYPE_VEC2}, +	{ "WORLD_VERTEX", TYPE_VEC2},  	{ "UV", TYPE_VEC2},  	{ "COLOR", TYPE_VEC4},  	{ "VAR1", TYPE_VEC4}, diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index a3aa573e35..3bcf0b8a3e 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -1576,6 +1576,15 @@ void VisualServerRaster::viewport_set_render_target_vflip(RID p_viewport,bool p_  } +void VisualServerRaster::viewport_set_render_target_clear_on_new_frame(RID p_viewport,bool p_enable) { + +	Viewport *viewport = viewport_owner.get( p_viewport ); +	ERR_FAIL_COND(!viewport); + +	viewport->render_target_clear_on_new_frame=p_enable; + +} +  void VisualServerRaster::viewport_set_render_target_to_screen_rect(RID p_viewport,const Rect2& p_rect) {  	Viewport *viewport = viewport_owner.get( p_viewport ); @@ -1594,6 +1603,23 @@ bool VisualServerRaster::viewport_get_render_target_vflip(RID p_viewport) const{  } +bool VisualServerRaster::viewport_get_render_target_clear_on_new_frame(RID p_viewport) const{ + +	const Viewport *viewport = viewport_owner.get( p_viewport ); +	ERR_FAIL_COND_V(!viewport,false); + +	return viewport->render_target_clear_on_new_frame; + +} + +void VisualServerRaster::viewport_render_target_clear(RID p_viewport) { + +	Viewport *viewport = viewport_owner.get( p_viewport ); +	ERR_FAIL_COND(!viewport); + +	viewport->render_target_clear=true; + +}  void VisualServerRaster::viewport_queue_screen_capture(RID p_viewport) { @@ -3195,6 +3221,7 @@ RID VisualServerRaster::canvas_create() {  	return rid;  } +  void VisualServerRaster::canvas_set_item_mirroring(RID p_canvas,RID p_item,const Point2& p_mirroring) {  	Canvas * canvas = canvas_owner.get(p_canvas); @@ -3220,6 +3247,14 @@ Point2 VisualServerRaster::canvas_get_item_mirroring(RID p_canvas,RID p_item) co  	return canvas->child_items[idx].mirror;  } +void VisualServerRaster::canvas_set_modulate(RID p_canvas,const Color& p_color) { + +	Canvas * canvas = canvas_owner.get(p_canvas); +	ERR_FAIL_COND(!canvas); +	canvas->modulate=p_color; +} + +  RID VisualServerRaster::canvas_item_create() { @@ -3305,14 +3340,27 @@ bool VisualServerRaster::canvas_item_is_visible(RID p_item) const {  } +void VisualServerRaster::canvas_item_set_light_mask(RID p_canvas_item,int p_mask) { + +	VS_CHANGED; + +	CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item ); +	ERR_FAIL_COND(!canvas_item); + +	if (canvas_item->light_mask==p_mask) +		return; +	VS_CHANGED; + +	canvas_item->light_mask=p_mask; + +} + +  void VisualServerRaster::canvas_item_set_blend_mode(RID p_canvas_item,MaterialBlendMode p_blend) {  	VS_CHANGED;  	CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item ); -	if (!canvas_item) { -		printf("!canvas_item\n"); -	};  	ERR_FAIL_COND(!canvas_item);  	if (canvas_item->blend_mode==p_blend) @@ -3470,7 +3518,7 @@ void VisualServerRaster::canvas_item_add_circle(RID p_item, const Point2& p_pos,  } -void VisualServerRaster::canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile,const Color& p_modulate) { +void VisualServerRaster::canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile,const Color& p_modulate,bool p_transpose) {  	VS_CHANGED;  	CanvasItem *canvas_item = canvas_item_owner.get( p_item );  	ERR_FAIL_COND(!canvas_item); @@ -3493,12 +3541,16 @@ void VisualServerRaster::canvas_item_add_texture_rect(RID p_item, const Rect2& p  		rect->flags|=Rasterizer::CANVAS_RECT_FLIP_V;  		rect->rect.size.y = -rect->rect.size.y;  	} +	if (p_transpose) { +		rect->flags|=Rasterizer::CANVAS_RECT_TRANSPOSE; +		SWAP(rect->rect.size.x, rect->rect.size.y); +	}  	rect->texture=p_texture;  	canvas_item->rect_dirty=true;  	canvas_item->commands.push_back(rect);  } -void VisualServerRaster::canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate)  { +void VisualServerRaster::canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate,bool p_transpose)  {  	VS_CHANGED;  	CanvasItem *canvas_item = canvas_item_owner.get( p_item );  	ERR_FAIL_COND(!canvas_item); @@ -3521,12 +3573,17 @@ void VisualServerRaster::canvas_item_add_texture_rect_region(RID p_item, const R  		rect->flags|=Rasterizer::CANVAS_RECT_FLIP_V;  		rect->rect.size.y = -rect->rect.size.y;  	} +	if (p_transpose) { +		rect->flags|=Rasterizer::CANVAS_RECT_TRANSPOSE; +		SWAP(rect->rect.size.x, rect->rect.size.y); +	}  	canvas_item->rect_dirty=true;  	canvas_item->commands.push_back(rect);	  } +  void VisualServerRaster::canvas_item_add_style_box(RID p_item, const Rect2& p_rect, RID p_texture,const Vector2& p_topleft, const Vector2& p_bottomright, bool p_draw_center,const Color& p_modulate) {  	VS_CHANGED; @@ -3708,55 +3765,32 @@ void VisualServerRaster::canvas_item_set_z_as_relative_to_parent(RID p_item, boo  } -void VisualServerRaster::canvas_item_set_use_parent_shader(RID p_item, bool p_enable) { +void VisualServerRaster::canvas_item_set_use_parent_material(RID p_item, bool p_enable) {  	VS_CHANGED;  	CanvasItem *canvas_item = canvas_item_owner.get( p_item );  	ERR_FAIL_COND(!canvas_item); -	canvas_item->use_parent_shader=p_enable; +	canvas_item->use_parent_material=p_enable;  } -void VisualServerRaster::canvas_item_set_shader(RID p_item, RID p_shader) { +void VisualServerRaster::canvas_item_set_material(RID p_item, RID p_material) {  	VS_CHANGED;  	CanvasItem *canvas_item = canvas_item_owner.get( p_item );  	ERR_FAIL_COND(!canvas_item); -	canvas_item->shader=p_shader; -} - -RID VisualServerRaster::canvas_item_get_shader(RID p_item) const{ - -	CanvasItem *canvas_item = canvas_item_owner.get( p_item ); -	ERR_FAIL_COND_V(!canvas_item,RID()); -	return canvas_item->shader; -} - -void VisualServerRaster::canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value){ - -	VS_CHANGED; -	CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item ); -	ERR_FAIL_COND(!canvas_item); -	if (p_value.get_type()==Variant::NIL) -		canvas_item->shader_param.erase(p_param); -	else -		canvas_item->shader_param[p_param]=p_value; +	if (canvas_item->material) +		canvas_item->material->owners.erase(canvas_item); -} -Variant VisualServerRaster::canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const{ +	canvas_item->material=NULL; -	CanvasItem *canvas_item = canvas_item_owner.get( p_canvas_item ); -	ERR_FAIL_COND_V(!canvas_item,Variant()); -	if (!canvas_item->shader_param.has(p_param)) { -		ERR_FAIL_COND_V(!canvas_item->shader.is_valid(),Variant()); -		return rasterizer->shader_get_default_param(canvas_item->shader,p_param); +	if (canvas_item_material_owner.owns(p_material)) { +		canvas_item->material=canvas_item_material_owner.get(p_material); +		canvas_item->material->owners.insert(canvas_item);  	} - -	return canvas_item->shader_param[p_param];  } -  void VisualServerRaster::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) {  	VS_CHANGED; @@ -3819,6 +3853,372 @@ void VisualServerRaster::canvas_item_raise(RID p_item) {  } +/***** CANVAS LIGHT *******/ + +RID VisualServerRaster::canvas_light_create() { + +	Rasterizer::CanvasLight *clight = memnew( Rasterizer::CanvasLight ); +	return canvas_light_owner.make_rid(clight); +} + +void VisualServerRaster::canvas_light_attach_to_canvas(RID p_light,RID p_canvas){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); + +	if (clight->canvas.is_valid()) { + +		Canvas *canvas = canvas_owner.get(clight->canvas); +		canvas->lights.erase(clight); +	} + +	if (!canvas_owner.owns(p_canvas)) +		p_canvas=RID(); +	clight->canvas=p_canvas; + +	if (clight->canvas.is_valid()) { + +		Canvas *canvas = canvas_owner.get(clight->canvas); +		canvas->lights.insert(clight); +	} + + + +} +void VisualServerRaster::canvas_light_set_enabled(RID p_light, bool p_enabled){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->enabled=p_enabled; + +} +void VisualServerRaster::canvas_light_set_transform(RID p_light, const Matrix32& p_transform){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->xform=p_transform; + +} +void VisualServerRaster::canvas_light_set_texture(RID p_light, RID p_texture){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->texture=p_texture; + +} +void VisualServerRaster::canvas_light_set_texture_offset(RID p_light, const Vector2& p_offset){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->texture_offset=p_offset; + +} +void VisualServerRaster::canvas_light_set_color(RID p_light, const Color& p_color){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->color=p_color; + + +} +void VisualServerRaster::canvas_light_set_height(RID p_light, float p_height){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->height=p_height; + +} +void VisualServerRaster::canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->z_min=p_min_z; +	clight->z_max=p_max_z; + +} + +void VisualServerRaster::canvas_light_set_layer_range(RID p_light, int p_min_layer,int p_max_layer) { + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->layer_min=p_min_layer; +	clight->layer_max=p_max_layer; + +} + +void VisualServerRaster::canvas_light_set_item_mask(RID p_light, int p_mask){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->item_mask=p_mask; + +} + +void VisualServerRaster::canvas_light_set_subtract_mode(RID p_light, bool p_enable) { + + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->subtract=p_enable; + +} +void VisualServerRaster::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); + +	if (clight->shadow_buffer.is_valid()==p_enabled) +		return; +	if (p_enabled) { +		clight->shadow_buffer=rasterizer->canvas_light_shadow_buffer_create(clight->shadow_buffer_size); +	} else { +		rasterizer->free(clight->shadow_buffer); +		clight->shadow_buffer=RID(); + +	} + +} + +void VisualServerRaster::canvas_light_set_shadow_buffer_size(RID p_light, int p_size){ + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); + +	ERR_FAIL_COND(p_size<32 || p_size>16384); + +	clight->shadow_buffer_size=nearest_power_of_2(p_size); + + +	if (clight->shadow_buffer.is_valid()) { +		rasterizer->free(clight->shadow_buffer); +		clight->shadow_buffer=rasterizer->canvas_light_shadow_buffer_create(clight->shadow_buffer_size); +	} + +} + +void VisualServerRaster::canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier) { + +	Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light); +	ERR_FAIL_COND(!clight); +	clight->shadow_esm_mult=p_multiplier; + +} + +/****** CANVAS LIGHT OCCLUDER ******/ + +RID VisualServerRaster::canvas_light_occluder_create() { + +	Rasterizer::CanvasLightOccluderInstance *occluder = memnew( Rasterizer::CanvasLightOccluderInstance ); + +	return canvas_light_occluder_owner.make_rid( occluder ); + +} + +void VisualServerRaster::canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas) { + +	Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder); +	ERR_FAIL_COND(!occluder); + +	if (occluder->canvas.is_valid()) { + +		Canvas *canvas = canvas_owner.get(occluder->canvas); +		canvas->occluders.erase(occluder); +	} + +	if (!canvas_owner.owns(p_canvas)) +		p_canvas=RID(); + +	occluder->canvas=p_canvas; + +	if (occluder->canvas.is_valid()) { + +		Canvas *canvas = canvas_owner.get(occluder->canvas); +		canvas->occluders.insert(occluder); +	} +} + +void VisualServerRaster::canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled){ + +	Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder); +	ERR_FAIL_COND(!occluder); + +	occluder->enabled=p_enabled; + +} + +void VisualServerRaster::canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon) { + +	Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder); +	ERR_FAIL_COND(!occluder); + +	if (occluder->polygon.is_valid()) { +		CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_polygon); +		if (occluder_poly) { +			occluder_poly->owners.erase(occluder); +		} +	} + +	occluder->polygon=p_polygon; +	occluder->polygon_buffer=RID(); + +	if (occluder->polygon.is_valid()) { +		CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_polygon); +		if (!occluder_poly) +			occluder->polygon=RID(); +		ERR_FAIL_COND(!occluder_poly); +		occluder_poly->owners.insert(occluder); +		occluder->polygon_buffer=occluder_poly->occluder; +		occluder->aabb_cache=occluder_poly->aabb; +		occluder->cull_cache=occluder_poly->cull_mode; +	} + +} + + + + +void VisualServerRaster::canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform) { + +	Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder); +	ERR_FAIL_COND(!occluder); + +	occluder->xform=p_xform; + +} + +void VisualServerRaster::canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask) { + +	Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder); +	ERR_FAIL_COND(!occluder); + +	occluder->light_mask=p_mask; + +} + + +RID VisualServerRaster::canvas_occluder_polygon_create() { + +	CanvasLightOccluderPolygon * occluder_poly = memnew( CanvasLightOccluderPolygon ); +	occluder_poly->occluder=rasterizer->canvas_light_occluder_create(); +	return canvas_light_occluder_polygon_owner.make_rid(occluder_poly); + +} + +void VisualServerRaster::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const DVector<Vector2>& p_shape, bool p_close){ + +	if (p_shape.size()<3) { +		canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon,p_shape); +		return; +	} + +	DVector<Vector2> lines; +	int lc = p_shape.size()*2; + +	lines.resize(lc-(p_close?0:2)); +	{ +		DVector<Vector2>::Write w = lines.write(); +		DVector<Vector2>::Read r = p_shape.read(); + +		int max=lc/2; +		if (!p_close) { +			max--; +		} +		for(int i=0;i<max;i++) { + +			Vector2 a = r[i]; +			Vector2 b = r[(i+1)%(lc/2)]; +			w[i*2+0]=a; +			w[i*2+1]=b; +		} + +	} + +	canvas_occluder_polygon_set_shape_as_lines(p_occluder_polygon,lines); +} + +void VisualServerRaster::canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape) { + +	CanvasLightOccluderPolygon * occluder_poly = canvas_light_occluder_polygon_owner.get(p_occluder_polygon); +	ERR_FAIL_COND(!occluder_poly); +	ERR_FAIL_COND(p_shape.size()&1); + +	int lc = p_shape.size(); +	occluder_poly->aabb=Rect2(); +	{ +		DVector<Vector2>::Read r = p_shape.read(); +		for(int i=0;i<lc;i++) { +			if (i==0) +				occluder_poly->aabb.pos=r[i]; +			else +				occluder_poly->aabb.expand_to(r[i]); +		} +	} + +	rasterizer->canvas_light_occluder_set_polylines(occluder_poly->occluder,p_shape); +	for( Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=occluder_poly->owners.front();E;E=E->next()) { +		E->get()->aabb_cache=occluder_poly->aabb; +	} +} + +void VisualServerRaster::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode) { + +	CanvasLightOccluderPolygon * occluder_poly = canvas_light_occluder_polygon_owner.get(p_occluder_polygon); +	ERR_FAIL_COND(!occluder_poly); +	occluder_poly->cull_mode=p_mode; +	for( Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=occluder_poly->owners.front();E;E=E->next()) { +		E->get()->cull_cache=p_mode; +	} + +} + +RID VisualServerRaster::canvas_item_material_create() { + +	Rasterizer::CanvasItemMaterial *material = memnew( Rasterizer::CanvasItemMaterial ); +	return canvas_item_material_owner.make_rid(material); + +} + +void VisualServerRaster::canvas_item_material_set_shader(RID p_material, RID p_shader){ + +	VS_CHANGED; +	Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material ); +	ERR_FAIL_COND(!material); +	material->shader=p_shader; + +} +void VisualServerRaster::canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value){ + +	VS_CHANGED; +	Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material ); +	ERR_FAIL_COND(!material); +	if (p_value.get_type()==Variant::NIL) +		material->shader_param.erase(p_param); +	else +		material->shader_param[p_param]=p_value; + + +} +Variant VisualServerRaster::canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const{ +	Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material ); +	ERR_FAIL_COND_V(!material,Variant()); +	if (!material->shader_param.has(p_param)) { +		ERR_FAIL_COND_V(!material->shader.is_valid(),Variant()); +		return rasterizer->shader_get_default_param(material->shader,p_param); +	} + +	return material->shader_param[p_param]; +} + +void VisualServerRaster::canvas_item_material_set_unshaded(RID p_material, bool p_unshaded){ + +	VS_CHANGED; +	Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get( p_material ); +	ERR_FAIL_COND(!material); +	material->unshaded=p_unshaded; + +} + +  /******** CANVAS *********/ @@ -4069,7 +4469,17 @@ void VisualServerRaster::free( RID p_rid ) {  			canvas->child_items[i].item->parent=RID();  		} -		 + +		for (Set<Rasterizer::CanvasLight*>::Element *E=canvas->lights.front();E;E=E->next()) { + +			E->get()->canvas=RID(); +		} + +		for (Set<Rasterizer::CanvasLightOccluderInstance*>::Element *E=canvas->occluders.front();E;E=E->next()) { + +			E->get()->canvas=RID(); +		} +  		canvas_owner.free( p_rid );  		memdelete( canvas ); @@ -4098,9 +4508,75 @@ void VisualServerRaster::free( RID p_rid ) {  			canvas_item->child_items[i]->parent=RID();  		} +		if (canvas_item->material) { +			canvas_item->material->owners.erase(canvas_item); +		} +  		canvas_item_owner.free( p_rid );  		memdelete( canvas_item ); + +	} else if (canvas_item_material_owner.owns(p_rid)) { + +		Rasterizer::CanvasItemMaterial *material = canvas_item_material_owner.get(p_rid); +		ERR_FAIL_COND(!material); +		for(Set<Rasterizer::CanvasItem*>::Element *E=material->owners.front();E;E=E->next()) { + +			E->get()->material=NULL; +		} + +		canvas_item_material_owner.free(p_rid); +		memdelete(material); + +	} else if (canvas_light_owner.owns(p_rid)) { + +		Rasterizer::CanvasLight *canvas_light = canvas_light_owner.get(p_rid); +		ERR_FAIL_COND(!canvas_light); + +		if (canvas_light->canvas.is_valid()) { +			Canvas* canvas = canvas_owner.get(canvas_light->canvas); +			if (canvas) +				canvas->lights.erase(canvas_light); +		} + +		if (canvas_light->shadow_buffer.is_valid()) +			rasterizer->free(canvas_light->shadow_buffer); + +		canvas_light_owner.free( p_rid ); +		memdelete( canvas_light ); + +	} else if (canvas_light_occluder_owner.owns(p_rid)) { + +		Rasterizer::CanvasLightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_rid); +		ERR_FAIL_COND(!occluder); + +		if (occluder->polygon.is_valid()) { + +			CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(occluder->polygon); +			if (occluder_poly) { +				occluder_poly->owners.erase(occluder); +			} + +		} + +		canvas_light_occluder_owner.free( p_rid ); +		memdelete(occluder); + +	} else if (canvas_light_occluder_polygon_owner.owns(p_rid)) { + +		CanvasLightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(p_rid); +		ERR_FAIL_COND(!occluder_poly); +		rasterizer->free(occluder_poly->occluder); + +		while(occluder_poly->owners.size()) { + +			occluder_poly->owners.front()->get()->polygon=RID(); +			occluder_poly->owners.erase( occluder_poly->owners.front() ); +		} + +		canvas_light_occluder_polygon_owner.free( p_rid ); +		memdelete(occluder_poly); +  	} else if (scenario_owner.owns(p_rid)) {  		Scenario *scenario=scenario_owner.get(p_rid); @@ -6146,7 +6622,7 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S  } -void VisualServerRaster::_render_canvas_item_tree(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect) { +void VisualServerRaster::_render_canvas_item_tree(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, const Color& p_modulate, Rasterizer::CanvasLight *p_lights) {  	static const int z_range = CANVAS_ITEM_Z_MAX-CANVAS_ITEM_Z_MIN+1; @@ -6164,7 +6640,7 @@ void VisualServerRaster::_render_canvas_item_tree(CanvasItem *p_canvas_item,cons  	for(int i=0;i<z_range;i++) {  		if (!z_list[i])  			continue; -		rasterizer->canvas_render_items(z_list[i]); +		rasterizer->canvas_render_items(z_list[i],CANVAS_ITEM_Z_MIN+i,p_modulate,p_lights);  	}  } @@ -6179,7 +6655,7 @@ void VisualServerRaster::_render_canvas_item_viewport(VisualServer* p_self,void  } -void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_shader_owner) { +void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_material_owner) {  	CanvasItem *ci = p_canvas_item; @@ -6224,11 +6700,11 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat  		ci->vp_render=NULL;  	} -	if (ci->use_parent_shader && p_shader_owner) -		ci->shader_owner=p_shader_owner; +	if (ci->use_parent_material && p_material_owner) +		ci->material_owner=p_material_owner;  	else { -		p_shader_owner=ci; -		ci->shader_owner=NULL; +		p_material_owner=ci; +		ci->material_owner=NULL;  	} @@ -6262,7 +6738,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat  		if (child_items[i]->ontop)  			continue; -		_render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_shader_owner); +		_render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_material_owner);  	} @@ -6270,7 +6746,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat  		//something to draw?  		ci->final_transform=xform;  		ci->final_opacity=opacity * ci->self_opacity; - +		ci->global_rect_cache=global_rect;  		int zidx = p_z-CANVAS_ITEM_Z_MIN; @@ -6283,6 +6759,8 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat  			z_last_list[zidx]=ci;  		} + +  		ci->next=NULL;  	} @@ -6291,12 +6769,12 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat  		if (!child_items[i]->ontop)  			continue; -		_render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_shader_owner); +		_render_canvas_item(child_items[i],xform,p_clip_rect,opacity,p_z,z_list,z_last_list,(CanvasItem*)ci->final_clip_owner,p_material_owner);  	}  } -void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform) { +void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform,Rasterizer::CanvasLight *p_lights) {  	rasterizer->canvas_begin(); @@ -6329,30 +6807,30 @@ void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_trans  		for(int i=0;i<z_range;i++) {  			if (!z_list[i])  				continue; -			rasterizer->canvas_render_items(z_list[i]); +			rasterizer->canvas_render_items(z_list[i],CANVAS_ITEM_Z_MIN+i,p_canvas->modulate,p_lights);  		}  	} else {  		for(int i=0;i<l;i++) {  			Canvas::ChildItem& ci=p_canvas->child_items[i]; -			_render_canvas_item_tree(ci.item,p_transform,clip_rect); +			_render_canvas_item_tree(ci.item,p_transform,clip_rect,p_canvas->modulate,p_lights);  			//mirroring (useful for scrolling backgrounds)  			if (ci.mirror.x!=0) {  				Matrix32 xform2 = p_transform * Matrix32(0,Vector2(ci.mirror.x,0)); -				_render_canvas_item_tree(ci.item,xform2,clip_rect); +				_render_canvas_item_tree(ci.item,xform2,clip_rect,p_canvas->modulate,p_lights);  			}  			if (ci.mirror.y!=0) {  				Matrix32 xform2 = p_transform * Matrix32(0,Vector2(0,ci.mirror.y)); -				_render_canvas_item_tree(ci.item,xform2,clip_rect); +				_render_canvas_item_tree(ci.item,xform2,clip_rect,p_canvas->modulate,p_lights);  			}  			if (ci.mirror.y!=0 && ci.mirror.x!=0) {  				Matrix32 xform2 = p_transform * Matrix32(0,ci.mirror); -				_render_canvas_item_tree(ci.item,xform2,clip_rect); +				_render_canvas_item_tree(ci.item,xform2,clip_rect,p_canvas->modulate,p_lights);  			}  		} @@ -6407,7 +6885,15 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_  	} else if (true /*|| !p_viewport->canvas_list.empty()*/){  		//clear the viewport black because of no camera? i seriously should.. -		rasterizer->clear_viewport(clear_color); +		if (p_viewport->render_target_clear_on_new_frame || p_viewport->render_target_clear) { +			if (p_viewport->transparent_bg) { +				rasterizer->clear_viewport(Color(0,0,0,0)); +			} +			else { +				rasterizer->clear_viewport(clear_color); +			} +			p_viewport->render_target_clear=false; +		}  	}  	if (!p_viewport->hide_canvas) { @@ -6415,21 +6901,113 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_  		Map<Viewport::CanvasKey,Viewport::CanvasData*> canvas_map; +		Rect2 clip_rect(0,0,viewport_rect.width,viewport_rect.height); +		Rasterizer::CanvasLight *lights=NULL; +		Rasterizer::CanvasLight *lights_with_shadow=NULL; +		Rect2 shadow_rect; +  		for (Map<RID,Viewport::CanvasData>::Element *E=p_viewport->canvas_map.front();E;E=E->next()) { + +			Matrix32 xf = p_viewport->global_transform * E->get().transform; + +			//find lights in canvas + + +			for(Set<Rasterizer::CanvasLight*>::Element *F=E->get().canvas->lights.front();F;F=F->next()) { + +				Rasterizer::CanvasLight* cl=F->get(); +				if (cl->enabled && cl->texture.is_valid()) { +					//not super efficient.. +					Size2 tsize(rasterizer->texture_get_width(cl->texture),rasterizer->texture_get_height(cl->texture)); +					Vector2 offset=tsize/2.0; +					cl->rect_cache=Rect2(-offset+cl->texture_offset,tsize); +					cl->xform_cache=xf * cl->xform; + + +					if (clip_rect.intersects_transformed(cl->xform_cache,cl->rect_cache)) { +						cl->filter_next_ptr=lights; +						lights=cl; +						cl->texture_cache=NULL; +						Matrix32 scale; +						scale.scale(cl->rect_cache.size); +						scale.elements[2]=cl->rect_cache.pos; +						cl->light_shader_xform = (cl->xform_cache * scale).affine_inverse(); +						cl->light_shader_pos=cl->xform_cache[2]; +						if (cl->shadow_buffer.is_valid()) { +							cl->shadows_next_ptr=lights_with_shadow; +							if (lights_with_shadow==NULL) { +								shadow_rect = cl->xform_cache.xform(cl->rect_cache); +							} else { +								shadow_rect=shadow_rect.merge( cl->xform_cache.xform(cl->rect_cache) ); +							} +							lights_with_shadow=cl; +							cl->radius_cache=cl->rect_cache.size.length(); + +						} +					} +				} +			} +  			canvas_map[ Viewport::CanvasKey( E->key(), E->get().layer) ]=&E->get();  		} +		if (lights_with_shadow) { +			//update shadows if any + +			Rasterizer::CanvasLightOccluderInstance * occluders=NULL; + +			//make list of occluders +			for (Map<RID,Viewport::CanvasData>::Element *E=p_viewport->canvas_map.front();E;E=E->next()) { + +				Matrix32 xf = p_viewport->global_transform * E->get().transform; + +				for(Set<Rasterizer::CanvasLightOccluderInstance*>::Element *F=E->get().canvas->occluders.front();F;F=F->next()) { + +					F->get()->xform_cache = xf * F->get()->xform; +					if (shadow_rect.intersects_transformed(F->get()->xform_cache,F->get()->aabb_cache)) { + +						F->get()->next=occluders; +						occluders=F->get(); + +					} +				} +			} +			//update the light shadowmaps with them +			Rasterizer::CanvasLight *light=lights_with_shadow; +			while(light) { + +				rasterizer->canvas_light_shadow_buffer_update(light->shadow_buffer,light->xform_cache.affine_inverse(),light->item_mask,light->radius_cache/1000.0,light->radius_cache*1.1,occluders,&light->shadow_matrix_cache); +				light=light->shadows_next_ptr; +			} + +			rasterizer->set_viewport(viewport_rect); //must reset viewport afterwards +		} +  		for (Map<Viewport::CanvasKey,Viewport::CanvasData*>::Element *E=canvas_map.front();E;E=E->next()) {  	//		print_line("canvas "+itos(i)+" size: "+itos(I->get()->canvas->child_items.size()));  			//print_line("GT "+p_viewport->global_transform+". CT: "+E->get()->transform);  			Matrix32 xform = p_viewport->global_transform * E->get()->transform; -			_render_canvas( E->get()->canvas,xform ); + +			Rasterizer::CanvasLight *canvas_lights=NULL; + +			Rasterizer::CanvasLight *ptr=lights; +			while(ptr) { +				if (E->get()->layer>=ptr->layer_min && E->get()->layer<=ptr->layer_max) { +					ptr->next_ptr=canvas_lights; +					canvas_lights=ptr; +				} +				ptr=ptr->filter_next_ptr; +			} + +			_render_canvas( E->get()->canvas,xform,canvas_lights );  			i++;  		} + +		rasterizer->canvas_debug_viewport_shadows(lights_with_shadow);  	}  	//capture diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 6c4e15827a..b9a3f83364 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -371,7 +371,7 @@ class VisualServerRaster : public VisualServer { - +	mutable RID_Owner<Rasterizer::CanvasItemMaterial> canvas_item_material_owner;  	struct CanvasItem : public Rasterizer::CanvasItem { @@ -384,7 +384,7 @@ class VisualServerRaster : public VisualServer {  		bool sort_y;  		float opacity;  		float self_opacity; -		bool use_parent_shader; +		bool use_parent_material;  		Vector<CanvasItem*> child_items; @@ -396,7 +396,7 @@ class VisualServerRaster : public VisualServer {  			opacity=1;  			self_opacity=1;  			sort_y=false; -			use_parent_shader=false; +			use_parent_material=false;  			z_relative=true;  		}  	}; @@ -410,6 +410,26 @@ class VisualServerRaster : public VisualServer {  		}  	}; +	struct CanvasLightOccluder; + +	struct CanvasLightOccluderPolygon { + +		bool active; +		Rect2 aabb; +		CanvasOccluderPolygonCullMode cull_mode; +		RID occluder; +		Set<Rasterizer::CanvasLightOccluderInstance*> owners; + +		CanvasLightOccluderPolygon() { active=false; cull_mode=CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; } +	}; + + +	RID_Owner<CanvasLightOccluderPolygon> canvas_light_occluder_polygon_owner; + +	RID_Owner<Rasterizer::CanvasLightOccluderInstance> canvas_light_occluder_owner; + +	struct CanvasLight; +  	struct Canvas {  		Set<RID> viewports; @@ -419,8 +439,11 @@ class VisualServerRaster : public VisualServer {  			CanvasItem *item;  		}; +		Set<Rasterizer::CanvasLight*> lights; +		Set<Rasterizer::CanvasLightOccluderInstance*> occluders;  		Vector<ChildItem> child_items; +		Color modulate;  		int find_item(CanvasItem *p_item) {  			for(int i=0;i<child_items.size();i++) { @@ -435,11 +458,13 @@ class VisualServerRaster : public VisualServer {  				child_items.remove(idx);  		} -		Canvas() {  } +		Canvas() { modulate=Color(1,1,1,1); }  	}; +	RID_Owner<Rasterizer::CanvasLight> canvas_light_owner; +  	struct Viewport { @@ -462,6 +487,8 @@ class VisualServerRaster : public VisualServer {  		bool transparent_bg;  		bool queue_capture;  		bool render_target_vflip; +		bool render_target_clear_on_new_frame; +		bool render_target_clear;  		Image capture;  		bool rendered_in_prev_frame; @@ -488,7 +515,7 @@ class VisualServerRaster : public VisualServer {  		SelfList<Viewport> update_list; -		Viewport() : update_list(this) { transparent_bg=false; render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE; queue_capture=false; rendered_in_prev_frame=false; render_target_vflip=false;} +		Viewport() : update_list(this) { transparent_bg=false; render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE; queue_capture=false; rendered_in_prev_frame=false; render_target_vflip=false; render_target_clear_on_new_frame=true; render_target_clear=true;}  	};  	SelfList<Viewport>::List viewport_update_list; @@ -601,9 +628,9 @@ class VisualServerRaster : public VisualServer {  	void _render_camera(Viewport *p_viewport,Camera *p_camera, Scenario *p_scenario);  	static void _render_canvas_item_viewport(VisualServer* p_self,void *p_vp,const Rect2& p_rect); -	void _render_canvas_item_tree(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect); -	void _render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_shader_owner); -	void _render_canvas(Canvas *p_canvas,const Matrix32 &p_transform); +	void _render_canvas_item_tree(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, const Color &p_modulate, Rasterizer::CanvasLight *p_lights); +	void _render_canvas_item(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, float p_opacity, int p_z, Rasterizer::CanvasItem **z_list, Rasterizer::CanvasItem **z_last_list, CanvasItem *p_canvas_clip, CanvasItem *p_material_owner); +	void _render_canvas(Canvas *p_canvas, const Matrix32 &p_transform, Rasterizer::CanvasLight *p_lights);  	Vector<Vector3> _camera_generate_endpoints(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max);  	Vector<Plane> _camera_generate_orthogonal_planes(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max); @@ -951,6 +978,9 @@ public:  	virtual RID viewport_get_render_target_texture(RID p_viewport) const;  	virtual void viewport_set_render_target_vflip(RID p_viewport,bool p_enable);  	virtual bool viewport_get_render_target_vflip(RID p_viewport) const; +	virtual void viewport_set_render_target_clear_on_new_frame(RID p_viewport,bool p_enable); +	virtual bool viewport_get_render_target_clear_on_new_frame(RID p_viewport) const; +	virtual void viewport_render_target_clear(RID p_viewport);  	virtual void viewport_set_render_target_to_screen_rect(RID p_viewport,const Rect2& p_rect);  	virtual void viewport_queue_screen_capture(RID p_viewport); @@ -1073,6 +1103,8 @@ public:  	virtual RID canvas_create();  	virtual void canvas_set_item_mirroring(RID p_canvas,RID p_item,const Point2& p_mirroring);  	virtual Point2 canvas_get_item_mirroring(RID p_canvas,RID p_item) const; +	virtual void canvas_set_modulate(RID p_canvas,const Color& p_color); +  	virtual RID canvas_item_create(); @@ -1083,6 +1115,8 @@ public:  	virtual bool canvas_item_is_visible(RID p_item) const;  	virtual void canvas_item_set_blend_mode(RID p_canvas_item,MaterialBlendMode p_blend); +	virtual void canvas_item_set_light_mask(RID p_canvas_item,int p_mask); +  	//virtual void canvas_item_set_rect(RID p_item, const Rect2& p_rect); @@ -1102,8 +1136,8 @@ public:  	virtual void canvas_item_add_line(RID p_item, const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width=1.0);  	virtual void canvas_item_add_rect(RID p_item, const Rect2& p_rect, const Color& p_color);  	virtual void canvas_item_add_circle(RID p_item, const Point2& p_pos, float p_radius,const Color& p_color); -	virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1)); -	virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)); +	virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1),bool p_transpose=false); +	virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1),bool p_transpose=false);  	virtual void canvas_item_add_style_box(RID p_item, const Rect2& p_rect, RID p_texture,const Vector2& p_topleft, const Vector2& p_bottomright, bool p_draw_center=true,const Color& p_modulate=Color(1,1,1));  	virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture,float p_width=1.0);  	virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), RID p_texture=RID()); @@ -1116,18 +1150,54 @@ public:  	virtual void canvas_item_set_z(RID p_item, int p_z);  	virtual void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable); -	virtual void canvas_item_set_shader(RID p_item, RID p_shader); -	virtual RID canvas_item_get_shader(RID p_item) const; +	virtual void canvas_item_set_material(RID p_item, RID p_material); +	virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable); + +	virtual RID canvas_light_create(); +	virtual void canvas_light_attach_to_canvas(RID p_light,RID p_canvas); +	virtual void canvas_light_set_enabled(RID p_light, bool p_enabled); +	virtual void canvas_light_set_transform(RID p_light, const Matrix32& p_transform); +	virtual void canvas_light_set_texture(RID p_light, RID p_texture); +	virtual void canvas_light_set_texture_offset(RID p_light, const Vector2& p_offset); +	virtual void canvas_light_set_color(RID p_light, const Color& p_color); +	virtual void canvas_light_set_height(RID p_light, float p_height); +	virtual void canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z); +	virtual void canvas_light_set_layer_range(RID p_light, int p_min_layer,int p_max_layer); +	virtual void canvas_light_set_item_mask(RID p_light, int p_mask); + +	virtual void canvas_light_set_subtract_mode(RID p_light, bool p_enable); +	virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled); +	virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size); +	virtual void canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier); + -	virtual void canvas_item_set_use_parent_shader(RID p_item, bool p_enable); +	virtual RID canvas_light_occluder_create(); +	virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas); +	virtual void canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled); +	virtual void canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon); +	virtual void canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform); +	virtual void canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask); + + +	virtual RID canvas_occluder_polygon_create(); +	virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon,const DVector<Vector2>& p_shape,bool p_close); +	virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape); +	virtual void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode); -	virtual void canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value); -	virtual Variant canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const;  	virtual void canvas_item_clear(RID p_item);  	virtual void canvas_item_raise(RID p_item); +	/* CANVAS ITEM MATERIAL */ + +	virtual RID canvas_item_material_create(); +	virtual void canvas_item_material_set_shader(RID p_material, RID p_shader); +	virtual void canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value); +	virtual Variant canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const; +	virtual void canvas_item_material_set_unshaded(RID p_material, bool p_unshaded); + +  	/* CURSOR */  	virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0); // radians  	virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor=0); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index b59fdbc66a..1890f7b760 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -967,6 +967,10 @@ public:  	FUNC2(viewport_set_render_target_vflip,RID,bool);  	FUNC1RC(bool,viewport_get_render_target_vflip,RID);  	FUNC2(viewport_set_render_target_to_screen_rect,RID,const Rect2&); +	 +	FUNC2(viewport_set_render_target_clear_on_new_frame,RID,bool); +	FUNC1RC(bool,viewport_get_render_target_clear_on_new_frame,RID); +	FUNC1(viewport_render_target_clear,RID);  	FUNC1(viewport_queue_screen_capture,RID);  	FUNC1RC(Image,viewport_get_screen_capture,RID); @@ -1087,6 +1091,8 @@ public:  	FUNC0R(RID,canvas_create);  	FUNC3(canvas_set_item_mirroring,RID,RID,const Point2&);  	FUNC2RC(Point2,canvas_get_item_mirroring,RID,RID); +	FUNC2(canvas_set_modulate,RID,const Color&); +  	FUNC0R(RID,canvas_item_create); @@ -1097,7 +1103,7 @@ public:  	FUNC1RC(bool,canvas_item_is_visible,RID);  	FUNC2(canvas_item_set_blend_mode,RID,MaterialBlendMode ); - +	FUNC2(canvas_item_set_light_mask,RID,int );  	//FUNC(canvas_item_set_rect,RID, const Rect2& p_rect);  	FUNC2(canvas_item_set_transform,RID, const Matrix32& ); @@ -1116,9 +1122,8 @@ public:  	FUNC5(canvas_item_add_line,RID, const Point2& , const Point2& ,const Color& ,float );  	FUNC3(canvas_item_add_rect,RID, const Rect2& , const Color& );  	FUNC4(canvas_item_add_circle,RID, const Point2& , float ,const Color& ); -	FUNC5(canvas_item_add_texture_rect,RID, const Rect2& , RID ,bool ,const Color& ); -	FUNC5(canvas_item_add_texture_rect_region,RID, const Rect2& , RID ,const Rect2& ,const Color& ); - +	FUNC6(canvas_item_add_texture_rect,RID, const Rect2& , RID ,bool ,const Color&,bool ); +	FUNC6(canvas_item_add_texture_rect_region,RID, const Rect2& , RID ,const Rect2& ,const Color&,bool );  	FUNC7(canvas_item_add_style_box,RID, const Rect2& , RID ,const Vector2& ,const Vector2&, bool ,const Color& );  	FUNC6(canvas_item_add_primitive,RID, const Vector<Point2>& , const Vector<Color>& ,const Vector<Point2>& , RID ,float );  	FUNC5(canvas_item_add_polygon,RID, const Vector<Point2>& , const Vector<Color>& ,const Vector<Point2>& , RID ); @@ -1134,18 +1139,54 @@ public:  	FUNC2(canvas_item_set_z,RID,int);  	FUNC2(canvas_item_set_z_as_relative_to_parent,RID,bool); -	FUNC2(canvas_item_set_shader,RID, RID ); -	FUNC1RC(RID,canvas_item_get_shader,RID ); - -	FUNC2(canvas_item_set_use_parent_shader,RID, bool ); - +	FUNC2(canvas_item_set_material,RID, RID ); -	FUNC3(canvas_item_set_shader_param,RID,const StringName&,const Variant&); -	FUNC2RC(Variant,canvas_item_get_shader_param,RID,const StringName&); +	FUNC2(canvas_item_set_use_parent_material,RID, bool );  	FUNC1(canvas_item_clear,RID);  	FUNC1(canvas_item_raise,RID); +	/* CANVAS LIGHT */ +	FUNC0R(RID,canvas_light_create); +	FUNC2(canvas_light_attach_to_canvas,RID,RID); +	FUNC2(canvas_light_set_enabled,RID,bool); +	FUNC2(canvas_light_set_transform,RID,const Matrix32&); +	FUNC2(canvas_light_set_texture,RID,RID); +	FUNC2(canvas_light_set_texture_offset,RID,const Vector2&); +	FUNC2(canvas_light_set_color,RID,const Color&); +	FUNC2(canvas_light_set_height,RID,float); +	FUNC3(canvas_light_set_layer_range,RID,int,int); +	FUNC3(canvas_light_set_z_range,RID,int,int); +	FUNC2(canvas_light_set_item_mask,RID,int); + +	FUNC2(canvas_light_set_subtract_mode,RID,bool); +	FUNC2(canvas_light_set_shadow_enabled,RID,bool); +	FUNC2(canvas_light_set_shadow_buffer_size,RID,int); +	FUNC2(canvas_light_set_shadow_esm_multiplier,RID,float); + + +	/* CANVAS OCCLUDER */ + +	FUNC0R(RID,canvas_light_occluder_create); +	FUNC2(canvas_light_occluder_attach_to_canvas,RID,RID); +	FUNC2(canvas_light_occluder_set_enabled,RID,bool); +	FUNC2(canvas_light_occluder_set_polygon,RID,RID); +	FUNC2(canvas_light_occluder_set_transform,RID,const Matrix32&); +	FUNC2(canvas_light_occluder_set_light_mask,RID,int); + + +	FUNC0R(RID,canvas_occluder_polygon_create); +	FUNC3(canvas_occluder_polygon_set_shape,RID,const DVector<Vector2>&,bool); +	FUNC2(canvas_occluder_polygon_set_shape_as_lines,RID,const DVector<Vector2>&); +	FUNC2(canvas_occluder_polygon_set_cull_mode,RID,CanvasOccluderPolygonCullMode); + +	/* CANVAS MATERIAL */ + +	FUNC0R(RID,canvas_item_material_create); +	FUNC2(canvas_item_material_set_shader,RID,RID); +	FUNC3(canvas_item_material_set_shader_param,RID,const StringName&,const Variant&); +	FUNC2RC(Variant,canvas_item_material_get_shader_param,RID,const StringName&); +	FUNC2(canvas_item_material_set_unshaded,RID,bool);  	/* CURSOR */  	FUNC2(cursor_set_rotation,float , int ); // radians diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index e0238c8042..5ddfaf7967 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -28,6 +28,7 @@  /*************************************************************************/  #include "visual_server.h"  #include "globals.h" +#include "method_bind_ext.inc"  VisualServer *VisualServer::singleton=NULL;  VisualServer* (*VisualServer::create_func)()=NULL; @@ -510,8 +511,9 @@ void VisualServer::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("canvas_item_add_line"),&VisualServer::canvas_item_add_line, DEFVAL(1.0));  	ObjectTypeDB::bind_method(_MD("canvas_item_add_rect"),&VisualServer::canvas_item_add_rect); -	ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect"),&VisualServer::canvas_item_add_texture_rect, DEFVAL(Color(1,1,1))); -	ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect_region"),&VisualServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1,1,1))); +	ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect"),&VisualServer::canvas_item_add_texture_rect, DEFVAL(Color(1,1,1)), DEFVAL(false)); +	ObjectTypeDB::bind_method(_MD("canvas_item_add_texture_rect_region"),&VisualServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1,1,1)), DEFVAL(false)); +  	ObjectTypeDB::bind_method(_MD("canvas_item_add_style_box"),&VisualServer::_canvas_item_add_style_box, DEFVAL(Color(1,1,1)));  //	ObjectTypeDB::bind_method(_MD("canvas_item_add_primitive"),&VisualServer::canvas_item_add_primitive,DEFVAL(Vector<Vector2>()),DEFVAL(RID()));  	ObjectTypeDB::bind_method(_MD("canvas_item_add_circle"),&VisualServer::canvas_item_add_circle); diff --git a/servers/visual_server.h b/servers/visual_server.h index 5721e7acf0..ccf6978ae3 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -684,6 +684,9 @@ public:  	virtual RID viewport_get_render_target_texture(RID p_viewport) const=0;  	virtual void viewport_set_render_target_vflip(RID p_viewport,bool p_enable)=0;  	virtual bool viewport_get_render_target_vflip(RID p_viewport) const=0; +	virtual void viewport_set_render_target_clear_on_new_frame(RID p_viewport,bool p_enable)=0; +	virtual bool viewport_get_render_target_clear_on_new_frame(RID p_viewport) const=0; +	virtual void viewport_render_target_clear(RID p_viewport)=0;  	virtual void viewport_queue_screen_capture(RID p_viewport)=0;  	virtual Image viewport_get_screen_capture(RID p_viewport) const=0; @@ -944,6 +947,8 @@ public:  	virtual RID canvas_create()=0;  	virtual void canvas_set_item_mirroring(RID p_canvas,RID p_item,const Point2& p_mirroring)=0;  	virtual Point2 canvas_get_item_mirroring(RID p_canvas,RID p_item) const=0; +	virtual void canvas_set_modulate(RID p_canvas,const Color& p_color)=0; +  	virtual RID canvas_item_create()=0; @@ -953,6 +958,8 @@ public:  	virtual void canvas_item_set_visible(RID p_item,bool p_visible)=0;  	virtual bool canvas_item_is_visible(RID p_item) const=0; +	virtual void canvas_item_set_light_mask(RID p_item,int p_mask)=0; +  	virtual void canvas_item_set_blend_mode(RID p_canvas_item,MaterialBlendMode p_blend)=0;  	virtual void canvas_item_attach_viewport(RID p_item, RID p_viewport)=0; @@ -974,8 +981,8 @@ public:  	virtual void canvas_item_add_line(RID p_item, const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width=1.0)=0;  	virtual void canvas_item_add_rect(RID p_item, const Rect2& p_rect, const Color& p_color)=0;  	virtual void canvas_item_add_circle(RID p_item, const Point2& p_pos, float p_radius,const Color& p_color)=0; -	virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1))=0; -	virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1))=0; +	virtual void canvas_item_add_texture_rect(RID p_item, const Rect2& p_rect, RID p_texture,bool p_tile=false,const Color& p_modulate=Color(1,1,1),bool p_transpose=false)=0; +	virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2& p_rect, RID p_texture,const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1),bool p_transpose=false)=0;  	virtual void canvas_item_add_style_box(RID p_item, const Rect2& p_rect, RID p_texture,const Vector2& p_topleft, const Vector2& p_bottomright, bool p_draw_center=true,const Color& p_modulate=Color(1,1,1))=0;  	virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, RID p_texture,float p_width=1.0)=0;  	virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), RID p_texture=RID())=0; @@ -991,13 +998,53 @@ public:  	virtual void canvas_item_clear(RID p_item)=0;  	virtual void canvas_item_raise(RID p_item)=0; -	virtual void canvas_item_set_shader(RID p_item, RID p_shader)=0; -	virtual RID canvas_item_get_shader(RID p_item) const=0; +	virtual void canvas_item_set_material(RID p_item, RID p_material)=0; + +	virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable)=0; + +	virtual RID canvas_light_create()=0; +	virtual void canvas_light_attach_to_canvas(RID p_light,RID p_canvas)=0; +	virtual void canvas_light_set_enabled(RID p_light, bool p_enabled)=0; +	virtual void canvas_light_set_transform(RID p_light, const Matrix32& p_transform)=0; +	virtual void canvas_light_set_texture(RID p_light, RID p_texture)=0; +	virtual void canvas_light_set_texture_offset(RID p_light, const Vector2& p_offset)=0; +	virtual void canvas_light_set_color(RID p_light, const Color& p_color)=0; +	virtual void canvas_light_set_height(RID p_light, float p_height)=0; +	virtual void canvas_light_set_z_range(RID p_light, int p_min_z,int p_max_z)=0; +	virtual void canvas_light_set_layer_range(RID p_light, int p_min_layer,int p_max_layer)=0; +	virtual void canvas_light_set_item_mask(RID p_light, int p_mask)=0; + +	virtual void canvas_light_set_subtract_mode(RID p_light, bool p_enable)=0; +	virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled)=0; +	virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size)=0; +	virtual void canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier)=0; + + + +	virtual RID canvas_light_occluder_create()=0; +	virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder,RID p_canvas)=0; +	virtual void canvas_light_occluder_set_enabled(RID p_occluder,bool p_enabled)=0; +	virtual void canvas_light_occluder_set_polygon(RID p_occluder,RID p_polygon)=0; +	virtual void canvas_light_occluder_set_transform(RID p_occluder,const Matrix32& p_xform)=0; +	virtual void canvas_light_occluder_set_light_mask(RID p_occluder,int p_mask)=0; + +	virtual RID canvas_occluder_polygon_create()=0; +	virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon,const DVector<Vector2>& p_shape,bool p_closed)=0; +	virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon,const DVector<Vector2>& p_shape)=0; +	enum CanvasOccluderPolygonCullMode { +		CANVAS_OCCLUDER_POLYGON_CULL_DISABLED, +		CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE, +		CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE, +	}; +	virtual void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon,CanvasOccluderPolygonCullMode p_mode)=0; -	virtual void canvas_item_set_use_parent_shader(RID p_item, bool p_enable)=0; +	/* CANVAS ITEM MATERIAL */ -	virtual void canvas_item_set_shader_param(RID p_canvas_item, const StringName& p_param, const Variant& p_value)=0; -	virtual Variant canvas_item_get_shader_param(RID p_canvas_item, const StringName& p_param) const=0; +	virtual RID canvas_item_material_create()=0; +	virtual void canvas_item_material_set_shader(RID p_material, RID p_shader)=0; +	virtual void canvas_item_material_set_shader_param(RID p_material, const StringName& p_param, const Variant& p_value)=0; +	virtual Variant canvas_item_material_get_shader_param(RID p_material, const StringName& p_param) const=0; +	virtual void canvas_item_material_set_unshaded(RID p_material, bool p_unshaded)=0;  	/* CURSOR */  	virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0)=0; // radians diff --git a/tools/editor/editor_import_export.cpp b/tools/editor/editor_import_export.cpp index 0881739cbe..e6ec11e9d3 100644 --- a/tools/editor/editor_import_export.cpp +++ b/tools/editor/editor_import_export.cpp @@ -1167,10 +1167,36 @@ EditorImportExport* EditorImportExport::singleton=NULL;  void EditorImportExport::add_import_plugin(const Ref<EditorImportPlugin>& p_plugin) { +	// Need to make sure the name is unique if we are going to lookup by it +	ERR_FAIL_COND(by_idx.has(p_plugin->get_name())); +  	by_idx[ p_plugin->get_name() ]=plugins.size();  	plugins.push_back(p_plugin);  } +void EditorImportExport::remove_import_plugin(const Ref<EditorImportPlugin>& p_plugin) { + +	String plugin_name = p_plugin->get_name(); + +	// Keep the indices the same +	// Find the index of the target plugin +	ERR_FAIL_COND(!by_idx.has(plugin_name)); +	int idx = by_idx[plugin_name]; +	int last_idx = plugins.size() - 1; + +	// Swap the last plugin and the target one +	SWAP(plugins[idx], plugins[last_idx]); + +	// Update the index of the old last one +	by_idx[plugins[idx]->get_name()] = idx; + +	// Remove the target plugin's by_idx entry +	by_idx.erase(plugin_name); + +	// Erase the plugin +	plugins.remove(last_idx); +} +  int EditorImportExport::get_import_plugin_count() const{  	return plugins.size(); diff --git a/tools/editor/editor_import_export.h b/tools/editor/editor_import_export.h index b97dde12f2..a4723f41d0 100644 --- a/tools/editor/editor_import_export.h +++ b/tools/editor/editor_import_export.h @@ -271,6 +271,7 @@ public:  	static EditorImportExport* get_singleton() { return singleton; }  	void add_import_plugin(const Ref<EditorImportPlugin>& p_plugin); +	void remove_import_plugin(const Ref<EditorImportPlugin>& p_plugin);  	int get_import_plugin_count() const;  	Ref<EditorImportPlugin> get_import_plugin(int p_idx) const;  	Ref<EditorImportPlugin> get_import_plugin_by_name(const String& p_string) const; diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 005bb0958f..3d42867d9a 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -89,6 +89,8 @@  #include "plugins/animation_player_editor_plugin.h"  #include "plugins/baked_light_editor_plugin.h"  #include "plugins/polygon_2d_editor_plugin.h" +#include "plugins/navigation_polygon_editor_plugin.h" +#include "plugins/light_occluder_2d_editor_plugin.h"  // end  #include "tools/editor/io_plugins/editor_texture_import_plugin.h"  #include "tools/editor/io_plugins/editor_scene_import_plugin.h" @@ -336,6 +338,19 @@ void EditorNode::_vp_resized() {  } +void EditorNode::_rebuild_import_menu() +{ +	PopupMenu* p = import_menu->get_popup(); +	p->clear(); +	p->add_item("Sub-Scene", FILE_IMPORT_SUBSCENE); +	p->add_separator(); +	for (int i = 0; i < editor_import_export->get_import_plugin_count(); i++) { +		p->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(), IMPORT_PLUGIN_BASE + i); +	} +	p->add_separator(); +	p->add_item("Re-Import..", SETTINGS_IMPORT); +} +  void EditorNode::_node_renamed() {  	if (property_editor) @@ -1967,6 +1982,25 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {  				log->add_message("REDO: "+action);  		} break; + +		case EDIT_REVERT: { + +			Node *scene = get_edited_scene(); + +			if (!scene) +				break; +			 +			if (unsaved_cache && !p_confirmed) { +				confirmation->get_ok()->set_text("Revert"); +				confirmation->set_text("This action cannot be undone. Revert anyway?"); +				confirmation->popup_centered(Size2(300,70)); +				break; +			} + +			Error err = load_scene(scene->get_filename()); + +		} break; +  #if 0  		case NODE_EXTERNAL_INSTANCE: { @@ -2388,6 +2422,19 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor) {  } +void EditorNode::add_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) { + +	editor_import_export->add_import_plugin(p_editor_import); +	_rebuild_import_menu(); +} + +void EditorNode::remove_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import) { + +	editor_import_export->remove_import_plugin(p_editor_import); +	_rebuild_import_menu(); +} + +  void EditorNode::set_edited_scene(Node *p_scene) {  	if (edited_scene) { @@ -3152,6 +3199,9 @@ void EditorNode::_bind_methods() {  	ObjectTypeDB::bind_method("_sources_changed",&EditorNode::_sources_changed);  	ObjectTypeDB::bind_method("_fs_changed",&EditorNode::_fs_changed); +	ObjectTypeDB::bind_method(_MD("add_editor_import_plugin", "plugin"), &EditorNode::add_editor_import_plugin); +	ObjectTypeDB::bind_method(_MD("remove_editor_import_plugin", "plugin"), &EditorNode::remove_editor_import_plugin); +	ObjectTypeDB::bind_method(_MD("get_gui_base"), &EditorNode::get_gui_base);  	ADD_SIGNAL( MethodInfo("play_pressed") );  	ADD_SIGNAL( MethodInfo("pause_pressed") ); @@ -3212,6 +3262,11 @@ Error EditorNode::export_platform(const String& p_platform, const String& p_path  	return OK;  } +void EditorNode::show_warning(const String& p_text) { + +	warning->set_text(p_text); +	warning->popup_centered_minsize(); +}  EditorNode::EditorNode() { @@ -3469,6 +3524,8 @@ EditorNode::EditorNode() {  	p->add_separator();  	p->add_item("Project Settings",RUN_SETTINGS);  	p->add_separator(); +	p->add_item("Revert Scene",EDIT_REVERT); +	p->add_separator();  	p->add_item("Quit to Project List",RUN_PROJECT_MANAGER,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_Q);  	p->add_item("Quit",FILE_QUIT,KEY_MASK_CMD+KEY_Q); @@ -3513,8 +3570,6 @@ EditorNode::EditorNode() {  	left_menu_hb->add_child( import_menu );  	p=import_menu->get_popup(); -	p->add_item("Sub-Scene",FILE_IMPORT_SUBSCENE); -	p->add_separator();  	p->connect("item_pressed",this,"_menu_option");  	export_button = memnew( ToolButton ); @@ -3552,7 +3607,7 @@ EditorNode::EditorNode() {  	play_button->set_icon(gui_base->get_icon("MainPlay","EditorIcons"));  	play_button->set_focus_mode(Control::FOCUS_NONE);  	play_button->connect("pressed", this,"_menu_option",make_binds(RUN_PLAY)); -	play_button->set_tooltip("Start the scene (F5)."); +	play_button->set_tooltip("Play the project (F5)."); @@ -3922,6 +3977,8 @@ EditorNode::EditorNode() {  	logo->set_pos(Point2(20,20));  	logo->set_texture(gui_base->get_icon("Logo","EditorIcons") ); +	warning = memnew( AcceptDialog ); +	add_child(warning); @@ -4023,11 +4080,6 @@ EditorNode::EditorNode() {  	editor_import_export->add_import_plugin( Ref<EditorSampleImportPlugin>( memnew(EditorSampleImportPlugin(this))));  	editor_import_export->add_import_plugin( Ref<EditorTranslationImportPlugin>( memnew(EditorTranslationImportPlugin(this)))); - -	for(int i=0;i<editor_import_export->get_import_plugin_count();i++) { -		    import_menu->get_popup()->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(),IMPORT_PLUGIN_BASE+i); -	} -  	editor_import_export->add_export_plugin( Ref<EditorTextureExportPlugin>( memnew(EditorTextureExportPlugin)));  	add_editor_plugin( memnew( CanvasItemEditorPlugin(this) ) ); @@ -4035,7 +4087,8 @@ EditorNode::EditorNode() {  	add_editor_plugin( memnew( ScriptEditorPlugin(this) ) );  	add_editor_plugin( memnew( EditorHelpPlugin(this) ) );  	add_editor_plugin( memnew( AnimationPlayerEditorPlugin(this) ) ); -	add_editor_plugin( memnew( ShaderGraphEditorPlugin(this) ) ); +	add_editor_plugin( memnew( ShaderGraphEditorPlugin(this,true) ) ); +	add_editor_plugin( memnew( ShaderGraphEditorPlugin(this,false) ) );  	add_editor_plugin( memnew( ShaderEditorPlugin(this,true) ) );  	add_editor_plugin( memnew( ShaderEditorPlugin(this,false) ) );  	add_editor_plugin( memnew( CameraEditorPlugin(this) ) ); @@ -4063,6 +4116,8 @@ EditorNode::EditorNode() {  	add_editor_plugin( memnew( PathEditorPlugin(this) ) );  	add_editor_plugin( memnew( BakedLightEditorPlugin(this) ) );  	add_editor_plugin( memnew( Polygon2DEditorPlugin(this) ) ); +	add_editor_plugin( memnew( LightOccluder2DEditorPlugin(this) ) ); +	add_editor_plugin( memnew( NavigationPolygonEditorPlugin(this) ) );  	for(int i=0;i<EditorPlugins::get_plugin_count();i++)  		add_editor_plugin( EditorPlugins::create(i,this) ); @@ -4071,9 +4126,7 @@ EditorNode::EditorNode() {  	circle_step_frame=OS::get_singleton()->get_frames_drawn();;  	circle_step=0; - -	import_menu->get_popup()->add_separator(); -	import_menu->get_popup()->add_item("Re-Import..",SETTINGS_IMPORT); +	_rebuild_import_menu();  	editor_plugin_screen=NULL;  	editor_plugin_over=NULL; diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index 7560c2b149..531eccb546 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -127,6 +127,7 @@ class EditorNode : public Node {  		FILE_EXTERNAL_OPEN_SCENE,  		EDIT_UNDO,  		EDIT_REDO, +		EDIT_REVERT,  		RESOURCE_NEW,  		RESOURCE_LOAD,  		RESOURCE_SAVE, @@ -231,6 +232,7 @@ class EditorNode : public Node {  	ConfirmationDialog *open_recent_confirmation;  	AcceptDialog *accept;  	AcceptDialog *about; +	AcceptDialog *warning;  	//OptimizedPresetsDialog *optimized_presets;  	EditorSettingsDialog *settings_config_dialog; @@ -339,6 +341,8 @@ class EditorNode : public Node {  	void _show_messages();  	void _vp_resized(); +	void _rebuild_import_menu(); +  	void _save_scene(String p_file); @@ -420,6 +424,9 @@ public:  	static void add_editor_plugin(EditorPlugin *p_editor);  	static void remove_editor_plugin(EditorPlugin *p_editor); +	void add_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import); +	void remove_editor_import_plugin(const Ref<EditorImportPlugin>& p_editor_import); +  	void edit_node(Node *p_node);  	void edit_resource(const Ref<Resource>& p_resource); @@ -478,6 +485,9 @@ public:  	Ref<Theme> get_editor_theme() const { return theme; } +	void show_warning(const String& p_text); + +  	Error export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after=false);  	static void register_editor_types(); diff --git a/tools/editor/icons/icon_canvas_item_material.png b/tools/editor/icons/icon_canvas_item_material.png Binary files differnew file mode 100644 index 0000000000..2fe8921653 --- /dev/null +++ b/tools/editor/icons/icon_canvas_item_material.png diff --git a/tools/editor/icons/icon_canvas_modulate.png b/tools/editor/icons/icon_canvas_modulate.png Binary files differnew file mode 100644 index 0000000000..2a34df7793 --- /dev/null +++ b/tools/editor/icons/icon_canvas_modulate.png diff --git a/tools/editor/icons/icon_graph_color_ramp.png b/tools/editor/icons/icon_graph_color_ramp.png Binary files differnew file mode 100644 index 0000000000..9031b5ec53 --- /dev/null +++ b/tools/editor/icons/icon_graph_color_ramp.png diff --git a/tools/editor/icons/icon_graph_curve_map.png b/tools/editor/icons/icon_graph_curve_map.png Binary files differnew file mode 100644 index 0000000000..de5c32f09e --- /dev/null +++ b/tools/editor/icons/icon_graph_curve_map.png diff --git a/tools/editor/icons/icon_graph_default_texture.png b/tools/editor/icons/icon_graph_default_texture.png Binary files differnew file mode 100644 index 0000000000..da77ec9364 --- /dev/null +++ b/tools/editor/icons/icon_graph_default_texture.png diff --git a/tools/editor/icons/icon_light_2d.png b/tools/editor/icons/icon_light_2d.png Binary files differnew file mode 100644 index 0000000000..9162b33090 --- /dev/null +++ b/tools/editor/icons/icon_light_2d.png diff --git a/tools/editor/icons/icon_light_occluder_2d.png b/tools/editor/icons/icon_light_occluder_2d.png Binary files differnew file mode 100644 index 0000000000..c66dd536d3 --- /dev/null +++ b/tools/editor/icons/icon_light_occluder_2d.png diff --git a/tools/editor/icons/icon_navigation_2d.png b/tools/editor/icons/icon_navigation_2d.png Binary files differnew file mode 100644 index 0000000000..8170ecf68c --- /dev/null +++ b/tools/editor/icons/icon_navigation_2d.png diff --git a/tools/editor/icons/icon_navigation_polygon_instance.png b/tools/editor/icons/icon_navigation_polygon_instance.png Binary files differnew file mode 100644 index 0000000000..9f9c318906 --- /dev/null +++ b/tools/editor/icons/icon_navigation_polygon_instance.png diff --git a/tools/editor/icons/icon_occluder_polygon_2d.png b/tools/editor/icons/icon_occluder_polygon_2d.png Binary files differnew file mode 100644 index 0000000000..705794b729 --- /dev/null +++ b/tools/editor/icons/icon_occluder_polygon_2d.png diff --git a/tools/editor/icons/icon_rotate_0.png b/tools/editor/icons/icon_rotate_0.png Binary files differnew file mode 100644 index 0000000000..85a4b4c420 --- /dev/null +++ b/tools/editor/icons/icon_rotate_0.png diff --git a/tools/editor/icons/icon_rotate_180.png b/tools/editor/icons/icon_rotate_180.png Binary files differnew file mode 100644 index 0000000000..c4c516cff5 --- /dev/null +++ b/tools/editor/icons/icon_rotate_180.png diff --git a/tools/editor/icons/icon_rotate_270.png b/tools/editor/icons/icon_rotate_270.png Binary files differnew file mode 100644 index 0000000000..6e0f2e62b8 --- /dev/null +++ b/tools/editor/icons/icon_rotate_270.png diff --git a/tools/editor/icons/icon_rotate_90.png b/tools/editor/icons/icon_rotate_90.png Binary files differnew file mode 100644 index 0000000000..f25b0e99a3 --- /dev/null +++ b/tools/editor/icons/icon_rotate_90.png diff --git a/tools/editor/icons/icon_transpose.png b/tools/editor/icons/icon_transpose.png Binary files differnew file mode 100644 index 0000000000..f9b78bc0fd --- /dev/null +++ b/tools/editor/icons/icon_transpose.png diff --git a/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp index ed228e9a1c..dab6df9a39 100644 --- a/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp +++ b/tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp @@ -4,6 +4,7 @@  #include "os/file_access.h"  #include "tools/editor/editor_settings.h" +  void CollisionPolygon2DEditor::_notification(int p_what) {  	switch(p_what) { diff --git a/tools/editor/plugins/collision_polygon_editor_plugin.cpp b/tools/editor/plugins/collision_polygon_editor_plugin.cpp index b92acb60f9..a6f2085a19 100644 --- a/tools/editor/plugins/collision_polygon_editor_plugin.cpp +++ b/tools/editor/plugins/collision_polygon_editor_plugin.cpp @@ -31,6 +31,8 @@  #include "os/file_access.h"  #include "tools/editor/editor_settings.h"  #include "scene/3d/camera.h" +#include "canvas_item_editor_plugin.h" +  void CollisionPolygonEditor::_notification(int p_what) {  	switch(p_what) { @@ -71,14 +73,14 @@ void CollisionPolygonEditor::_node_removed(Node *p_node) {  Vector2 CollisionPolygonEditor::snap_point(const Vector2& p_point) const {  	return p_point; -	/* -	if (canvas_item_editor->is_snap_active()) { +	 +	if (CanvasItemEditor::get_singleton()->is_snap_active()) { -		return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap()); +		return p_point.snapped(Vector2(1,1)*CanvasItemEditor::get_singleton()->get_snap());  	} else {  		return p_point; -	} ??? */ +	}  }  void CollisionPolygonEditor::_menu_option(int p_option) { @@ -148,7 +150,7 @@ bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const  			Vector2 cpoint(spoint.x,spoint.y); -			//cpoint=snap_point(cpoint); snap? +			cpoint=snap_point(cpoint);  			Vector<Vector2> poly = node->get_polygon(); @@ -362,7 +364,7 @@ bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const  				Vector2 cpoint(spoint.x,spoint.y); -				//cpoint=snap_point(cpoint); +				cpoint=snap_point(cpoint);  				edited_point_pos = cpoint;  				_polygon_draw(); diff --git a/tools/editor/plugins/light_occluder_2d_editor_plugin.cpp b/tools/editor/plugins/light_occluder_2d_editor_plugin.cpp new file mode 100644 index 0000000000..c1fb81b66a --- /dev/null +++ b/tools/editor/plugins/light_occluder_2d_editor_plugin.cpp @@ -0,0 +1,500 @@ +#include "light_occluder_2d_editor_plugin.h" + +#include "canvas_item_editor_plugin.h" +#include "os/file_access.h" +#include "tools/editor/editor_settings.h" + +void LightOccluder2DEditor::_notification(int p_what) { + +	switch(p_what) { + +		case NOTIFICATION_READY: { + +			button_create->set_icon( get_icon("Edit","EditorIcons")); +			button_edit->set_icon( get_icon("MovePoint","EditorIcons")); +			button_edit->set_pressed(true); +			get_tree()->connect("node_removed",this,"_node_removed"); +			create_poly->connect("confirmed",this,"_create_poly"); + +		} break; +		case NOTIFICATION_FIXED_PROCESS: { + + +		} break; +	} + +} +void LightOccluder2DEditor::_node_removed(Node *p_node) { + +	if(p_node==node) { +		node=NULL; +		hide(); +		canvas_item_editor->get_viewport_control()->update(); +	} + +} + + +Vector2 LightOccluder2DEditor::snap_point(const Vector2& p_point) const { + +	if (canvas_item_editor->is_snap_active()) { + +		return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap()); + +	} else { +		return p_point; +	} +} + +void LightOccluder2DEditor::_menu_option(int p_option) { + +	switch(p_option) { + +		case MODE_CREATE: { + +			mode=MODE_CREATE; +			button_create->set_pressed(true); +			button_edit->set_pressed(false); +		} break; +		case MODE_EDIT: { + +			mode=MODE_EDIT; +			button_create->set_pressed(false); +			button_edit->set_pressed(true); +		} break; + +	} +} + +void LightOccluder2DEditor::_wip_close(bool p_closed) { + +	undo_redo->create_action("Create Poly"); +	undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",node->get_occluder_polygon()->get_polygon()); +	undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",wip); +	undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_closed",node->get_occluder_polygon()->is_closed()); +	undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_closed",p_closed); + +	undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); +	undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); +	undo_redo->commit_action(); +	wip.clear(); +	wip_active=false; +	mode=MODE_EDIT; +	button_edit->set_pressed(true); +	button_create->set_pressed(false); +	edited_point=-1; +} + +bool LightOccluder2DEditor::forward_input_event(const InputEvent& p_event) { + + +	if (!node) +		return false; + +	if (node->get_occluder_polygon().is_null()) { +		if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) { +			create_poly->set_text("No OccluderPolygon2D resource on this node.\nCreate and assign one?"); +			create_poly->popup_centered_minsize(); +		} +		return false; +	} +	switch(p_event.type) { + +		case InputEvent::MOUSE_BUTTON: { + +			const InputEventMouseButton &mb=p_event.mouse_button; + +			Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); + + +			Vector2 gpoint = Point2(mb.x,mb.y); +			Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint); +			cpoint=snap_point(cpoint); +			cpoint = node->get_global_transform().affine_inverse().xform(cpoint); + +			Vector<Vector2> poly = Variant(node->get_occluder_polygon()->get_polygon()); + +			//first check if a point is to be added (segment split) +			real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8); + +			switch(mode) { + + +				case MODE_CREATE: { + +					if (mb.button_index==BUTTON_LEFT && mb.pressed) { + + +						if (!wip_active) { + +							wip.clear(); +							wip.push_back( cpoint ); +							wip_active=true; +							edited_point_pos=cpoint; +							canvas_item_editor->get_viewport_control()->update(); +							edited_point=1; +							return true; +						} else { + + +							if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) { +								//wip closed +								_wip_close(true); + +								return true; +							} else if (wip.size()>1 && xform.xform(wip[wip.size()-1]).distance_to(gpoint)<grab_treshold) { +									//wip closed +									_wip_close(false); +									return true; + +							} else { + +								wip.push_back( cpoint ); +								edited_point=wip.size(); +								canvas_item_editor->get_viewport_control()->update(); +								return true; + +								//add wip point +							} +						} +					} else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) { +						_wip_close(true); +					} + + + +				} break; + +				case MODE_EDIT: { + +					if (mb.button_index==BUTTON_LEFT) { +						if (mb.pressed) { + +							if (mb.mod.control) { + + +								if (poly.size() < 3) { + +									undo_redo->create_action("Edit Poly"); +									undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",poly); +									poly.push_back(cpoint); +									undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly); +									undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); +									undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); +									undo_redo->commit_action(); +									return true; +								} + +								//search edges +								int closest_idx=-1; +								Vector2 closest_pos; +								real_t closest_dist=1e10; +								for(int i=0;i<poly.size();i++) { + +									Vector2 points[2] ={ xform.xform(poly[i]), +										xform.xform(poly[(i+1)%poly.size()]) }; + +									Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points); +									if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2) +										continue; //not valid to reuse point + +									real_t d = cp.distance_to(gpoint); +									if (d<closest_dist && d<grab_treshold) { +										closest_dist=d; +										closest_pos=cp; +										closest_idx=i; +									} + + +								} + +								if (closest_idx>=0) { + +									pre_move_edit=poly; +									poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos)); +									edited_point=closest_idx+1; +									edited_point_pos=xform.affine_inverse().xform(closest_pos); +									node->get_occluder_polygon()->set_polygon(Variant(poly)); +									canvas_item_editor->get_viewport_control()->update(); +									return true; +								} +							} else { + +								//look for points to move + +								int closest_idx=-1; +								Vector2 closest_pos; +								real_t closest_dist=1e10; +								for(int i=0;i<poly.size();i++) { + +									Vector2 cp =xform.xform(poly[i]); + +									real_t d = cp.distance_to(gpoint); +									if (d<closest_dist && d<grab_treshold) { +										closest_dist=d; +										closest_pos=cp; +										closest_idx=i; +									} + +								} + +								if (closest_idx>=0) { + +									pre_move_edit=poly; +									edited_point=closest_idx; +									edited_point_pos=xform.affine_inverse().xform(closest_pos); +									canvas_item_editor->get_viewport_control()->update(); +									return true; +								} +							} +						} else { + +							if (edited_point!=-1) { + +								//apply + +								ERR_FAIL_INDEX_V(edited_point,poly.size(),false); +								poly[edited_point]=edited_point_pos; +								undo_redo->create_action("Edit Poly"); +								undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly); +								undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",pre_move_edit); +								undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); +								undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); +								undo_redo->commit_action(); + +								edited_point=-1; +								return true; +							} +						} +					} if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) { + + + +						int closest_idx=-1; +						Vector2 closest_pos; +						real_t closest_dist=1e10; +						for(int i=0;i<poly.size();i++) { + +							Vector2 cp =xform.xform(poly[i]); + +							real_t d = cp.distance_to(gpoint); +							if (d<closest_dist && d<grab_treshold) { +								closest_dist=d; +								closest_pos=cp; +								closest_idx=i; +							} + +						} + +						if (closest_idx>=0) { + + +							undo_redo->create_action("Edit Poly (Remove Point)"); +							undo_redo->add_undo_method(node->get_occluder_polygon().ptr(),"set_polygon",poly); +							poly.remove(closest_idx); +							undo_redo->add_do_method(node->get_occluder_polygon().ptr(),"set_polygon",poly); +							undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); +							undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); +							undo_redo->commit_action(); +							return true; +						} + +					} + + + +				} break; +			} + + + +		} break; +		case InputEvent::MOUSE_MOTION: { + +			const InputEventMouseMotion &mm=p_event.mouse_motion; + +			if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) { + +				Vector2 gpoint = Point2(mm.x,mm.y); +				Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint); +				cpoint=snap_point(cpoint); +				edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint); + +				canvas_item_editor->get_viewport_control()->update(); + +			} + +		} break; +	} + +	return false; +} +void LightOccluder2DEditor::_canvas_draw() { + +	if (!node || !node->get_occluder_polygon().is_valid()) +		return; + +	Control *vpc = canvas_item_editor->get_viewport_control(); + +	Vector<Vector2> poly; + +	if (wip_active) +		poly=wip; +	else +		poly=Variant(node->get_occluder_polygon()->get_polygon()); + + +	Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); +	Ref<Texture> handle= get_icon("EditorHandle","EditorIcons"); + +	int len = poly.size(); + +	for(int i=0;i<poly.size();i++) { + + +		Vector2 p,p2; +		p = i==edited_point ? edited_point_pos : poly[i]; +		if ((wip_active && i==poly.size()-1) || (((i+1)%poly.size())==edited_point)) +			p2=edited_point_pos; +		else +			p2 = poly[(i+1)%poly.size()]; + +		Vector2 point = xform.xform(p); +		Vector2 next_point = xform.xform(p2); + +		Color col=Color(1,0.3,0.1,0.8); + +		if (i==poly.size()-1 && (!node->get_occluder_polygon()->is_closed() || wip_active)) { + +		} else { +			vpc->draw_line(point,next_point,col,2); +		} +		vpc->draw_texture(handle,point-handle->get_size()*0.5); +	} +} + + + +void LightOccluder2DEditor::edit(Node *p_collision_polygon) { + +	if (!canvas_item_editor) { +		canvas_item_editor=CanvasItemEditor::get_singleton(); +	} + +	if (p_collision_polygon) { + +		node=p_collision_polygon->cast_to<LightOccluder2D>(); +		if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw")) +			canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw"); +		wip.clear(); +		wip_active=false; +		edited_point=-1; + +	} else { +		node=NULL; + +		if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw")) +			canvas_item_editor->get_viewport_control()->disconnect("draw",this,"_canvas_draw"); + +	} + +} + +void LightOccluder2DEditor::_create_poly()  { + +	undo_redo->create_action("Create Occluder Polygon"); +	undo_redo->add_do_method(node,"set_occluder_polygon",Ref<OccluderPolygon2D>(memnew( OccluderPolygon2D))); +	undo_redo->add_undo_method(node,"set_occluder_polygon",Variant(REF())); +	undo_redo->commit_action(); +} + +void LightOccluder2DEditor::_bind_methods() { + +	ObjectTypeDB::bind_method(_MD("_menu_option"),&LightOccluder2DEditor::_menu_option); +	ObjectTypeDB::bind_method(_MD("_canvas_draw"),&LightOccluder2DEditor::_canvas_draw); +	ObjectTypeDB::bind_method(_MD("_node_removed"),&LightOccluder2DEditor::_node_removed); +	ObjectTypeDB::bind_method(_MD("_create_poly"),&LightOccluder2DEditor::_create_poly); + +} + + +LightOccluder2DEditor::LightOccluder2DEditor(EditorNode *p_editor) { + +	canvas_item_editor=NULL; +	editor=p_editor; +	undo_redo = editor->get_undo_redo(); + +	add_child( memnew( VSeparator )); +	button_create = memnew( ToolButton ); +	add_child(button_create); +	button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE)); +	button_create->set_toggle_mode(true); +	button_create->set_tooltip("Create a new polygon from scratch"); + +	button_edit = memnew( ToolButton ); +	add_child(button_edit); +	button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT)); +	button_edit->set_toggle_mode(true); +	button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point."); + +	create_poly = memnew( ConfirmationDialog ); +	add_child(create_poly); +	create_poly->get_ok()->set_text("Create"); + + +	//add_constant_override("separation",0); + +#if 0 +	options = memnew( MenuButton ); +	add_child(options); +	options->set_area_as_parent_rect(); +	options->set_text("Polygon"); +	//options->get_popup()->add_item("Parse BBCODE",PARSE_BBCODE); +	options->get_popup()->connect("item_pressed", this,"_menu_option"); +#endif + +	mode = MODE_EDIT; +	wip_active=false; + +} + + +void LightOccluder2DEditorPlugin::edit(Object *p_object) { + +	collision_polygon_editor->edit(p_object->cast_to<Node>()); +} + +bool LightOccluder2DEditorPlugin::handles(Object *p_object) const { + +	return p_object->is_type("LightOccluder2D"); +} + +void LightOccluder2DEditorPlugin::make_visible(bool p_visible) { + +	if (p_visible) { +		collision_polygon_editor->show(); +	} else { + +		collision_polygon_editor->hide(); +		collision_polygon_editor->edit(NULL); +	} + +} + +LightOccluder2DEditorPlugin::LightOccluder2DEditorPlugin(EditorNode *p_node) { + +	editor=p_node; +	collision_polygon_editor = memnew( LightOccluder2DEditor(p_node) ); +	CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor); + +	collision_polygon_editor->hide(); + + + +} + + +LightOccluder2DEditorPlugin::~LightOccluder2DEditorPlugin() +{ +} + diff --git a/tools/editor/plugins/light_occluder_2d_editor_plugin.h b/tools/editor/plugins/light_occluder_2d_editor_plugin.h new file mode 100644 index 0000000000..5fb5631d05 --- /dev/null +++ b/tools/editor/plugins/light_occluder_2d_editor_plugin.h @@ -0,0 +1,87 @@ +#ifndef LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H +#define LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H + + + +#include "tools/editor/editor_plugin.h" +#include "tools/editor/editor_node.h" +#include "scene/2d/light_occluder_2d.h" +#include "scene/gui/tool_button.h" +#include "scene/gui/button_group.h" + +/** +	@author Juan Linietsky <reduzio@gmail.com> +*/ +class CanvasItemEditor; + +class LightOccluder2DEditor : public HBoxContainer { + +	OBJ_TYPE(LightOccluder2DEditor, HBoxContainer ); + +	UndoRedo *undo_redo; +	enum Mode { + +		MODE_CREATE, +		MODE_EDIT, + +	}; + +	Mode mode; + +	ToolButton *button_create; +	ToolButton *button_edit; + +	CanvasItemEditor *canvas_item_editor; +	EditorNode *editor; +	Panel *panel; +	LightOccluder2D *node; +	MenuButton *options; + +	int edited_point; +	Vector2 edited_point_pos; +	Vector<Vector2> pre_move_edit; +	Vector<Vector2> wip; +	bool wip_active; + +	ConfirmationDialog *create_poly; + +	void _wip_close(bool p_closed); +	void _canvas_draw(); +	void _menu_option(int p_option); +	void _create_poly(); + +protected: +	void _notification(int p_what); +	void _node_removed(Node *p_node); +	static void _bind_methods(); +public: + +	Vector2 snap_point(const Vector2& p_point) const; +	bool forward_input_event(const InputEvent& p_event); +	void edit(Node *p_collision_polygon); +	LightOccluder2DEditor(EditorNode *p_editor); +}; + +class LightOccluder2DEditorPlugin : public EditorPlugin { + +	OBJ_TYPE( LightOccluder2DEditorPlugin, EditorPlugin ); + +	LightOccluder2DEditor *collision_polygon_editor; +	EditorNode *editor; + +public: + +	virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); } + +	virtual String get_name() const { return "LightOccluder2D"; } +	bool has_main_screen() const { return false; } +	virtual void edit(Object *p_node); +	virtual bool handles(Object *p_node) const; +	virtual void make_visible(bool p_visible); + +	LightOccluder2DEditorPlugin(EditorNode *p_node); +	~LightOccluder2DEditorPlugin(); + +}; + +#endif // LIGHT_OCCLUDER_2D_EDITOR_PLUGIN_H diff --git a/tools/editor/plugins/navigation_polygon_editor_plugin.cpp b/tools/editor/plugins/navigation_polygon_editor_plugin.cpp new file mode 100644 index 0000000000..599d18c8bb --- /dev/null +++ b/tools/editor/plugins/navigation_polygon_editor_plugin.cpp @@ -0,0 +1,547 @@ +#include "navigation_polygon_editor_plugin.h" + +#include "canvas_item_editor_plugin.h" +#include "os/file_access.h" +#include "tools/editor/editor_settings.h" + +void NavigationPolygonEditor::_notification(int p_what) { + +	switch(p_what) { + +		case NOTIFICATION_READY: { + +			button_create->set_icon( get_icon("Edit","EditorIcons")); +			button_edit->set_icon( get_icon("MovePoint","EditorIcons")); +			button_edit->set_pressed(true); +			get_tree()->connect("node_removed",this,"_node_removed"); +			create_nav->connect("confirmed",this,"_create_nav"); + +		} break; +		case NOTIFICATION_FIXED_PROCESS: { + + +		} break; +	} + +} +void NavigationPolygonEditor::_node_removed(Node *p_node) { + +	if(p_node==node) { +		node=NULL; +		hide(); +		canvas_item_editor->get_viewport_control()->update(); +	} + +} + +void NavigationPolygonEditor::_create_nav()  { + +	undo_redo->create_action("Create Navigation Polygon"); +	undo_redo->add_do_method(node,"set_navigation_polygon",Ref<NavigationPolygon>(memnew( NavigationPolygon))); +	undo_redo->add_undo_method(node,"set_navigation_polygon",Variant(REF())); +	undo_redo->commit_action(); +} + +Vector2 NavigationPolygonEditor::snap_point(const Vector2& p_point) const { + +	if (canvas_item_editor->is_snap_active()) { + +		return p_point.snapped(Vector2(1,1)*canvas_item_editor->get_snap()); + +	} else { +		return p_point; +	} +} + +void NavigationPolygonEditor::_menu_option(int p_option) { + +	switch(p_option) { + +		case MODE_CREATE: { + +			mode=MODE_CREATE; +			button_create->set_pressed(true); +			button_edit->set_pressed(false); +		} break; +		case MODE_EDIT: { + +			mode=MODE_EDIT; +			button_create->set_pressed(false); +			button_edit->set_pressed(true); +		} break; + +	} +} + +void NavigationPolygonEditor::_wip_close() { + + +	if (wip.size()>=3) { + +		undo_redo->create_action("Create Poly"); +		undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"remove_outline",node->get_navigation_polygon()->get_outline_count()); +		undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"add_outline",wip); +		undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines"); +		undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines"); +		undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); +		undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); +		undo_redo->commit_action(); +		mode=MODE_EDIT; +		button_edit->set_pressed(true); +		button_create->set_pressed(false); +	} + +	wip.clear(); +	wip_active=false; +	edited_point=-1; +} + +bool NavigationPolygonEditor::forward_input_event(const InputEvent& p_event) { + + +	if (!node) +		return false; + +	if (node->get_navigation_polygon().is_null()) { +		if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) { +			create_nav->set_text("No NavigationPolygon resource on this node.\nCreate and assign one?"); +			create_nav->popup_centered_minsize(); +		} +		return false; +	} + + +	switch(p_event.type) { + +		case InputEvent::MOUSE_BUTTON: { + +			const InputEventMouseButton &mb=p_event.mouse_button; + +			Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); + + +			Vector2 gpoint = Point2(mb.x,mb.y); +			Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint); +			cpoint=snap_point(cpoint); +			cpoint = node->get_global_transform().affine_inverse().xform(cpoint); + + + +			//first check if a point is to be added (segment split) +			real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8); + +			switch(mode) { + + +				case MODE_CREATE: { + +					if (mb.button_index==BUTTON_LEFT && mb.pressed) { + + +						if (!wip_active) { + +							wip.clear(); +							wip.push_back( cpoint ); +							wip_active=true; +							edited_point_pos=cpoint; +							edited_outline=-1; +							canvas_item_editor->get_viewport_control()->update(); +							edited_point=1; +							return true; +						} else { + + +							if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) { +								//wip closed +								_wip_close(); + +								return true; +							} else { + +								wip.push_back( cpoint ); +								edited_point=wip.size(); +								canvas_item_editor->get_viewport_control()->update(); +								return true; + +								//add wip point +							} +						} +					} else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) { +						_wip_close(); +					} + + + +				} break; + +				case MODE_EDIT: { + +					if (mb.button_index==BUTTON_LEFT) { +						if (mb.pressed) { + +							if (mb.mod.control) { + + +								//search edges +								int closest_outline=-1; +								int closest_idx=-1; +								Vector2 closest_pos; +								real_t closest_dist=1e10; + +								for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) { + + +									DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j); + +									int pc=points.size(); +									DVector<Vector2>::Read poly=points.read(); + +									for(int i=0;i<pc;i++) { + +										Vector2 points[2] ={ xform.xform(poly[i]), +											xform.xform(poly[(i+1)%pc]) }; + +										Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points); +										if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2) +											continue; //not valid to reuse point + +										real_t d = cp.distance_to(gpoint); +										if (d<closest_dist && d<grab_treshold) { +											closest_dist=d; +											closest_outline=j; +											closest_pos=cp; +											closest_idx=i; +										} + + +									} +								} + +								if (closest_idx>=0) { + +									pre_move_edit=node->get_navigation_polygon()->get_outline(closest_outline); +									DVector<Point2> poly = pre_move_edit; +									poly.insert(closest_idx+1,xform.affine_inverse().xform(closest_pos)); +									edited_point=closest_idx+1; +									edited_outline=closest_outline; +									edited_point_pos=xform.affine_inverse().xform(closest_pos); +									node->get_navigation_polygon()->set_outline(closest_outline,poly); +									canvas_item_editor->get_viewport_control()->update(); +									return true; +								} +							} else { + +								//look for points to move +								int closest_outline=-1; +								int closest_idx=-1; +								Vector2 closest_pos; +								real_t closest_dist=1e10; + +								for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) { + + +									DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j); + +									int pc=points.size(); +									DVector<Vector2>::Read poly=points.read(); + +									for(int i=0;i<pc;i++) { + + +										Vector2 cp =xform.xform(poly[i]); + +										real_t d = cp.distance_to(gpoint); +										if (d<closest_dist && d<grab_treshold) { +											closest_dist=d; +											closest_pos=cp; +											closest_outline=j; +											closest_idx=i; +										} +									} +								} + +								if (closest_idx>=0) { + +									pre_move_edit=node->get_navigation_polygon()->get_outline(closest_outline); +									edited_point=closest_idx; +									edited_outline=closest_outline; +									edited_point_pos=xform.affine_inverse().xform(closest_pos); +									canvas_item_editor->get_viewport_control()->update(); +									return true; +								} +							} +						} else { + +							if (edited_point!=-1) { + +								//apply + +								DVector<Vector2> poly = node->get_navigation_polygon()->get_outline(edited_outline); +								ERR_FAIL_INDEX_V(edited_point,poly.size(),false); +								poly.set(edited_point,edited_point_pos); +								undo_redo->create_action("Edit Poly"); +								undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"set_outline",edited_outline,poly); +								undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"set_outline",edited_outline,pre_move_edit); +								undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines"); +								undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines"); +								undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); +								undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); +								undo_redo->commit_action(); + +								edited_point=-1; +								return true; +							} +						} +					} if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) { + +						int closest_outline=-1; +						int closest_idx=-1; +						Vector2 closest_pos; +						real_t closest_dist=1e10; + +						for(int j=0;j<node->get_navigation_polygon()->get_outline_count();j++) { + + +							DVector<Vector2> points=node->get_navigation_polygon()->get_outline(j); + +							int pc=points.size(); +							DVector<Vector2>::Read poly=points.read(); + +							for(int i=0;i<pc;i++) { + + +								Vector2 cp =xform.xform(poly[i]); + +								real_t d = cp.distance_to(gpoint); +								if (d<closest_dist && d<grab_treshold) { +									closest_dist=d; +									closest_pos=cp; +									closest_outline=j; +									closest_idx=i; +								} +							} +						} + +						if (closest_idx>=0) { + + +							DVector<Vector2> poly = node->get_navigation_polygon()->get_outline(closest_outline); + +							if (poly.size()>3) { +								undo_redo->create_action("Edit Poly (Remove Point)"); +								undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"set_outline",closest_outline,poly); +								poly.remove(closest_idx); +								undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"set_outline",closest_outline,poly); +								undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines"); +								undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines"); +								undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); +								undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); +								undo_redo->commit_action(); +							} else { + +								undo_redo->create_action("Remove Poly And Point"); +								undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"add_outline_at_index",poly,closest_outline); +								poly.remove(closest_idx); +								undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"remove_outline",closest_outline); +								undo_redo->add_do_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines"); +								undo_redo->add_undo_method(node->get_navigation_polygon().ptr(),"make_polygons_from_outlines"); +								undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); +								undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); +								undo_redo->commit_action(); + +							} +							return true; +						} +					} + + + +				} break; +			} + + + +		} break; +		case InputEvent::MOUSE_MOTION: { + +			const InputEventMouseMotion &mm=p_event.mouse_motion; + +			if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) { + +				Vector2 gpoint = Point2(mm.x,mm.y); +				Vector2 cpoint = canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint); +				cpoint=snap_point(cpoint); +				edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint); + +				canvas_item_editor->get_viewport_control()->update(); + +			} + +		} break; +	} + +	return false; +} +void NavigationPolygonEditor::_canvas_draw() { + +	if (!node) +		return; + +	Control *vpc = canvas_item_editor->get_viewport_control(); +	if (node->get_navigation_polygon().is_null()) +			return; + +	Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); +	Ref<Texture> handle= get_icon("EditorHandle","EditorIcons"); + + + +	for(int j=-1;j<node->get_navigation_polygon()->get_outline_count();j++)	{ +		Vector<Vector2> poly; + +		if (wip_active && j==edited_outline) { +			poly=wip; +		} else { +			if (j==-1) +				continue; +			poly = Variant(node->get_navigation_polygon()->get_outline(j)); +		} + +		int len = poly.size(); + +		for(int i=0;i<poly.size();i++) { + + +			Vector2 p,p2; +			p = (j==edited_outline && i==edited_point) ? edited_point_pos : poly[i]; +			if (j==edited_outline && ((wip_active && i==poly.size()-1) || (((i+1)%poly.size())==edited_point))) +				p2=edited_point_pos; +			else +				p2 = poly[(i+1)%poly.size()]; + +			Vector2 point = xform.xform(p); +			Vector2 next_point = xform.xform(p2); + +			Color col=Color(1,0.3,0.1,0.8); +			vpc->draw_line(point,next_point,col,2); +			vpc->draw_texture(handle,point-handle->get_size()*0.5); +		} +	} +} + + + +void NavigationPolygonEditor::edit(Node *p_collision_polygon) { + +	if (!canvas_item_editor) { +		canvas_item_editor=CanvasItemEditor::get_singleton(); +	} + +	if (p_collision_polygon) { + +		node=p_collision_polygon->cast_to<NavigationPolygonInstance>(); +		if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw")) +			canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw"); +		wip.clear(); +		wip_active=false; +		edited_point=-1; + +	} else { +		node=NULL; + +		if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw")) +			canvas_item_editor->get_viewport_control()->disconnect("draw",this,"_canvas_draw"); + +	} + +} + +void NavigationPolygonEditor::_bind_methods() { + +	ObjectTypeDB::bind_method(_MD("_menu_option"),&NavigationPolygonEditor::_menu_option); +	ObjectTypeDB::bind_method(_MD("_canvas_draw"),&NavigationPolygonEditor::_canvas_draw); +	ObjectTypeDB::bind_method(_MD("_node_removed"),&NavigationPolygonEditor::_node_removed); +	ObjectTypeDB::bind_method(_MD("_create_nav"),&NavigationPolygonEditor::_create_nav); + +} + +NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) { + +	canvas_item_editor=NULL; +	editor=p_editor; +	undo_redo = editor->get_undo_redo(); + +	add_child( memnew( VSeparator )); +	button_create = memnew( ToolButton ); +	add_child(button_create); +	button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE)); +	button_create->set_toggle_mode(true); +	button_create->set_tooltip("Create a new polygon from scratch"); + +	button_edit = memnew( ToolButton ); +	add_child(button_edit); +	button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT)); +	button_edit->set_toggle_mode(true); +	button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point."); +	create_nav = memnew( ConfirmationDialog ); +	add_child(create_nav); +	create_nav->get_ok()->set_text("Create"); + + +	//add_constant_override("separation",0); + +#if 0 +	options = memnew( MenuButton ); +	add_child(options); +	options->set_area_as_parent_rect(); +	options->set_text("Polygon"); +	//options->get_popup()->add_item("Parse BBCODE",PARSE_BBCODE); +	options->get_popup()->connect("item_pressed", this,"_menu_option"); +#endif + +	mode = MODE_EDIT; +	wip_active=false; +	edited_outline=-1; + +} + + +void NavigationPolygonEditorPlugin::edit(Object *p_object) { + +	collision_polygon_editor->edit(p_object->cast_to<Node>()); +} + +bool NavigationPolygonEditorPlugin::handles(Object *p_object) const { + +	return p_object->is_type("NavigationPolygonInstance"); +} + +void NavigationPolygonEditorPlugin::make_visible(bool p_visible) { + +	if (p_visible) { +		collision_polygon_editor->show(); +	} else { + +		collision_polygon_editor->hide(); +		collision_polygon_editor->edit(NULL); +	} + +} + +NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) { + +	editor=p_node; +	collision_polygon_editor = memnew( NavigationPolygonEditor(p_node) ); +	CanvasItemEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor); + +	collision_polygon_editor->hide(); + + + +} + + +NavigationPolygonEditorPlugin::~NavigationPolygonEditorPlugin() +{ +} + diff --git a/tools/editor/plugins/navigation_polygon_editor_plugin.h b/tools/editor/plugins/navigation_polygon_editor_plugin.h new file mode 100644 index 0000000000..a86d28c8a8 --- /dev/null +++ b/tools/editor/plugins/navigation_polygon_editor_plugin.h @@ -0,0 +1,91 @@ +#ifndef NAVIGATIONPOLYGONEDITORPLUGIN_H +#define NAVIGATIONPOLYGONEDITORPLUGIN_H + + + +#include "tools/editor/editor_plugin.h" +#include "tools/editor/editor_node.h" +#include "scene/2d/navigation_polygon.h" +#include "scene/gui/tool_button.h" +#include "scene/gui/button_group.h" + +/** +	@author Juan Linietsky <reduzio@gmail.com> +*/ +class CanvasItemEditor; + +class NavigationPolygonEditor : public HBoxContainer { + +	OBJ_TYPE(NavigationPolygonEditor, HBoxContainer ); + +	UndoRedo *undo_redo; +	enum Mode { + +		MODE_CREATE, +		MODE_EDIT, + +	}; + +	Mode mode; + +	ToolButton *button_create; +	ToolButton *button_edit; + +	ConfirmationDialog *create_nav; + +	CanvasItemEditor *canvas_item_editor; +	EditorNode *editor; +	Panel *panel; +	NavigationPolygonInstance *node; +	MenuButton *options; + +	int edited_outline; +	int edited_point; +	Vector2 edited_point_pos; +	DVector<Vector2> pre_move_edit; +	Vector<Vector2> wip; +	bool wip_active; + + +	void _wip_close(); +	void _canvas_draw(); +	void _create_nav(); + +	void _menu_option(int p_option); + +protected: +	void _notification(int p_what); +	void _node_removed(Node *p_node); +	static void _bind_methods(); +public: + +	Vector2 snap_point(const Vector2& p_point) const; +	bool forward_input_event(const InputEvent& p_event); +	void edit(Node *p_collision_polygon); +	NavigationPolygonEditor(EditorNode *p_editor); +}; + +class NavigationPolygonEditorPlugin : public EditorPlugin { + +	OBJ_TYPE( NavigationPolygonEditorPlugin, EditorPlugin ); + +	NavigationPolygonEditor *collision_polygon_editor; +	EditorNode *editor; + +public: + +	virtual bool forward_input_event(const InputEvent& p_event) { return collision_polygon_editor->forward_input_event(p_event); } + +	virtual String get_name() const { return "NavigationPolygonInstance"; } +	bool has_main_screen() const { return false; } +	virtual void edit(Object *p_node); +	virtual bool handles(Object *p_node) const; +	virtual void make_visible(bool p_visible); + +	NavigationPolygonEditorPlugin(EditorNode *p_node); +	~NavigationPolygonEditorPlugin(); + +}; + + +#endif // NAVIGATIONPOLYGONEDITORPLUGIN_H diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp index d90597ddfb..1349d5ccab 100644 --- a/tools/editor/plugins/script_editor_plugin.cpp +++ b/tools/editor/plugins/script_editor_plugin.cpp @@ -631,7 +631,10 @@ bool ScriptEditor::_test_script_times_on_disk() {  	if (!all_ok) -		disk_changed->call_deferred("popup_centered_ratio",0.5); +		if (bool(EDITOR_DEF("text_editor/auto_reload_changed_scripts",false))) +			script_editor->_reload_scripts(); +		else +			disk_changed->call_deferred("popup_centered_ratio",0.5);  	return all_ok;  } @@ -1607,7 +1610,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {  	edit_menu->get_popup()->add_item("Clone Down",EDIT_CLONE_DOWN,KEY_MASK_CMD|KEY_B);  	edit_menu->get_popup()->add_separator();  #ifdef OSX_ENABLED -	edit_menu->get_popup()->add_item("Complete Symbol",EDIT_COMPLETE,KEY_MASK_META|KEY_SPACE); +	edit_menu->get_popup()->add_item("Complete Symbol",EDIT_COMPLETE,KEY_MASK_CTRL|KEY_SPACE);  #else  	edit_menu->get_popup()->add_item("Complete Symbol",EDIT_COMPLETE,KEY_MASK_CMD|KEY_SPACE);  #endif @@ -1806,6 +1809,7 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {  	script_editor->hide(); +	EDITOR_DEF("text_editor/auto_reload_changed_scripts",false);  	EDITOR_DEF("external_editor/use_external_editor",false);  	EDITOR_DEF("external_editor/exec_path","");  	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"external_editor/exec_path",PROPERTY_HINT_GLOBAL_FILE)); diff --git a/tools/editor/plugins/shader_editor_plugin.cpp b/tools/editor/plugins/shader_editor_plugin.cpp index 81b5cd8f78..2fcd4e8cd1 100644 --- a/tools/editor/plugins/shader_editor_plugin.cpp +++ b/tools/editor/plugins/shader_editor_plugin.cpp @@ -396,7 +396,7 @@ void ShaderEditor::edit(const Ref<Shader>& p_shader) {  		light_editor->set_edited_shader(shader,ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT);  	} -	vertex_editor->set_edited_shader(shader,ShaderLanguage::SHADER_MATERIAL_VERTEX); +	//vertex_editor->set_edited_shader(shader,ShaderLanguage::SHADER_MATERIAL_VERTEX);  	// see if already has it diff --git a/tools/editor/plugins/shader_graph_editor_plugin.cpp b/tools/editor/plugins/shader_graph_editor_plugin.cpp index 0a206c4a45..508e8b4cba 100644 --- a/tools/editor/plugins/shader_graph_editor_plugin.cpp +++ b/tools/editor/plugins/shader_graph_editor_plugin.cpp @@ -32,6 +32,642 @@  #include "scene/gui/menu_button.h"  #include "scene/gui/panel.h"  #include "spatial_editor_plugin.h" +#include "os/keyboard.h" +#include "canvas_item_editor_plugin.h" + +void GraphColorRampEdit::_input_event(const InputEvent& p_event) { + +	if (p_event.type==InputEvent::KEY && p_event.key.pressed && p_event.key.scancode==KEY_DELETE && grabbed!=-1) { + +		points.remove(grabbed); +		grabbed=-1; +		update(); +		emit_signal("ramp_changed"); +		accept_event(); +	} + +	if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) { + +		update(); +		int x = p_event.mouse_button.x; +		int total_w = get_size().width-get_size().height-3; +		if (x>total_w+3) { + +			if (grabbed==-1) +				return; +			Size2 ms = Size2(350, picker->get_combined_minimum_size().height+10); +			picker->set_color(points[grabbed].color); +			popup->set_pos(get_global_pos()-Size2(0,ms.height)); +			popup->set_size(ms); +			popup->popup(); +			return; +		} + + +		float ofs = CLAMP(x/float(total_w),0,1); + +		grabbed=-1; +		grabbing=true; +		int pos=-1; +		for(int i=0;i<points.size();i++) { + +			if (ABS(x-points[i].offset*total_w)<4) { +				grabbed=i; +			} +			if (points[i].offset<ofs) +				pos=i; +		} + +		grabbed_at=ofs; +		//grab or select +		if (grabbed!=-1) { +			return; +		} +		//insert + + +		Point p; +		p.offset=ofs; + +		Point prev; +		Point next; + +		if (pos==-1) { + +			prev.color=Color(0,0,0); +			prev.offset=0; +			if (points.size()) { +				next=points[0]; +			} else { +				next.color=Color(1,1,1); +				next.offset=1.0; +			} +		} else  { + +			if (pos==points.size()-1) { +				next.color=Color(1,1,1); +				next.offset=1.0; +			} else { +				next=points[pos+1]; +			} +			prev=points[pos]; + +		} + +		p.color=prev.color.linear_interpolate(next.color,(p.offset-prev.offset)/(next.offset-prev.offset)); + +		points.push_back(p); +		points.sort(); +		for(int i=0;i<points.size();i++) { +			if (points[i].offset==ofs) { +				grabbed=i; +				break; +			} +		} + +		emit_signal("ramp_changed"); + +	} + +	if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && !p_event.mouse_button.pressed) { + +		if (grabbing) { +			grabbing=false; +			emit_signal("ramp_changed"); +		} +		update(); +	} + +	if (p_event.type==InputEvent::MOUSE_MOTION && grabbing) { + +		int total_w = get_size().width-get_size().height-3; + +		int x = p_event.mouse_motion.x; +		float newofs = CLAMP(x/float(total_w),0,1); + +		bool valid=true; +		for(int i=0;i<points.size();i++) { + +			if (points[i].offset==newofs && i!=grabbed) { +				valid=false; +			} +		} + +		if (!valid) +			return; + +		points[grabbed].offset=newofs; + +		points.sort(); +		for(int i=0;i<points.size();i++) { +			if (points[i].offset==newofs) { +				grabbed=i; +				break; +			} +		} + +		emit_signal("ramp_changed"); + +		update(); +	} +} + +void GraphColorRampEdit::_notification(int p_what){ + +	if (p_what==NOTIFICATION_ENTER_TREE) { +		picker->connect("color_changed",this,"_color_changed"); +	} +	if (p_what==NOTIFICATION_DRAW) { + + +		Point prev; +		prev.offset=0; +		prev.color=Color(0,0,0); +		int w = get_size().x; +		int h = get_size().y; + +		int total_w = get_size().width-get_size().height-3; + +		for(int i=-1;i<points.size();i++) { + +			Point next; +			if (i+1==points.size()) { +				next.color=Color(1,1,1); +				next.offset=1; +			} else { +				next=points[i+1]; +			} + +			if (prev.offset==next.offset) { +				prev=next; +				continue; +			} + +			Vector<Vector2> points; +			Vector<Color> colors; +			points.push_back(Vector2(prev.offset*total_w,h)); +			points.push_back(Vector2(prev.offset*total_w,0)); +			points.push_back(Vector2(next.offset*total_w,0)); +			points.push_back(Vector2(next.offset*total_w,h)); +			colors.push_back(prev.color); +			colors.push_back(prev.color); +			colors.push_back(next.color); +			colors.push_back(next.color); +			draw_primitive(points,colors,Vector<Point2>()); +			prev=next; +		} + +		for(int i=0;i<points.size();i++) { + +			Color col=i==grabbed?Color(1,0.0,0.0,0.9):Color(1,1,1,0.8); + +			draw_line(Vector2(points[i].offset*total_w,0),Vector2(points[i].offset*total_w,h-1),Color(0,0,0,0.7)); +			draw_line(Vector2(points[i].offset*total_w-1,h/2),Vector2(points[i].offset*total_w-1,h-1),col); +			draw_line(Vector2(points[i].offset*total_w+1,h/2),Vector2(points[i].offset*total_w+1,h-1),col); +			draw_line(Vector2(points[i].offset*total_w-1,h/2),Vector2(points[i].offset*total_w+1,h/2),col); +			draw_line(Vector2(points[i].offset*total_w-1,h-1),Vector2(points[i].offset*total_w+1,h-1),col); + +		} + +		if (grabbed!=-1) { + +			draw_rect(Rect2(total_w+3,0,h,h),points[grabbed].color); +		} + +		if (has_focus()) { + +			draw_line(Vector2(-1,-1),Vector2(total_w+1,-1),Color(1,1,1,0.6)); +			draw_line(Vector2(total_w+1,-1),Vector2(total_w+1,h+1),Color(1,1,1,0.6)); +			draw_line(Vector2(total_w+1,h+1),Vector2(-1,h+1),Color(1,1,1,0.6)); +			draw_line(Vector2(-1,-1),Vector2(-1,h+1),Color(1,1,1,0.6)); +		} + +	} +} + +Size2 GraphColorRampEdit::get_minimum_size() const { + +	return Vector2(0,16); +} + + +void GraphColorRampEdit::_color_changed(const Color& p_color) { + +	if (grabbed==-1) +		return; +	points[grabbed].color=p_color; +	update(); +	emit_signal("ramp_changed"); + +} + +void GraphColorRampEdit::set_ramp(const Vector<float>& p_offsets,const Vector<Color>& p_colors) { + +	ERR_FAIL_COND(p_offsets.size()!=p_colors.size()); +	points.clear(); +	for(int i=0;i<p_offsets.size();i++) { +		Point p; +		p.offset=p_offsets[i]; +		p.color=p_colors[i]; +		points.push_back(p); +	} + +	points.sort(); +	update(); +} + +Vector<float> GraphColorRampEdit::get_offsets() const{ +	Vector<float> ret; +	for(int i=0;i<points.size();i++) +		ret.push_back(points[i].offset); +	return ret; +} +Vector<Color> GraphColorRampEdit::get_colors() const{ + +	Vector<Color> ret; +	for(int i=0;i<points.size();i++) +		ret.push_back(points[i].color); +	return ret; +} + + +void GraphColorRampEdit::_bind_methods(){ + +	ObjectTypeDB::bind_method(_MD("_input_event"),&GraphColorRampEdit::_input_event); +	ObjectTypeDB::bind_method(_MD("_color_changed"),&GraphColorRampEdit::_color_changed); +	ADD_SIGNAL(MethodInfo("ramp_changed")); +} + +GraphColorRampEdit::GraphColorRampEdit(){ + +	grabbed=-1; +	grabbing=false; +	set_focus_mode(FOCUS_ALL); + +	popup = memnew( PopupPanel ); +	picker = memnew( ColorPicker ); +	popup->add_child(picker); +	popup->set_child_rect(picker); +	add_child(popup); + +} +//////////// + +void GraphCurveMapEdit::_input_event(const InputEvent& p_event) { + +	if (p_event.type==InputEvent::KEY && p_event.key.pressed && p_event.key.scancode==KEY_DELETE && grabbed!=-1) { + +		points.remove(grabbed); +		grabbed=-1; +		update(); +		emit_signal("curve_changed"); +		accept_event(); +	} + +	if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) { + +		update(); +		Point2 p = Vector2(p_event.mouse_button.x,p_event.mouse_button.y)/get_size(); +		p.y=1.0-p.y; +		grabbed=-1; +		grabbing=true; + +		for(int i=0;i<points.size();i++) { + +			Vector2 ps = p*get_size(); +			Vector2 pt = Vector2(points[i].offset,points[i].height)*get_size(); +			if (ps.distance_to(pt)<4) { +				grabbed=i; +			} + +		} + + +		//grab or select +		if (grabbed!=-1) { +			return; +		} +		//insert + + +		Point np; +		np.offset=p.x; +		np.height=p.y; + +		points.push_back(np); +		points.sort(); +		for(int i=0;i<points.size();i++) { +			if (points[i].offset==p.x && points[i].height==p.y) { +				grabbed=i; +				break; +			} +		} + +		emit_signal("curve_changed"); + +	} + +	if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && !p_event.mouse_button.pressed) { + +		if (grabbing) { +			grabbing=false; +			emit_signal("curve_changed"); +		} +		update(); +	} + +	if (p_event.type==InputEvent::MOUSE_MOTION && grabbing) { + +		Point2 p = Vector2(p_event.mouse_button.x,p_event.mouse_button.y)/get_size(); +		p.y=1.0-p.y; + +		p.x = CLAMP(p.x,0.0,1.0); +		p.y = CLAMP(p.y,0.0,1.0); + +		bool valid=true; + +		for(int i=0;i<points.size();i++) { + +			if (points[i].offset==p.x && points[i].height==p.y && i!=grabbed) { +				valid=false; +			} +		} + +		if (!valid) +			return; + +		points[grabbed].offset=p.x; +		points[grabbed].height=p.y; + +		points.sort(); +		for(int i=0;i<points.size();i++) { +			if (points[i].offset==p.x && points[i].height==p.y) { +				grabbed=i; +				break; +			} +		} + +		emit_signal("curve_changed"); + +		update(); +	} +} + +void GraphCurveMapEdit::_plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d) { + +	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=get_size().x; +	int ymax=get_size().y; + +	/* 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); + +/*	if (fix255) +	{ +		cd->curve[cd->outline][lastx] = lasty; +	} +	else +	{ +		cd->curve_ptr[cd->outline][lastx] = lasty; +		if(gb_debug) printf("bender_plot_curve xmax:%d ymax:%d\n", (int)xmax, (int)ymax); +	} +*/ +	/* 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)) +		{ +#if 0 +			/* +			if(fix255) +			{ +				/* use fixed array size (for the curve graph) */ +				cd->curve[cd->outline][newx] = newy; +			} +			else +			{ +				/* use dynamic allocated curve_ptr (for the real curve) */ +				cd->curve_ptr[cd->outline][newx] = newy; + +				if(gb_debug) printf("outline: %d  cX: %d cY: %d\n", (int)cd->outline, (int)newx, (int)newy); +			} +#endif +			draw_line(Vector2(lastx,ymax-lasty),Vector2(newx,ymax-newy),Color(0.8,0.8,0.8,0.8),2.0); +		} + +		lastx = newx; +		lasty = newy; +	} +} + + +void GraphCurveMapEdit::_notification(int p_what){ + +	if (p_what==NOTIFICATION_DRAW) { + +		draw_style_box(get_stylebox("bg","Tree"),Rect2(Point2(),get_size())); + +		int w = get_size().x; +		int h = get_size().y; + +		Vector2 prev=Vector2(0,0); +		Vector2 prev2=Vector2(0,0); + +		for(int i=-1;i<points.size();i++) { + +			Vector2 next; +			Vector2 next2; +			if (i+1>=points.size()) { +				next=Vector2(1,1); +			} else { +				next=Vector2(points[i+1].offset,points[i+1].height); +			} + +			if (i+2>=points.size()) { +				next2=Vector2(1,1); +			} else { +				next2=Vector2(points[i+2].offset,points[i+2].height); +			} + +			/*if (i==-1 && prev.offset==next.offset) { +				prev=next; +				continue; +			}*/ + +			_plot_curve(prev2,prev,next,next2); + +			prev2=prev; +			prev=next; +		} + +		for(int i=0;i<points.size();i++) { + +			Color col=i==grabbed?Color(1,0.0,0.0,0.9):Color(1,1,1,0.8); + + +			draw_rect(Rect2( Vector2(points[i].offset,1.0-points[i].height)*get_size()-Vector2(2,2),Vector2(5,5)),col); +		} + +/*		if (grabbed!=-1) { + +			draw_rect(Rect2(total_w+3,0,h,h),points[grabbed].color); +		} +*/ +		if (has_focus()) { + +			draw_line(Vector2(-1,-1),Vector2(w+1,-1),Color(1,1,1,0.6)); +			draw_line(Vector2(w+1,-1),Vector2(w+1,h+1),Color(1,1,1,0.6)); +			draw_line(Vector2(w+1,h+1),Vector2(-1,h+1),Color(1,1,1,0.6)); +			draw_line(Vector2(-1,-1),Vector2(-1,h+1),Color(1,1,1,0.6)); +		} + +	} +} + +Size2 GraphCurveMapEdit::get_minimum_size() const { + +	return Vector2(64,64); +} + + + +void GraphCurveMapEdit::set_points(const Vector<Vector2>& p_points) { + + +	points.clear(); +	for(int i=0;i<p_points.size();i++) { +		Point p; +		p.offset=p_points[i].x; +		p.height=p_points[i].y; +		points.push_back(p); +	} + +	points.sort(); +	update(); +} + +Vector<Vector2> GraphCurveMapEdit::get_points() const { +	Vector<Vector2> ret; +	for(int i=0;i<points.size();i++) +		ret.push_back(Vector2(points[i].offset,points[i].height)); +	return ret; +} + +void GraphCurveMapEdit::_bind_methods(){ + +	ObjectTypeDB::bind_method(_MD("_input_event"),&GraphCurveMapEdit::_input_event); +	ADD_SIGNAL(MethodInfo("curve_changed")); +} + +GraphCurveMapEdit::GraphCurveMapEdit(){ + +	grabbed=-1; +	grabbing=false; +	set_focus_mode(FOCUS_ALL); + +} +  ////cbacks  /// @@ -306,6 +942,84 @@ void ShaderGraphView::_comment_edited(int p_id,Node* p_button) {  } +void ShaderGraphView::_color_ramp_changed(int p_id,Node* p_ramp) { + +	GraphColorRampEdit *cr=p_ramp->cast_to<GraphColorRampEdit>(); + +	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + + +	Vector<float> offsets=cr->get_offsets(); +	Vector<Color> colors=cr->get_colors(); + +	DVector<float> new_offsets; +	DVector<Color> new_colors; +	{ +		new_offsets.resize(offsets.size()); +		new_colors.resize(colors.size()); +		DVector<float>::Write ow=new_offsets.write(); +		DVector<Color>::Write cw=new_colors.write(); +		for(int i=0;i<new_offsets.size();i++) { +			ow[i]=offsets[i]; +			cw[i]=colors[i]; +		} + +	} + + +	DVector<float> old_offsets=graph->color_ramp_node_get_offsets(type,p_id); +	DVector<Color> old_colors=graph->color_ramp_node_get_colors(type,p_id); + +	if (old_offsets.size()!=new_offsets.size()) +		ur->create_action("Add/Remove to Color Ramp"); +	else +		ur->create_action("Modify Color Ramp",true); + +	ur->add_do_method(graph.ptr(),"color_ramp_node_set_ramp",type,p_id,new_colors,new_offsets); +	ur->add_undo_method(graph.ptr(),"color_ramp_node_set_ramp",type,p_id,old_colors,old_offsets); +	ur->add_do_method(this,"_update_graph"); +	ur->add_undo_method(this,"_update_graph"); +	block_update=true; +	ur->commit_action(); +	block_update=false; +} + +void ShaderGraphView::_curve_changed(int p_id,Node* p_curve) { + +	GraphCurveMapEdit *cr=p_curve->cast_to<GraphCurveMapEdit>(); + +	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + + +	Vector<Point2> points=cr->get_points(); + +	DVector<Vector2> new_points; +	{ +		new_points.resize(points.size()); +		DVector<Vector2>::Write ow=new_points.write(); +		for(int i=0;i<new_points.size();i++) { +			ow[i]=points[i]; +		} + +	} + + +	DVector<Vector2> old_points=graph->curve_map_node_get_points(type,p_id); + +	if (old_points.size()!=new_points.size()) +		ur->create_action("Add/Remove to Curve Map"); +	else +		ur->create_action("Modify Curve Map",true); + +	ur->add_do_method(graph.ptr(),"curve_map_node_set_points",type,p_id,new_points); +	ur->add_undo_method(graph.ptr(),"curve_map_node_set_points",type,p_id,old_points); +	ur->add_do_method(this,"_update_graph"); +	ur->add_undo_method(this,"_update_graph"); +	block_update=true; +	ur->commit_action(); +	block_update=false; +} +  void ShaderGraphView::_input_name_changed(const String& p_name, int p_id, Node *p_line_edit) { @@ -1026,6 +1740,96 @@ void ShaderGraphView::_create_node(int p_id) {  			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());  		} break; // vec3 interpolation  (with optional curve) +		case ShaderGraph::NODE_COLOR_RAMP: { + +			gn->set_title("ColorRamp"); +			GraphColorRampEdit * ramp  = memnew( GraphColorRampEdit ); + +			DVector<real_t> offsets = graph->color_ramp_node_get_offsets(type,p_id); +			DVector<Color> colors = graph->color_ramp_node_get_colors(type,p_id); + +			int oc = offsets.size(); + +			if (oc) { +				DVector<real_t>::Read rofs = offsets.read(); +				DVector<Color>::Read rcol = colors.read(); + +				Vector<float> ofsv; +				Vector<Color> colorv; +				for(int i=0;i<oc;i++) { +					ofsv.push_back(rofs[i]); +					colorv.push_back(rcol[i]); +				} + +				ramp->set_ramp(ofsv,colorv); + +			} + +			ramp->connect("ramp_changed",this,"_color_ramp_changed",varray(p_id,ramp)); +			ramp->set_custom_minimum_size(Size2(128,1)); +			gn->add_child(ramp); + + +			HBoxContainer *hbc = memnew( HBoxContainer ); +			hbc->add_constant_override("separation",0); +			hbc->add_child( memnew(Label("c"))); +			hbc->add_spacer(); +			Label *l=memnew(Label("rgb")); +			l->set_align(Label::ALIGN_RIGHT); +			hbc->add_child( l); +			gn->add_child(hbc); +			l=memnew(Label("alpha")); +			l->set_align(Label::ALIGN_RIGHT); +			gn->add_child( l); + + +			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); +			gn->set_slot(2,false,ShaderGraph::SLOT_MAX,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + +		} break; // scalar interpolation (with optional curve) +		case ShaderGraph::NODE_CURVE_MAP: { + +			gn->set_title("CurveMap"); +			GraphCurveMapEdit * map  = memnew( GraphCurveMapEdit ); + +			DVector<Vector2> points = graph->curve_map_node_get_points(type,p_id); + +			int oc = points.size(); + +			if (oc) { +				DVector<Vector2>::Read rofs = points.read(); + + +				Vector<Vector2> ofsv; +				for(int i=0;i<oc;i++) { +					ofsv.push_back(rofs[i]); +				} + +				map->set_points(ofsv); + +			} +			map->connect("curve_changed",this,"_curve_changed",varray(p_id,map)); + +			//map->connect("map_changed",this,"_curve_map_changed",varray(p_id,map)); +			map->set_custom_minimum_size(Size2(128,64)); +			gn->add_child(map); + +			HBoxContainer *hbc = memnew( HBoxContainer ); +			hbc->add_constant_override("separation",0); +			hbc->add_child( memnew(Label("c"))); +			hbc->add_spacer(); +			Label *l=memnew(Label("cmap")); +			l->set_align(Label::ALIGN_RIGHT); +			hbc->add_child( l); +			gn->add_child(hbc); + + +			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + +		} break; // scalar interpolation (with optional curve) +  		case ShaderGraph::NODE_SCALAR_INPUT: {  			gn->set_title("ScalarUniform"); @@ -1173,6 +1977,28 @@ void ShaderGraphView::_create_node(int p_id) {  			gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);  		} break; // cubemap input (assignable in material) +		case ShaderGraph::NODE_DEFAULT_TEXTURE: { + +			gn->set_title("CanvasItemTex"); +			HBoxContainer *hbc = memnew( HBoxContainer ); +			hbc->add_constant_override("separation",0); +			hbc->add_child( memnew(Label("UV"))); +			hbc->add_spacer(); +			Label *l=memnew(Label("RGB")); +			l->set_align(Label::ALIGN_RIGHT); +			hbc->add_child(l); +			gn->add_child(hbc); +			l = memnew( Label ); +			l->set_text("Alpha"); +			l->set_align(Label::ALIGN_RIGHT); +			gn->add_child(l); + +			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]); +			gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]); + + +		} break; // screen texture sampler (takes UV) (only usable in fragment case Shader) +  		case ShaderGraph::NODE_OUTPUT: {  			gn->set_title("Output"); @@ -1360,6 +2186,8 @@ void ShaderGraphView::_bind_methods() {  	ObjectTypeDB::bind_method("_variant_edited",&ShaderGraphView::_variant_edited);  	ObjectTypeDB::bind_method("_cube_edited",&ShaderGraphView::_cube_edited);  	ObjectTypeDB::bind_method("_comment_edited",&ShaderGraphView::_comment_edited); +	ObjectTypeDB::bind_method("_color_ramp_changed",&ShaderGraphView::_color_ramp_changed); +	ObjectTypeDB::bind_method("_curve_changed",&ShaderGraphView::_curve_changed);  	ObjectTypeDB::bind_method("_sg_updated",&ShaderGraphView::_sg_updated);  } @@ -1406,6 +2234,9 @@ void ShaderGraphEditor::_notification(int p_what) {  			if (i==ShaderGraph::NODE_OUTPUT)  				continue; +			if (!_2d && i==ShaderGraph::NODE_DEFAULT_TEXTURE) +				continue; +  			String nn = node_names[i];  			String ic = nn.get_slice(":",0);  			String v = nn.get_slice(":",1); @@ -1455,18 +2286,22 @@ const char* ShaderGraphEditor::node_names[ShaderGraph::NODE_TYPE_MAX]={  	"GraphVecsToXform:Vectors -> XForm:", // 3 vec input", 1 xform output  	"GraphScalarInterp:Scalar Interpolate", // scalar interpolation (with optional curve)  	"GraphVecInterp:Vector Interpolate:", // vec3 interpolation  (with optional curve) -	"GraphScalarUniform:Scalar Uniform", // scalar uniform (assignable in material) +    "GraphColorRamp:Color Ramp", // vec3 interpolation  (with optional curve) +    "GraphCurveMap:Curve Remap:", // vec3 interpolation  (with optional curve) +    "GraphScalarUniform:Scalar Uniform", // scalar uniform (assignable in material)  	"GraphVectorUniform:Vector Uniform", // vec3 uniform (assignable in material)  	"GraphRgbUniform:RGB Uniform", // color uniform (assignable in material)  	"GraphXformUniform:XForm Uniform", // mat4 uniform (assignable in material)  	"GraphTextureUniform:Texture Uniform", // texture input (assignable in material)  	"GraphCubeUniform:CubeMap Uniform:", // cubemap input (assignable in material) -	"Output", // output (shader type dependent) +    "GraphDefaultTexture:CanvasItem Texture:", // cubemap input (assignable in material) +    "Output", // output (shader type dependent)  	"GraphComment:Comment", // comment  }; -ShaderGraphEditor::ShaderGraphEditor() { +ShaderGraphEditor::ShaderGraphEditor(bool p_2d) { +	_2d=p_2d;  	HBoxContainer *hbc = memnew( HBoxContainer );  	menu = memnew( MenuButton ); @@ -1508,7 +2343,13 @@ void ShaderGraphEditorPlugin::edit(Object *p_object) {  bool ShaderGraphEditorPlugin::handles(Object *p_object) const { -	return p_object->is_type("ShaderGraph"); +	ShaderGraph *shader=p_object->cast_to<ShaderGraph>(); +	if (!shader) +		return false; +	if (_2d) +		return shader->get_mode()==Shader::MODE_CANVAS_ITEM; +	else +		return shader->get_mode()==Shader::MODE_MATERIAL;  }  void ShaderGraphEditorPlugin::make_visible(bool p_visible) { @@ -1522,12 +2363,16 @@ void ShaderGraphEditorPlugin::make_visible(bool p_visible) {  } -ShaderGraphEditorPlugin::ShaderGraphEditorPlugin(EditorNode *p_node) { +ShaderGraphEditorPlugin::ShaderGraphEditorPlugin(EditorNode *p_node, bool p_2d) { +	_2d=p_2d;  	editor=p_node; -	shader_editor = memnew( ShaderGraphEditor ); +	shader_editor = memnew( ShaderGraphEditor(p_2d) );  	shader_editor->hide(); -	SpatialEditor::get_singleton()->get_shader_split()->add_child(shader_editor); +	if (p_2d) +		CanvasItemEditor::get_singleton()->get_bottom_split()->add_child(shader_editor); +	else +		SpatialEditor::get_singleton()->get_shader_split()->add_child(shader_editor);  //	editor->get_viewport()->add_child(shader_editor); diff --git a/tools/editor/plugins/shader_graph_editor_plugin.h b/tools/editor/plugins/shader_graph_editor_plugin.h index bd983c59be..1726302e90 100644 --- a/tools/editor/plugins/shader_graph_editor_plugin.h +++ b/tools/editor/plugins/shader_graph_editor_plugin.h @@ -45,6 +45,77 @@  */ +class GraphColorRampEdit : public Control { + +	OBJ_TYPE(GraphColorRampEdit,Control); + + +	struct Point { + +		float offset; +		Color color; +		bool operator<(const Point& p_ponit) const { +			return offset<p_ponit.offset; +		} +	}; + +	PopupPanel *popup; +	ColorPicker *picker; + + +	bool grabbing; +	int grabbed; +	float grabbed_at; +	Vector<Point> points; + +	void _color_changed(const Color& p_color); + +protected: +	void _input_event(const InputEvent& p_event); +	void _notification(int p_what); +	static void _bind_methods(); +public: + +	void set_ramp(const Vector<float>& p_offsets,const Vector<Color>& p_colors); +	Vector<float> get_offsets() const; +	Vector<Color> get_colors() const; +	virtual Size2 get_minimum_size() const; +	GraphColorRampEdit(); +}; + + +class GraphCurveMapEdit : public Control { + +	OBJ_TYPE(GraphCurveMapEdit,Control); + + +	struct Point { + +		float offset; +		float height; +		bool operator<(const Point& p_ponit) const { +			return offset<p_ponit.offset; +		} +	}; + + +	bool grabbing; +	int grabbed; +	Vector<Point> points; + +	void _plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d); +protected: +	void _input_event(const InputEvent& p_event); +	void _notification(int p_what); +	static void _bind_methods(); +public: + +	void set_points(const Vector<Vector2>& p_points); +	Vector<Vector2> get_points() const; +	virtual Size2 get_minimum_size() const; +	GraphCurveMapEdit(); +}; +  class ShaderGraphView : public Node {  	OBJ_TYPE(ShaderGraphView,Node); @@ -95,7 +166,8 @@ class ShaderGraphView : public Node {  	void _cube_edited(int p_id,Node* p_button);  	void _variant_edited();  	void _comment_edited(int p_id,Node* p_button); - +	void _color_ramp_changed(int p_id,Node* p_ramp); +	void _curve_changed(int p_id,Node* p_curve);  	void _sg_updated();  	Map<int,GraphNode*> node_map;  protected: @@ -119,6 +191,7 @@ class ShaderGraphEditor : public VBoxContainer {  	ShaderGraphView *graph_edits[ShaderGraph::SHADER_TYPE_MAX];  	static const char* node_names[ShaderGraph::NODE_TYPE_MAX]; +	bool _2d;  	void _add_node(int p_type);  protected:  	void _notification(int p_what); @@ -126,13 +199,14 @@ protected:  public:  	void edit(Ref<ShaderGraph> p_shader); -	ShaderGraphEditor(); +	ShaderGraphEditor(bool p_2d);  };  class ShaderGraphEditorPlugin : public EditorPlugin {  	OBJ_TYPE( ShaderGraphEditorPlugin, EditorPlugin ); +	bool _2d;  	ShaderGraphEditor *shader_editor;  	EditorNode *editor; @@ -144,7 +218,7 @@ public:  	virtual bool handles(Object *p_node) const;  	virtual void make_visible(bool p_visible); -	ShaderGraphEditorPlugin(EditorNode *p_node); +	ShaderGraphEditorPlugin(EditorNode *p_node,bool p_2d);  	~ShaderGraphEditorPlugin();  }; diff --git a/tools/editor/plugins/tile_map_editor_plugin.cpp b/tools/editor/plugins/tile_map_editor_plugin.cpp index ce5ea58124..47727a00c2 100644 --- a/tools/editor/plugins/tile_map_editor_plugin.cpp +++ b/tools/editor/plugins/tile_map_editor_plugin.cpp @@ -34,7 +34,7 @@  #include "os/file_access.h"  #include "tools/editor/editor_settings.h"  #include "os/input.h" - +#include "method_bind_ext.inc"  void TileMapEditor::_notification(int p_what) { @@ -42,8 +42,13 @@ void TileMapEditor::_notification(int p_what) {  		case NOTIFICATION_READY: { +			transpose->set_icon( get_icon("Transpose","EditorIcons"));  			mirror_x->set_icon( get_icon("MirrorX","EditorIcons"));  			mirror_y->set_icon( get_icon("MirrorY","EditorIcons")); +			rotate_0->set_icon( get_icon("Rotate0","EditorIcons")); +			rotate_90->set_icon( get_icon("Rotate90","EditorIcons")); +			rotate_180->set_icon( get_icon("Rotate180","EditorIcons")); +			rotate_270->set_icon( get_icon("Rotate270","EditorIcons"));  		} break;  	} @@ -85,24 +90,31 @@ void TileMapEditor::set_selected_tile(int p_tile) {  	}  } -void TileMapEditor::_set_cell(const Point2i& p_pos,int p_value,bool p_flip_h, bool p_flip_v,bool p_with_undo) { +// Wrapper to workaround five arg limit of undo/redo methods +void TileMapEditor::_set_cell_shortened(const Point2& p_pos,int p_value,bool p_flip_h, bool p_flip_v, bool p_transpose) { +	ERR_FAIL_COND(!node); +	node->set_cell(floor(p_pos.x), floor(p_pos.y), p_value, p_flip_h, p_flip_v, p_transpose); +} +	 +void TileMapEditor::_set_cell(const Point2i& p_pos,int p_value,bool p_flip_h, bool p_flip_v, bool p_transpose,bool p_with_undo) {  	ERR_FAIL_COND(!node);  	bool prev_flip_h=node->is_cell_x_flipped(p_pos.x,p_pos.y);  	bool prev_flip_v=node->is_cell_y_flipped(p_pos.x,p_pos.y); +	bool prev_transpose=node->is_cell_transposed(p_pos.x,p_pos.y);  	int prev_val=node->get_cell(p_pos.x,p_pos.y); -	if (p_value==prev_val && p_flip_h==prev_flip_h && p_flip_v==prev_flip_v) +	if (p_value==prev_val && p_flip_h==prev_flip_h && p_flip_v==prev_flip_v && p_transpose==prev_transpose)  		return; //check that it's actually different  	if (p_with_undo) { -		undo_redo->add_do_method(node,"set_cell",p_pos.x,p_pos.y,p_value,p_flip_h,p_flip_v); -		undo_redo->add_undo_method(node,"set_cell",p_pos.x,p_pos.y,prev_val,prev_flip_h,prev_flip_v); +		undo_redo->add_do_method(this,"_set_cell_shortened",Point2(p_pos),p_value,p_flip_h,p_flip_v,p_transpose); +		undo_redo->add_undo_method(this,"_set_cell_shortened",Point2(p_pos),prev_val,prev_flip_h,prev_flip_v,prev_transpose);  	} else { -		node->set_cell(p_pos.x,p_pos.y,p_value,p_flip_h,p_flip_v); +		node->set_cell(p_pos.x,p_pos.y,p_value,p_flip_h,p_flip_v,p_transpose);  	} @@ -168,6 +180,7 @@ struct _TileMapEditorCopyData {  	int cell;  	bool flip_h;  	bool flip_v; +	bool transpose;  };  bool TileMapEditor::forward_input_event(const InputEvent& p_event) { @@ -204,6 +217,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {  							tcd.cell=node->get_cell(j,i);  							tcd.flip_h=node->is_cell_x_flipped(j,i);  							tcd.flip_v=node->is_cell_y_flipped(j,i); +							tcd.transpose=node->is_cell_transposed(j,i);  							dupdata.push_back(tcd); @@ -214,7 +228,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {  					for (List<_TileMapEditorCopyData>::Element *E=dupdata.front();E;E=E->next()) { -						_set_cell(E->get().pos+ofs,E->get().cell,E->get().flip_h,E->get().flip_v,true); +						_set_cell(E->get().pos+ofs,E->get().cell,E->get().flip_h,E->get().flip_v,E->get().transpose,true);  					}  					undo_redo->commit_action(); @@ -239,6 +253,10 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {  					} else if (mb.mod.control) {  						tool=TOOL_PICKING;  						set_selected_tile(node->get_cell(over_tile.x, over_tile.y)); +						mirror_x->set_pressed(node->is_cell_x_flipped(over_tile.x, over_tile.y)); +						mirror_y->set_pressed(node->is_cell_y_flipped(over_tile.x, over_tile.y)); +						transpose->set_pressed(node->is_cell_transposed(over_tile.x, over_tile.y)); +						_update_transform_buttons();  						canvas_item_editor->update();  						return true;  					} else { @@ -248,7 +266,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {  							Point2i local =node->world_to_map((xform_inv.xform(Point2(mb.x,mb.y))));  							paint_undo.clear();  							paint_undo[local]=_get_op_from_cell(local); -							node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed()); +							node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());  							return true;  						}  					} @@ -263,8 +281,8 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {  								for(Map<Point2i,CellOp>::Element *E=paint_undo.front();E;E=E->next()) {  									Point2i p=E->key(); -									undo_redo->add_do_method(node,"set_cell",p.x,p.y,node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y)); -									undo_redo->add_undo_method(node,"set_cell",p.x,p.y,E->get().idx,E->get().xf,E->get().yf); +									undo_redo->add_do_method(this,"_set_cell_shortened",Point2(p),node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y),node->is_cell_transposed(p.x,p.y)); +									undo_redo->add_undo_method(this,"_set_cell_shortened",Point2(p),E->get().idx,E->get().xf,E->get().yf,E->get().tr);  								}  								undo_redo->commit_action(); @@ -289,7 +307,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {  					Point2i local =node->world_to_map(xform_inv.xform(Point2(mb.x,mb.y)));  					paint_undo.clear();  					paint_undo[local]=_get_op_from_cell(local); -					//node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed()); +					//node->set_cell(local.x,local.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());  					//return true;  					_set_cell(local,TileMap::INVALID_CELL);  					return true; @@ -302,9 +320,9 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {  							for(Map<Point2i,CellOp>::Element *E=paint_undo.front();E;E=E->next()) {  								Point2i p=E->key(); -								//undo_redo->add_do_method(node,"set_cell",p.x,p.y,node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y)); -								_set_cell(p,TileMap::INVALID_CELL,false,false,true); -								undo_redo->add_undo_method(node,"set_cell",p.x,p.y,E->get().idx,E->get().xf,E->get().yf); +								//undo_redo->add_do_method(node,"set_cell",p.x,p.y,node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y),node->is_cell_transposed(p.x,p.y)); +								_set_cell(p,TileMap::INVALID_CELL,false,false,false,true); +								undo_redo->add_undo_method(this,"_set_cell_shortened",Point2(p),E->get().idx,E->get().xf,E->get().yf,E->get().tr);  							}  							undo_redo->commit_action(); @@ -340,7 +358,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {  						paint_undo[over_tile]=_get_op_from_cell(over_tile);  					} -					node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed()); +					node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());  					return true;  				} @@ -373,13 +391,17 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {  				if (!paint_undo.has(over_tile)) {  					paint_undo[over_tile]=_get_op_from_cell(over_tile);  				} -				//node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed()); +				//node->set_cell(over_tile.x,over_tile.y,id,mirror_x->is_pressed(),mirror_y->is_pressed(),transpose->is_pressed());  				_set_cell(local,TileMap::INVALID_CELL);  				return true;  			}  			if (tool==TOOL_PICKING) {  				set_selected_tile(node->get_cell(over_tile.x, over_tile.y)); +				mirror_x->set_pressed(node->is_cell_x_flipped(over_tile.x, over_tile.y)); +				mirror_y->set_pressed(node->is_cell_y_flipped(over_tile.x, over_tile.y)); +				transpose->set_pressed(node->is_cell_transposed(over_tile.x, over_tile.y)); +				_update_transform_buttons();  				canvas_item_editor->update();  				return true;  			} @@ -627,10 +649,10 @@ void TileMapEditor::_canvas_draw() {  							sc.y*=-1.0;  						if (r==Rect2()) { -							canvas_item_editor->draw_texture_rect(t,Rect2(from,t->get_size()*sc),false,Color(1,1,1,0.5)); +							canvas_item_editor->draw_texture_rect(t,Rect2(from,t->get_size()*sc),false,Color(1,1,1,0.5),transpose->is_pressed());  						} else { -							canvas_item_editor->draw_texture_rect_region(t,Rect2(from,r.get_size()*sc),r,Color(1,1,1,0.5)); +							canvas_item_editor->draw_texture_rect_region(t,Rect2(from,r.get_size()*sc),r,Color(1,1,1,0.5),transpose->is_pressed());  						}  					}  				} @@ -697,6 +719,8 @@ void TileMapEditor::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("_canvas_mouse_enter"),&TileMapEditor::_canvas_mouse_enter);  	ObjectTypeDB::bind_method(_MD("_canvas_mouse_exit"),&TileMapEditor::_canvas_mouse_exit);  	ObjectTypeDB::bind_method(_MD("_tileset_settings_changed"),&TileMapEditor::_tileset_settings_changed); +	ObjectTypeDB::bind_method(_MD("_update_transform_buttons"),&TileMapEditor::_update_transform_buttons); +	ObjectTypeDB::bind_method(_MD("_set_cell_shortened","pos","tile","flip_x","flip_y","transpose"),&TileMapEditor::_set_cell_shortened,DEFVAL(false),DEFVAL(false),DEFVAL(false));  } @@ -709,10 +733,60 @@ TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i& p_pos)  			op.xf=true;  		if (node->is_cell_y_flipped(p_pos.x,p_pos.y))  			op.yf=true; +		if (node->is_cell_transposed(p_pos.x,p_pos.y)) +			op.tr=true;  	}  	return op;  } +void TileMapEditor::_update_transform_buttons(Object *p_button) { +	//ERR_FAIL_NULL(p_button); +	ToolButton *b=p_button->cast_to<ToolButton>(); +	//ERR_FAIL_COND(!b); +	 +	mirror_x->set_block_signals(true); +	mirror_y->set_block_signals(true); +	transpose->set_block_signals(true); +	rotate_0->set_block_signals(true); +	rotate_90->set_block_signals(true); +	rotate_180->set_block_signals(true); +	rotate_270->set_block_signals(true); +	 +	if (b == rotate_0) { +		mirror_x->set_pressed(false); +		mirror_y->set_pressed(false); +		transpose->set_pressed(false); +	} +	else if (b == rotate_90) { +		mirror_x->set_pressed(true); +		mirror_y->set_pressed(false); +		transpose->set_pressed(true); +	} +	else if (b == rotate_180) { +		mirror_x->set_pressed(true); +		mirror_y->set_pressed(true); +		transpose->set_pressed(false); +	} +	else if (b == rotate_270) { +		mirror_x->set_pressed(false); +		mirror_y->set_pressed(true); +		transpose->set_pressed(true); +	} +	 +	rotate_0->set_pressed(!mirror_x->is_pressed() && !mirror_y->is_pressed() && !transpose->is_pressed()); +	rotate_90->set_pressed(mirror_x->is_pressed() && !mirror_y->is_pressed() && transpose->is_pressed()); +	rotate_180->set_pressed(mirror_x->is_pressed() && mirror_y->is_pressed() && !transpose->is_pressed()); +	rotate_270->set_pressed(!mirror_x->is_pressed() && mirror_y->is_pressed() && transpose->is_pressed()); + +	mirror_x->set_block_signals(false); +	mirror_y->set_block_signals(false); +	transpose->set_block_signals(false); +	rotate_0->set_block_signals(false); +	rotate_90->set_block_signals(false); +	rotate_180->set_block_signals(false); +	rotate_270->set_block_signals(false); +} +  TileMapEditor::TileMapEditor(EditorNode *p_editor) {  	node=NULL; @@ -734,18 +808,52 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {  	canvas_item_editor_hb = memnew( HBoxContainer );  	CanvasItemEditor::get_singleton()->add_control_to_menu_panel(canvas_item_editor_hb);  	canvas_item_editor_hb->add_child( memnew( VSeparator )); +	transpose = memnew( ToolButton ); +	transpose->set_toggle_mode(true); +	transpose->set_tooltip("Transpose"); +	transpose->set_focus_mode(FOCUS_NONE); +	transpose->connect("pressed", this, "_update_transform_buttons", make_binds(transpose)); +	canvas_item_editor_hb->add_child(transpose);  	mirror_x = memnew( ToolButton );  	mirror_x->set_toggle_mode(true);  	mirror_x->set_tooltip("Mirror X (A)");  	mirror_x->set_focus_mode(FOCUS_NONE); +	mirror_x->connect("pressed", this, "_update_transform_buttons", make_binds(mirror_x));  	canvas_item_editor_hb->add_child(mirror_x);  	mirror_y = memnew( ToolButton );  	mirror_y->set_toggle_mode(true);  	mirror_y->set_tooltip("Mirror Y (S)");  	mirror_y->set_focus_mode(FOCUS_NONE); +	mirror_y->connect("pressed", this, "_update_transform_buttons", make_binds(mirror_y));  	canvas_item_editor_hb->add_child(mirror_y); +	canvas_item_editor_hb->add_child(memnew(VSeparator)); +	rotate_0 = memnew( ToolButton ); +	rotate_0->set_toggle_mode(true); +	rotate_0->set_tooltip("Rotate 0 degrees"); +	rotate_0->set_focus_mode(FOCUS_NONE); +	rotate_0->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_0)); +	canvas_item_editor_hb->add_child(rotate_0); +	rotate_90 = memnew( ToolButton ); +	rotate_90->set_toggle_mode(true); +	rotate_90->set_tooltip("Rotate 90 degrees"); +	rotate_90->set_focus_mode(FOCUS_NONE); +	rotate_90->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_90)); +	canvas_item_editor_hb->add_child(rotate_90); +	rotate_180 = memnew( ToolButton ); +	rotate_180->set_toggle_mode(true); +	rotate_180->set_tooltip("Rotate 180 degrees"); +	rotate_180->set_focus_mode(FOCUS_NONE); +	rotate_180->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_180)); +	canvas_item_editor_hb->add_child(rotate_180); +	rotate_270 = memnew( ToolButton ); +	rotate_270->set_toggle_mode(true); +	rotate_270->set_tooltip("Rotate 270 degrees"); +	rotate_270->set_focus_mode(FOCUS_NONE); +	rotate_270->connect("pressed", this, "_update_transform_buttons", make_binds(rotate_270)); +	canvas_item_editor_hb->add_child(rotate_270);  	canvas_item_editor_hb->hide(); - +	 +	rotate_0->set_pressed(true);  	tool=TOOL_NONE;  	selection_active=false;  	mouse_over=false; diff --git a/tools/editor/plugins/tile_map_editor_plugin.h b/tools/editor/plugins/tile_map_editor_plugin.h index f3c590e228..367e687d77 100644 --- a/tools/editor/plugins/tile_map_editor_plugin.h +++ b/tools/editor/plugins/tile_map_editor_plugin.h @@ -71,8 +71,13 @@ class TileMapEditor : public VBoxContainer {  	bool mouse_over;  	Label *mirror_label; +	ToolButton *transpose;  	ToolButton *mirror_x;  	ToolButton *mirror_y; +	ToolButton *rotate_0; +	ToolButton *rotate_90; +	ToolButton *rotate_180; +	ToolButton *rotate_270;  	HBoxContainer *canvas_item_editor_hb; @@ -81,8 +86,8 @@ class TileMapEditor : public VBoxContainer {  		int idx;  		bool xf;  		bool yf; -		CellOp() { idx=-1; xf=false; yf=false; } -		CellOp(const CellOp& p_other) : idx(p_other.idx), xf(p_other.xf), yf(p_other.yf) {} +		bool tr; +		CellOp() { idx=-1; xf=false; yf=false; tr=false; }  	};  	Map<Point2i,CellOp> paint_undo; @@ -94,7 +99,8 @@ class TileMapEditor : public VBoxContainer {  	void _canvas_draw();  	void _menu_option(int p_option); -	void _set_cell(const Point2i& p_pos, int p_value, bool p_flip_h=false, bool p_flip_v=false, bool p_with_undo=false); +	void _set_cell(const Point2i& p_pos, int p_value, bool p_flip_h=false, bool p_flip_v=false, bool p_transpose=false, bool p_with_undo=false); +	void _set_cell_shortened(const Point2& p_pos, int p_value, bool p_flip_h=false, bool p_flip_v=false, bool p_transpose=false);  	void _canvas_mouse_enter();  	void _canvas_mouse_exit(); @@ -106,6 +112,7 @@ protected:  	void _node_removed(Node *p_node);  	static void _bind_methods();  	CellOp _get_op_from_cell(const Point2i& p_pos); +	void _update_transform_buttons(Object *p_button=0);  public:  	HBoxContainer *get_canvas_item_editor_hb() const { return canvas_item_editor_hb; } diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index a600683097..25c39b3173 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -1857,8 +1857,33 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p  				} else {  					p_item->set_text(1,"<"+res->get_type()+">");  				}; + +				if (has_icon(res->get_type(),"EditorIcons")) { + +					p_item->set_icon(1,get_icon(res->get_type(),"EditorIcons")); +				} else { + +					Dictionary d = p_item->get_metadata(0); +					int hint=d.has("hint")?d["hint"].operator int():-1; +					String hint_text=d.has("hint_text")?d["hint_text"]:""; +					if (hint==PROPERTY_HINT_RESOURCE_TYPE) { + +						if (has_icon(hint_text,"EditorIcons")) { + +							p_item->set_icon(1,get_icon(hint_text,"EditorIcons")); + +						} else { +							p_item->set_icon(1,get_icon("Object","EditorIcons")); + +						} +					} +				} + + +  			} +  		} break;  		default: {};  	} @@ -2529,7 +2554,10 @@ void PropertyEditor::update_tree() {  				item->set_editable( 1, !read_only );  				item->add_button(1,get_icon("EditResource","EditorIcons"));  				String type; +				if (p.hint==PROPERTY_HINT_RESOURCE_TYPE) +					type=p.hint_string;  				bool notnil=false; +  				if (obj->get( p.name ).get_type() == Variant::NIL || obj->get( p.name ).operator RefPtr().is_null()) {  					item->set_text(1,"<null>"); @@ -2553,12 +2581,18 @@ void PropertyEditor::update_tree() {  					};  					notnil=true; +					if (has_icon(res->get_type(),"EditorIcons")) { +						type=res->get_type(); +					}  				} -				if (p.hint==PROPERTY_HINT_RESOURCE_TYPE) { + +				if (type!=String()) { +					if (type.find(",")!=-1) +						type=type.get_slice(",",0);  					//printf("prop %s , type %s\n",p.name.ascii().get_data(),p.hint_string.ascii().get_data()); -					if (has_icon(p.hint_string,"EditorIcons")) -						item->set_icon( 0, get_icon(p.hint_string,"EditorIcons") ); +					if (has_icon(type,"EditorIcons")) +						item->set_icon( 0, get_icon(type,"EditorIcons") );  					else  						item->set_icon( 0, get_icon("Object","EditorIcons") );  				} diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp index cff3913579..2012d96664 100644 --- a/tools/editor/scene_tree_dock.cpp +++ b/tools/editor/scene_tree_dock.cpp @@ -79,10 +79,22 @@ Node* SceneTreeDock::instance(const String& p_file) {  		//accept->get_cancel()->hide();  		accept->get_ok()->set_text("Ugh");  		accept->set_text(String("Error loading scene from ")+p_file); -		accept->popup_centered(Size2(300,70));; +		accept->popup_centered(Size2(300,70));  		return NULL;  	} +	// If the scene hasn't been saved yet a cyclical dependency cannot exist. +	if (edited_scene->get_filename()!="") { + +		if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) { + +			accept->get_ok()->set_text("Ok"); +			accept->set_text(String("Cannot instance the scene '")+p_file+String("' because the current scene exists within one of its' nodes.")); +			accept->popup_centered(Size2(300,90)); +			return NULL; +		} +	} +  	instanced_scene->generate_instance_state();  	instanced_scene->set_filename( Globals::get_singleton()->localize_path(p_file) ); @@ -100,6 +112,25 @@ Node* SceneTreeDock::instance(const String& p_file) {  } +bool SceneTreeDock::_cyclical_dependency_exists(const String& p_target_scene_path, Node* p_desired_node) { +	int childCount = p_desired_node->get_child_count(); + +	if (p_desired_node->get_filename()==p_target_scene_path) { +		return true; +	} + +	for (int i=0;i<childCount;i++) { +		Node* child=p_desired_node->get_child(i); + +		if(_cyclical_dependency_exists(p_target_scene_path,child)) { +			return true; +		} +	} + +	return false; +} + +  static String _get_name_num_separator() {  	switch(EditorSettings::get_singleton()->get("scenetree_editor/duplicate_node_name_num_separator").operator int()) {  		case 0: return ""; @@ -1223,7 +1254,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec  	tb = memnew( ToolButton );  	tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_INSTANCE, false)); -	tb->set_tooltip("Instance a Node from scene file."); +	tb->set_tooltip("Instance a scene file as a Node.");  	hbc_top->add_child(tb);  	tool_buttons[TOOL_INSTANCE]=tb; diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h index ac5391f3b9..92ebfc5bee 100644 --- a/tools/editor/scene_tree_dock.h +++ b/tools/editor/scene_tree_dock.h @@ -102,6 +102,7 @@ class SceneTreeDock : public VBoxContainer {  	void _load_request(const String& p_path);  	void _script_open_request(const Ref<Script>& p_script); +	bool _cyclical_dependency_exists(const String& p_target_scene_path, Node* p_desired_node);  	void _node_selected();  	void _node_renamed();  |