mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 05:31:01 +00:00 
			
		
		
		
	Merge branch 'master' of https://github.com/okamstudio/godot
Conflicts: modules/gdscript/gd_tokenizer.cpp scene/resources/shader_graph.h
This commit is contained in:
		
						commit
						2c2894ceb6
					
				
					 151 changed files with 12123 additions and 954 deletions
				
			
		
							
								
								
									
										4
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -19,6 +19,9 @@ tools/editor/register_exporters.cpp | ||||||
| tools/editor/doc_data_compressed.h | tools/editor/doc_data_compressed.h | ||||||
| tools/editor/editor_icons.cpp | tools/editor/editor_icons.cpp | ||||||
| -fpic | -fpic | ||||||
|  | .fscache | ||||||
|  | make.bat | ||||||
|  | log.txt | ||||||
| 
 | 
 | ||||||
| # Android specific | # Android specific | ||||||
| platform/android/java/local.properties | platform/android/java/local.properties | ||||||
|  | @ -258,3 +261,4 @@ Desktop.ini | ||||||
| # Recycle Bin used on file shares | # Recycle Bin used on file shares | ||||||
| $RECYCLE.BIN/ | $RECYCLE.BIN/ | ||||||
| logo.h | logo.h | ||||||
|  | *.autosave | ||||||
|  |  | ||||||
|  | @ -487,7 +487,7 @@ struct test_27_data { | ||||||
| 
 | 
 | ||||||
| bool test_27() { | 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[] = { | 	test_27_data tc[] = { | ||||||
| 		{"res://foobar", "res://", true}, | 		{"res://foobar", "res://", true}, | ||||||
| 		{"res", "res://", false}, | 		{"res", "res://", false}, | ||||||
|  | @ -504,11 +504,348 @@ bool test_27() { | ||||||
| 		} | 		} | ||||||
| 		if (!state) { | 		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"); | 			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; | 	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); | typedef bool (*TestFunc)(void); | ||||||
| 
 | 
 | ||||||
| TestFunc test_funcs[] = { | TestFunc test_funcs[] = { | ||||||
|  | @ -540,6 +877,7 @@ TestFunc test_funcs[] = { | ||||||
| 	test_25, | 	test_25, | ||||||
| 	test_26, | 	test_26, | ||||||
| 	test_27, | 	test_27, | ||||||
|  | 	test_28, | ||||||
| 	0 | 	0 | ||||||
| 	 | 	 | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -316,6 +316,11 @@ float _OS::get_time_scale() { | ||||||
| 	return OS::get_singleton()->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 { | enum Weekday { | ||||||
| 	DAY_SUNDAY, | 	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_system_dir","dir"),&_OS::get_system_dir); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_unique_ID"),&_OS::get_unique_ID); | 	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("get_frames_per_second"),&_OS::get_frames_per_second); | ||||||
| 
 | 
 | ||||||
| 	ObjectTypeDB::bind_method(_MD("print_all_textures_by_size"),&_OS::print_all_textures_by_size); | 	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(); | 		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> _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; | 	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_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_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("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); | 	ObjectTypeDB::bind_method(_MD("triangulate_polygon","polygon"),&_Geometry::triangulate_polygon); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -220,6 +220,8 @@ public: | ||||||
| 	void set_time_scale(float p_scale); | 	void set_time_scale(float p_scale); | ||||||
| 	float get_time_scale(); | 	float get_time_scale(); | ||||||
| 
 | 
 | ||||||
|  | 	bool is_ok_left_and_cancel_right() const; | ||||||
|  | 
 | ||||||
| 	static _OS *get_singleton() { return singleton; } | 	static _OS *get_singleton() { return singleton; } | ||||||
| 
 | 
 | ||||||
| 	_OS(); | 	_OS(); | ||||||
|  | @ -248,6 +250,8 @@ public: | ||||||
| 	Vector3 get_closest_point_to_segment(const Vector3& p_point, const Vector3& p_a,const Vector3& p_b); | 	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 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); | 	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_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_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); | 	DVector<Vector3> segment_intersects_convex(const Vector3& p_from, const Vector3& p_to,const Vector<Plane>& p_planes); | ||||||
|  |  | ||||||
|  | @ -262,6 +262,23 @@ public: | ||||||
| 			w[bs+i]=r[i]; | 			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(); } | 	bool is_locked() const { return mem.is_locked(); } | ||||||
| 	 | 	 | ||||||
| 	inline const T operator[](int p_index) const; | 	inline const T operator[](int p_index) const; | ||||||
|  |  | ||||||
|  | @ -273,7 +273,7 @@ Error HTTPClient::poll(){ | ||||||
| 			while(true) { | 			while(true) { | ||||||
| 				uint8_t byte; | 				uint8_t byte; | ||||||
| 				int rec=0; | 				int rec=0; | ||||||
| 				Error err = connection->get_partial_data(&byte,1,rec); | 				Error err = _get_http_data(&byte,1,rec); | ||||||
| 				if (err!=OK) { | 				if (err!=OK) { | ||||||
| 					close(); | 					close(); | ||||||
| 					status=STATUS_CONNECTION_ERROR; | 					status=STATUS_CONNECTION_ERROR; | ||||||
|  | @ -417,7 +417,7 @@ ByteArray HTTPClient::read_response_body_chunk() { | ||||||
| 				//reading len
 | 				//reading len
 | ||||||
| 				uint8_t b; | 				uint8_t b; | ||||||
| 				int rec=0; | 				int rec=0; | ||||||
| 				err = connection->get_partial_data(&b,1,rec); | 				err = _get_http_data(&b,1,rec); | ||||||
| 
 | 
 | ||||||
| 				if (rec==0) | 				if (rec==0) | ||||||
| 					break; | 					break; | ||||||
|  | @ -471,7 +471,7 @@ ByteArray HTTPClient::read_response_body_chunk() { | ||||||
| 			} else { | 			} else { | ||||||
| 
 | 
 | ||||||
| 				int rec=0; | 				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) { | 				if (rec==0) { | ||||||
| 					break; | 					break; | ||||||
| 				} | 				} | ||||||
|  | @ -502,18 +502,23 @@ ByteArray HTTPClient::read_response_body_chunk() { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	} else { | 	} else { | ||||||
|  | 
 | ||||||
|  | 		int to_read = MIN(body_left,read_chunk_size); | ||||||
| 		ByteArray ret; | 		ByteArray ret; | ||||||
| 		ret.resize(MAX(body_left,tmp_read.size())); | 		ret.resize(to_read); | ||||||
| 		ByteArray::Write w = ret.write(); | 		ByteArray::Write w = ret.write(); | ||||||
| 		int _offset = 0; | 		int _offset = 0; | ||||||
| 		while (body_left > 0) { | 		while (to_read > 0) { | ||||||
| 			ByteArray::Write r = tmp_read.write(); |  | ||||||
| 			int rec=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) { | 			if (rec>0) { | ||||||
| 				copymem(w.ptr()+_offset,r.ptr(),rec); |  | ||||||
| 				body_left-=rec; | 				body_left-=rec; | ||||||
|  | 				to_read-=rec; | ||||||
| 				_offset += rec; | 				_offset += rec; | ||||||
|  | 			} else { | ||||||
|  | 				if (to_read>0) //ended up reading less
 | ||||||
|  | 					ret.resize(_offset); | ||||||
|  | 				break; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if (body_left==0) { | 		if (body_left==0) { | ||||||
|  | @ -557,6 +562,20 @@ bool HTTPClient::is_blocking_mode_enabled() const{ | ||||||
| 	return blocking; | 	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() { | 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_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("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("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("set_blocking_mode","enabled"),&HTTPClient::set_blocking_mode); | ||||||
| 	ObjectTypeDB::bind_method(_MD("is_blocking_mode_enabled"),&HTTPClient::is_blocking_mode_enabled); | 	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(){ | HTTPClient::HTTPClient(){ | ||||||
| 
 | 
 | ||||||
| 	tcp_connection = StreamPeerTCP::create_ref(); | 	tcp_connection = StreamPeerTCP::create_ref(); | ||||||
|  | @ -677,7 +702,7 @@ HTTPClient::HTTPClient(){ | ||||||
| 	response_num=0; | 	response_num=0; | ||||||
| 	ssl=false; | 	ssl=false; | ||||||
| 	blocking=false; | 	blocking=false; | ||||||
| 	tmp_read.resize(4096); | 	read_chunk_size=4096; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HTTPClient::~HTTPClient(){ | HTTPClient::~HTTPClient(){ | ||||||
|  |  | ||||||
|  | @ -157,7 +157,10 @@ private: | ||||||
| 	static void _bind_methods(); | 	static void _bind_methods(); | ||||||
| 	StringArray _get_response_headers(); | 	StringArray _get_response_headers(); | ||||||
| 	Dictionary _get_response_headers_as_dictionary(); | 	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: | public: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -185,6 +188,7 @@ public: | ||||||
| 	void set_blocking_mode(bool p_enable); //useful mostly if running in a thread
 | 	void set_blocking_mode(bool p_enable); //useful mostly if running in a thread
 | ||||||
| 	bool is_blocking_mode_enabled() const; | 	bool is_blocking_mode_enabled() const; | ||||||
| 
 | 
 | ||||||
|  | 	void set_read_chunk_size(int p_size); | ||||||
| 
 | 
 | ||||||
| 	Error poll(); | 	Error poll(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1778,6 +1778,11 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_ | ||||||
| 	f->store_32(VERSION_MINOR); | 	f->store_32(VERSION_MINOR); | ||||||
| 	f->store_32(FORMAT_VERSION); | 	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
 | 	//f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed
 | ||||||
| 	save_unicode_string(p_resource->get_type()); | 	save_unicode_string(p_resource->get_type()); | ||||||
| 	uint64_t md_at = f->get_pos(); | 	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
 | 	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(); | 	f->close(); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2592,6 +2592,11 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	exit_tag("resource_file"); | 	exit_tag("resource_file"); | ||||||
|  | 	if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) { | ||||||
|  | 		f->close(); | ||||||
|  | 		return ERR_CANT_CREATE; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	f->close(); | 	f->close(); | ||||||
| 	//memdelete(f);
 | 	//memdelete(f);
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										56
									
								
								core/list.h
									
										
									
									
									
								
							
							
						
						
									
										56
									
								
								core/list.h
									
										
									
									
									
								
							|  | @ -30,7 +30,7 @@ | ||||||
| #define GLOBALS_LIST_H | #define GLOBALS_LIST_H | ||||||
| 
 | 
 | ||||||
| #include "os/memory.h" | #include "os/memory.h" | ||||||
| 
 | #include "sort.h" | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Generic Templatized Linked List Implementation. |  * Generic Templatized Linked List Implementation. | ||||||
|  | @ -551,7 +551,7 @@ public: | ||||||
| 	} | 	} | ||||||
| 			 | 			 | ||||||
| 	template<class C> | 	template<class C> | ||||||
| 	void sort_custom() { | 	void sort_custom_inplace() { | ||||||
| 
 | 
 | ||||||
| 		if(size()<2) | 		if(size()<2) | ||||||
| 			return; | 			return; | ||||||
|  | @ -603,6 +603,58 @@ public: | ||||||
| 		_data->last=to; | 		_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 | 	 * copy constructor for the list | ||||||
| 	 */ | 	 */ | ||||||
|  |  | ||||||
|  | @ -121,7 +121,7 @@ void CameraMatrix::set_orthogonal(float p_size, float p_aspect, float p_znear, f | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| void CameraMatrix::set_frustum(float p_left, float p_right, float p_bottom, float p_top, float p_near, float p_far) { | 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.
 | 	///@TODO, give a check to this. I'm not sure if it's working.
 | ||||||
| 	set_identity(); | 	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[2][3]=-(2*p_far*p_near) / (p_far-p_near); | ||||||
| 	matrix[3][2]=-1; | 	matrix[3][2]=-1; | ||||||
| 	matrix[3][3]=0; | 	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 { | float CameraMatrix::get_z_far() const { | ||||||
| 	 | 	 | ||||||
| 	const float * matrix = (const float*)this->matrix;			 | 	const float * matrix = (const float*)this->matrix;			 | ||||||
|  |  | ||||||
|  | @ -511,6 +511,20 @@ public: | ||||||
| 		else | 		else | ||||||
| 			return p_segment[0]+n*d; // inside
 | 			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) { | 	static Vector2 get_closest_point_to_segment_uncapped_2d(const Vector2& p_point, const Vector2 *p_segment) { | ||||||
| 
 | 
 | ||||||
| 		Vector2 p=p_point-p_segment[0]; | 		Vector2 p=p_point-p_segment[0]; | ||||||
|  |  | ||||||
|  | @ -159,8 +159,8 @@ struct Vector2 { | ||||||
| 	 | 	 | ||||||
| 	operator String() const { return String::num(x)+","+String::num(y); } | 	operator String() const { return String::num(x)+","+String::num(y); } | ||||||
| 	 | 	 | ||||||
| 	inline Vector2(float p_x,float p_y) { x=p_x; y=p_y; } | 	_FORCE_INLINE_ Vector2(float p_x,float p_y) { x=p_x; y=p_y; } | ||||||
| 	inline Vector2() { x=0; y=0; } | 	_FORCE_INLINE_ Vector2() { x=0; y=0; } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| _FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2& p_vec) const { | _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 Size2; | ||||||
| typedef Vector2 Point2; | typedef Vector2 Point2; | ||||||
| 
 | 
 | ||||||
|  | struct Matrix32; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| struct Rect2 { | struct Rect2 { | ||||||
| 	 | 	 | ||||||
|  | @ -224,6 +226,8 @@ struct Rect2 { | ||||||
| 		return true; | 		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; | 	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 { | 	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 { | Vector2 Matrix32::basis_xform(const Vector2& v) const { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										1550
									
								
								core/math/triangulator.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1550
									
								
								core/math/triangulator.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										306
									
								
								core/math/triangulator.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								core/math/triangulator.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,306 @@ | ||||||
|  | //Copyright (C) 2011 by Ivan Fratric
 | ||||||
|  | //
 | ||||||
|  | //Permission is hereby granted, free of charge, to any person obtaining a copy
 | ||||||
|  | //of this software and associated documentation files (the "Software"), to deal
 | ||||||
|  | //in the Software without restriction, including without limitation the rights
 | ||||||
|  | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | ||||||
|  | //copies of the Software, and to permit persons to whom the Software is
 | ||||||
|  | //furnished to do so, subject to the following conditions:
 | ||||||
|  | //
 | ||||||
|  | //The above copyright notice and this permission notice shall be included in
 | ||||||
|  | //all copies or substantial portions of the Software.
 | ||||||
|  | //
 | ||||||
|  | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | ||||||
|  | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | ||||||
|  | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | ||||||
|  | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | ||||||
|  | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | ||||||
|  | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | ||||||
|  | //THE SOFTWARE.
 | ||||||
|  | 
 | ||||||
|  | #ifndef TRIANGULATOR_H | ||||||
|  | #define TRIANGULATOR_H | ||||||
|  | 
 | ||||||
|  | #include "math_2d.h" | ||||||
|  | #include "list.h" | ||||||
|  | #include "set.h" | ||||||
|  | //2D point structure
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #define TRIANGULATOR_CCW 1 | ||||||
|  | #define TRIANGULATOR_CW -1 | ||||||
|  | //Polygon implemented as an array of points with a 'hole' flag
 | ||||||
|  | class TriangulatorPoly { | ||||||
|  | protected: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	Vector2 *points; | ||||||
|  | 	long numpoints; | ||||||
|  | 	bool hole; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 	//constructors/destructors
 | ||||||
|  | 	TriangulatorPoly(); | ||||||
|  | 	~TriangulatorPoly(); | ||||||
|  | 
 | ||||||
|  | 	TriangulatorPoly(const TriangulatorPoly &src); | ||||||
|  | 	TriangulatorPoly& operator=(const TriangulatorPoly &src); | ||||||
|  | 
 | ||||||
|  | 	//getters and setters
 | ||||||
|  | 	long GetNumPoints() { | ||||||
|  | 		return numpoints; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool IsHole() { | ||||||
|  | 		return hole; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void SetHole(bool hole) { | ||||||
|  | 		this->hole = hole; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	Vector2 &GetPoint(long i) { | ||||||
|  | 		return points[i]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	Vector2 *GetPoints() { | ||||||
|  | 		return points; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	Vector2& operator[] (int i) { | ||||||
|  | 		return points[i]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	//clears the polygon points
 | ||||||
|  | 	void Clear(); | ||||||
|  | 
 | ||||||
|  | 	//inits the polygon with numpoints vertices
 | ||||||
|  | 	void Init(long numpoints); | ||||||
|  | 
 | ||||||
|  | 	//creates a triangle with points p1,p2,p3
 | ||||||
|  | 	void Triangle(Vector2 &p1, Vector2 &p2, Vector2 &p3); | ||||||
|  | 
 | ||||||
|  | 	//inverts the orfer of vertices
 | ||||||
|  | 	void Invert(); | ||||||
|  | 
 | ||||||
|  | 	//returns the orientation of the polygon
 | ||||||
|  | 	//possible values:
 | ||||||
|  | 	//   Triangulator_CCW : polygon vertices are in counter-clockwise order
 | ||||||
|  | 	//   Triangulator_CW : polygon vertices are in clockwise order
 | ||||||
|  | 	//       0 : the polygon has no (measurable) area
 | ||||||
|  | 	int GetOrientation(); | ||||||
|  | 
 | ||||||
|  | 	//sets the polygon orientation
 | ||||||
|  | 	//orientation can be
 | ||||||
|  | 	//   Triangulator_CCW : sets vertices in counter-clockwise order
 | ||||||
|  | 	//   Triangulator_CW : sets vertices in clockwise order
 | ||||||
|  | 	void SetOrientation(int orientation); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class TriangulatorPartition { | ||||||
|  | protected: | ||||||
|  | 	struct PartitionVertex { | ||||||
|  | 		bool isActive; | ||||||
|  | 		bool isConvex; | ||||||
|  | 		bool isEar; | ||||||
|  | 
 | ||||||
|  | 		Vector2 p; | ||||||
|  | 		real_t angle; | ||||||
|  | 		PartitionVertex *previous; | ||||||
|  | 		PartitionVertex *next; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	struct MonotoneVertex { | ||||||
|  | 		Vector2 p; | ||||||
|  | 		long previous; | ||||||
|  | 		long next; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	struct VertexSorter{ | ||||||
|  | 		mutable MonotoneVertex *vertices; | ||||||
|  | 		bool operator() (long index1, long index2) const; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	struct Diagonal { | ||||||
|  | 		long index1; | ||||||
|  | 		long index2; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	//dynamic programming state for minimum-weight triangulation
 | ||||||
|  | 	struct DPState { | ||||||
|  | 		bool visible; | ||||||
|  | 		real_t weight; | ||||||
|  | 		long bestvertex; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	//dynamic programming state for convex partitioning
 | ||||||
|  | 	struct DPState2 { | ||||||
|  | 		bool visible; | ||||||
|  | 		long weight; | ||||||
|  | 		List<Diagonal> pairs; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	//edge that intersects the scanline
 | ||||||
|  | 	struct ScanLineEdge { | ||||||
|  | 		mutable long index; | ||||||
|  | 		Vector2 p1; | ||||||
|  | 		Vector2 p2; | ||||||
|  | 
 | ||||||
|  | 		//determines if the edge is to the left of another edge
 | ||||||
|  | 		bool operator< (const ScanLineEdge & other) const; | ||||||
|  | 
 | ||||||
|  | 		bool IsConvex(const Vector2& p1, const Vector2& p2, const Vector2& p3) const; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	//standard helper functions
 | ||||||
|  | 	bool IsConvex(Vector2& p1, Vector2& p2, Vector2& p3); | ||||||
|  | 	bool IsReflex(Vector2& p1, Vector2& p2, Vector2& p3); | ||||||
|  | 	bool IsInside(Vector2& p1, Vector2& p2, Vector2& p3, Vector2 &p); | ||||||
|  | 
 | ||||||
|  | 	bool InCone(Vector2 &p1, Vector2 &p2, Vector2 &p3, Vector2 &p); | ||||||
|  | 	bool InCone(PartitionVertex *v, Vector2 &p); | ||||||
|  | 
 | ||||||
|  | 	int Intersects(Vector2 &p11, Vector2 &p12, Vector2 &p21, Vector2 &p22); | ||||||
|  | 
 | ||||||
|  | 	Vector2 Normalize(const Vector2 &p); | ||||||
|  | 	real_t Distance(const Vector2 &p1, const Vector2 &p2); | ||||||
|  | 
 | ||||||
|  | 	//helper functions for Triangulate_EC
 | ||||||
|  | 	void UpdateVertexReflexity(PartitionVertex *v); | ||||||
|  | 	void UpdateVertex(PartitionVertex *v,PartitionVertex *vertices, long numvertices); | ||||||
|  | 
 | ||||||
|  | 	//helper functions for ConvexPartition_OPT
 | ||||||
|  | 	void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates); | ||||||
|  | 	void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates); | ||||||
|  | 	void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates); | ||||||
|  | 
 | ||||||
|  | 	//helper functions for MonotonePartition
 | ||||||
|  | 	bool Below(Vector2 &p1, Vector2 &p2); | ||||||
|  | 	void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2, | ||||||
|  | 			 char *vertextypes, Set<ScanLineEdge>::Element **edgeTreeIterators, | ||||||
|  | 			 Set<ScanLineEdge> *edgeTree, long *helpers); | ||||||
|  | 
 | ||||||
|  | 	//triangulates a monotone polygon, used in Triangulate_MONO
 | ||||||
|  | 	int TriangulateMonotone(TriangulatorPoly *inPoly, List<TriangulatorPoly> *triangles); | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 	//simple heuristic procedure for removing holes from a list of polygons
 | ||||||
|  | 	//works by creating a diagonal from the rightmost hole vertex to some visible vertex
 | ||||||
|  | 	//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
 | ||||||
|  | 	//space complexity: O(n)
 | ||||||
|  | 	//params:
 | ||||||
|  | 	//   inpolys : a list of polygons that can contain holes
 | ||||||
|  | 	//             vertices of all non-hole polys have to be in counter-clockwise order
 | ||||||
|  | 	//             vertices of all hole polys have to be in clockwise order
 | ||||||
|  | 	//   outpolys : a list of polygons without holes
 | ||||||
|  | 	//returns 1 on success, 0 on failure
 | ||||||
|  | 	int RemoveHoles(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *outpolys); | ||||||
|  | 
 | ||||||
|  | 	//triangulates a polygon by ear clipping
 | ||||||
|  | 	//time complexity O(n^2), n is the number of vertices
 | ||||||
|  | 	//space complexity: O(n)
 | ||||||
|  | 	//params:
 | ||||||
|  | 	//   poly : an input polygon to be triangulated
 | ||||||
|  | 	//          vertices have to be in counter-clockwise order
 | ||||||
|  | 	//   triangles : a list of triangles (result)
 | ||||||
|  | 	//returns 1 on success, 0 on failure
 | ||||||
|  | 	int Triangulate_EC(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles); | ||||||
|  | 
 | ||||||
|  | 	//triangulates a list of polygons that may contain holes by ear clipping algorithm
 | ||||||
|  | 	//first calls RemoveHoles to get rid of the holes, and then Triangulate_EC for each resulting polygon
 | ||||||
|  | 	//time complexity: O(h*(n^2)), h is the number of holes, n is the number of vertices
 | ||||||
|  | 	//space complexity: O(n)
 | ||||||
|  | 	//params:
 | ||||||
|  | 	//   inpolys : a list of polygons to be triangulated (can contain holes)
 | ||||||
|  | 	//             vertices of all non-hole polys have to be in counter-clockwise order
 | ||||||
|  | 	//             vertices of all hole polys have to be in clockwise order
 | ||||||
|  | 	//   triangles : a list of triangles (result)
 | ||||||
|  | 	//returns 1 on success, 0 on failure
 | ||||||
|  | 	int Triangulate_EC(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles); | ||||||
|  | 
 | ||||||
|  | 	//creates an optimal polygon triangulation in terms of minimal edge length
 | ||||||
|  | 	//time complexity: O(n^3), n is the number of vertices
 | ||||||
|  | 	//space complexity: O(n^2)
 | ||||||
|  | 	//params:
 | ||||||
|  | 	//   poly : an input polygon to be triangulated
 | ||||||
|  | 	//          vertices have to be in counter-clockwise order
 | ||||||
|  | 	//   triangles : a list of triangles (result)
 | ||||||
|  | 	//returns 1 on success, 0 on failure
 | ||||||
|  | 	int Triangulate_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles); | ||||||
|  | 
 | ||||||
|  | 	//triangulates a polygons by firstly partitioning it into monotone polygons
 | ||||||
|  | 	//time complexity: O(n*log(n)), n is the number of vertices
 | ||||||
|  | 	//space complexity: O(n)
 | ||||||
|  | 	//params:
 | ||||||
|  | 	//   poly : an input polygon to be triangulated
 | ||||||
|  | 	//          vertices have to be in counter-clockwise order
 | ||||||
|  | 	//   triangles : a list of triangles (result)
 | ||||||
|  | 	//returns 1 on success, 0 on failure
 | ||||||
|  | 	int Triangulate_MONO(TriangulatorPoly *poly, List<TriangulatorPoly> *triangles); | ||||||
|  | 
 | ||||||
|  | 	//triangulates a list of polygons by firstly partitioning them into monotone polygons
 | ||||||
|  | 	//time complexity: O(n*log(n)), n is the number of vertices
 | ||||||
|  | 	//space complexity: O(n)
 | ||||||
|  | 	//params:
 | ||||||
|  | 	//   inpolys : a list of polygons to be triangulated (can contain holes)
 | ||||||
|  | 	//             vertices of all non-hole polys have to be in counter-clockwise order
 | ||||||
|  | 	//             vertices of all hole polys have to be in clockwise order
 | ||||||
|  | 	//   triangles : a list of triangles (result)
 | ||||||
|  | 	//returns 1 on success, 0 on failure
 | ||||||
|  | 	int Triangulate_MONO(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *triangles); | ||||||
|  | 
 | ||||||
|  | 	//creates a monotone partition of a list of polygons that can contain holes
 | ||||||
|  | 	//time complexity: O(n*log(n)), n is the number of vertices
 | ||||||
|  | 	//space complexity: O(n)
 | ||||||
|  | 	//params:
 | ||||||
|  | 	//   inpolys : a list of polygons to be triangulated (can contain holes)
 | ||||||
|  | 	//             vertices of all non-hole polys have to be in counter-clockwise order
 | ||||||
|  | 	//             vertices of all hole polys have to be in clockwise order
 | ||||||
|  | 	//   monotonePolys : a list of monotone polygons (result)
 | ||||||
|  | 	//returns 1 on success, 0 on failure
 | ||||||
|  | 	int MonotonePartition(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *monotonePolys); | ||||||
|  | 
 | ||||||
|  | 	//partitions a polygon into convex polygons by using Hertel-Mehlhorn algorithm
 | ||||||
|  | 	//the algorithm gives at most four times the number of parts as the optimal algorithm
 | ||||||
|  | 	//however, in practice it works much better than that and often gives optimal partition
 | ||||||
|  | 	//uses triangulation obtained by ear clipping as intermediate result
 | ||||||
|  | 	//time complexity O(n^2), n is the number of vertices
 | ||||||
|  | 	//space complexity: O(n)
 | ||||||
|  | 	//params:
 | ||||||
|  | 	//   poly : an input polygon to be partitioned
 | ||||||
|  | 	//          vertices have to be in counter-clockwise order
 | ||||||
|  | 	//   parts : resulting list of convex polygons
 | ||||||
|  | 	//returns 1 on success, 0 on failure
 | ||||||
|  | 	int ConvexPartition_HM(TriangulatorPoly *poly, List<TriangulatorPoly> *parts); | ||||||
|  | 
 | ||||||
|  | 	//partitions a list of polygons into convex parts by using Hertel-Mehlhorn algorithm
 | ||||||
|  | 	//the algorithm gives at most four times the number of parts as the optimal algorithm
 | ||||||
|  | 	//however, in practice it works much better than that and often gives optimal partition
 | ||||||
|  | 	//uses triangulation obtained by ear clipping as intermediate result
 | ||||||
|  | 	//time complexity O(n^2), n is the number of vertices
 | ||||||
|  | 	//space complexity: O(n)
 | ||||||
|  | 	//params:
 | ||||||
|  | 	//   inpolys : an input list of polygons to be partitioned
 | ||||||
|  | 	//             vertices of all non-hole polys have to be in counter-clockwise order
 | ||||||
|  | 	//             vertices of all hole polys have to be in clockwise order
 | ||||||
|  | 	//   parts : resulting list of convex polygons
 | ||||||
|  | 	//returns 1 on success, 0 on failure
 | ||||||
|  | 	int ConvexPartition_HM(List<TriangulatorPoly> *inpolys, List<TriangulatorPoly> *parts); | ||||||
|  | 
 | ||||||
|  | 	//optimal convex partitioning (in terms of number of resulting convex polygons)
 | ||||||
|  | 	//using the Keil-Snoeyink algorithm
 | ||||||
|  | 	//M. Keil, J. Snoeyink, "On the time bound for convex decomposition of simple polygons", 1998
 | ||||||
|  | 	//time complexity O(n^3), n is the number of vertices
 | ||||||
|  | 	//space complexity: O(n^3)
 | ||||||
|  | 	//   poly : an input polygon to be partitioned
 | ||||||
|  | 	//          vertices have to be in counter-clockwise order
 | ||||||
|  | 	//   parts : resulting list of convex polygons
 | ||||||
|  | 	//returns 1 on success, 0 on failure
 | ||||||
|  | 	int ConvexPartition_OPT(TriangulatorPoly *poly, List<TriangulatorPoly> *parts); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | @ -62,6 +62,8 @@ void Input::_bind_methods() { | ||||||
| 	ObjectTypeDB::bind_method(_MD("set_mouse_mode","mode"),&Input::set_mouse_mode); | 	ObjectTypeDB::bind_method(_MD("set_mouse_mode","mode"),&Input::set_mouse_mode); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_mouse_mode"),&Input::get_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("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_VISIBLE ); | ||||||
| 	BIND_CONSTANT( MOUSE_MODE_HIDDEN ); | 	BIND_CONSTANT( MOUSE_MODE_HIDDEN ); | ||||||
|  |  | ||||||
|  | @ -130,7 +130,7 @@ void ResourceImportMetadata::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ObjectTypeDB::bind_method(_MD("set_editor","name"),&ResourceImportMetadata::set_editor); | 	ObjectTypeDB::bind_method(_MD("set_editor","name"),&ResourceImportMetadata::set_editor); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_editor"),&ResourceImportMetadata::get_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_path","idx"),&ResourceImportMetadata::get_source_path); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_source_md5","idx"),&ResourceImportMetadata::get_source_md5); | 	ObjectTypeDB::bind_method(_MD("get_source_md5","idx"),&ResourceImportMetadata::get_source_md5); | ||||||
| 	ObjectTypeDB::bind_method(_MD("remove_source","idx"),&ResourceImportMetadata::remove_source); | 	ObjectTypeDB::bind_method(_MD("remove_source","idx"),&ResourceImportMetadata::remove_source); | ||||||
|  |  | ||||||
							
								
								
									
										37
									
								
								core/set.h
									
										
									
									
									
								
							
							
						
						
									
										37
									
								
								core/set.h
									
										
									
									
									
								
							|  | @ -249,6 +249,37 @@ private: | ||||||
| 		return (node!=_data._nil)?node:NULL; | 		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) { | 	Element *_insert(const T& p_value, bool& r_exists) { | ||||||
| 		 | 		 | ||||||
|  | @ -583,6 +614,12 @@ public: | ||||||
| 		return e; | 		return e; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	Element *lower_bound(const T& p_value) const { | ||||||
|  | 
 | ||||||
|  | 		return _lower_bound(p_value); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	 | ||||||
| 	inline int size() const { return _data.size_cache; } | 	inline int size() const { return _data.size_cache; } | ||||||
| 	int calculate_depth() const { | 	int calculate_depth() const { | ||||||
| 		// used for debug mostly
 | 		// used for debug mostly
 | ||||||
|  |  | ||||||
							
								
								
									
										296
									
								
								core/ustring.cpp
									
										
									
									
									
								
							
							
						
						
									
										296
									
								
								core/ustring.cpp
									
										
									
									
									
								
							|  | @ -34,6 +34,7 @@ | ||||||
| #include "io/md5.h" | #include "io/md5.h" | ||||||
| #include "ucaps.h" | #include "ucaps.h" | ||||||
| #include "color.h" | #include "color.h" | ||||||
|  | #include "variant.h" | ||||||
| #define MAX_DIGITS 6 | #define MAX_DIGITS 6 | ||||||
| #define UPPERCASE(m_c) (((m_c)>='a' && (m_c)<='z')?((m_c)-('a'-'A')):(m_c)) | #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)) | #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; | 	bool sign=p_num<0; | ||||||
| 	int64_t num=ABS(p_num); | 	int64_t num=ABS(p_num); | ||||||
|  | @ -990,7 +991,7 @@ String String::num_int64(int64_t p_num) { | ||||||
| 
 | 
 | ||||||
| 	int chars=0; | 	int chars=0; | ||||||
| 	do { | 	do { | ||||||
| 		n/=10; | 		n/=base; | ||||||
| 		chars++; | 		chars++; | ||||||
| 	} while(n); | 	} while(n); | ||||||
| 
 | 
 | ||||||
|  | @ -1002,8 +1003,15 @@ String String::num_int64(int64_t p_num) { | ||||||
| 	c[chars]=0; | 	c[chars]=0; | ||||||
| 	n=num; | 	n=num; | ||||||
| 	do { | 	do { | ||||||
| 		c[--chars]='0'+(n%10); | 		int mod = n%base; | ||||||
| 		n/=10; | 		if (mod >= 10) { | ||||||
|  | 			char a = (capitalize_hex ? 'A' : 'a'); | ||||||
|  | 			c[--chars]=a+(mod - 10); | ||||||
|  | 		} else { | ||||||
|  | 			c[--chars]='0'+mod; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		n/=base; | ||||||
| 	} while(n); | 	} while(n); | ||||||
| 
 | 
 | ||||||
| 	if (sign) | 	if (sign) | ||||||
|  | @ -3518,4 +3526,284 @@ String rtoss(double p_val) { | ||||||
| 	return String::num_scientific(p_val); | 	return String::num_scientific(p_val); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Right-pad with a character.
 | ||||||
|  | String String::rpad(int min_length, const String& character) const { | ||||||
|  | 	String s = *this; | ||||||
|  | 	int padding = min_length - s.length(); | ||||||
|  | 	if (padding > 0) { | ||||||
|  | 		for (int i = 0; i < padding; i++) s = s + character; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|  | 	return s; | ||||||
|  | } | ||||||
|  | // Left-pad with a character.
 | ||||||
|  | String String::lpad(int min_length, const String& character) const { | ||||||
|  | 	String s = *this; | ||||||
|  | 	int padding = min_length - s.length(); | ||||||
|  | 	if (padding > 0) { | ||||||
|  | 		for (int i = 0; i < padding; i++) s = character + s; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // sprintf is implemented in GDScript via:
 | ||||||
|  | //   "fish %s pie" % "frog"
 | ||||||
|  | //   "fish %s %d pie" % ["frog", 12]
 | ||||||
|  | String String::sprintf(const Array& values) const { | ||||||
|  | 
 | ||||||
|  | 	String formatted; | ||||||
|  | 	CharType* self = (CharType*)c_str(); | ||||||
|  | 	int num_items = values.size(); | ||||||
|  | 	bool in_format = false; | ||||||
|  | 	int value_index = 0; | ||||||
|  | 	int min_chars; | ||||||
|  | 	int min_decimals; | ||||||
|  | 	bool in_decimals; | ||||||
|  | 	bool pad_with_zeroes; | ||||||
|  | 	bool left_justified; | ||||||
|  | 	bool show_sign; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	for (; *self; self++) { | ||||||
|  | 		const CharType c = *self; | ||||||
|  | 
 | ||||||
|  | 		if (in_format) { // We have % - lets see what else we get.
 | ||||||
|  | 			switch (c) { | ||||||
|  | 				case '%': { // Replace %% with %
 | ||||||
|  | 					formatted += chr(c); | ||||||
|  | 					in_format = false; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				case 'd': // Integer (signed)
 | ||||||
|  | 				case 'o': // Octal
 | ||||||
|  | 				case 'x': // Hexadecimal (lowercase)
 | ||||||
|  | 				case 'X': { // Hexadecimal (uppercase)
 | ||||||
|  | 					if (value_index >= values.size()) { | ||||||
|  | 						ERR_EXPLAIN("not enough arguments for format string"); | ||||||
|  | 						ERR_FAIL_V(""); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (!values[value_index].is_num()) { | ||||||
|  | 						ERR_EXPLAIN("a number is required"); | ||||||
|  | 						ERR_FAIL_V(""); | ||||||
|  | 					} | ||||||
|  | 					 | ||||||
|  | 					int64_t value = values[value_index]; | ||||||
|  | 					int base; | ||||||
|  | 					bool capitalize = false; | ||||||
|  | 					switch (c) { | ||||||
|  | 						case 'd': base = 10; break; | ||||||
|  | 						case 'o': base = 8; break; | ||||||
|  | 						case 'x': base = 16; break; | ||||||
|  | 						case 'X': base = 16; capitalize = true; break; | ||||||
|  | 					} | ||||||
|  | 					// Get basic number.
 | ||||||
|  | 					String str = String::num_int64(value, base, capitalize); | ||||||
|  | 
 | ||||||
|  | 					// Sign.
 | ||||||
|  | 					if (show_sign && value >= 0) { | ||||||
|  | 						str = str.insert(0, "+"); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// Padding.
 | ||||||
|  | 					String pad_char = pad_with_zeroes ? String("0") : String(" "); | ||||||
|  | 					if (left_justified) { | ||||||
|  | 						str = str.rpad(min_chars, pad_char); | ||||||
|  | 					} else { | ||||||
|  | 						str = str.lpad(min_chars, pad_char); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					formatted += str; | ||||||
|  | 					++value_index; | ||||||
|  | 					in_format = false; | ||||||
|  | 
 | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				case 'f': { // Float
 | ||||||
|  | 					if (value_index >= values.size()) { | ||||||
|  | 						ERR_EXPLAIN("not enough arguments for format string"); | ||||||
|  | 						ERR_FAIL_V(""); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (!values[value_index].is_num()) { | ||||||
|  | 						ERR_EXPLAIN("a number is required"); | ||||||
|  | 						ERR_FAIL_V(""); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					double value = values[value_index]; | ||||||
|  | 					String str = String::num(value, min_decimals); | ||||||
|  | 
 | ||||||
|  | 					// Pad decimals out.
 | ||||||
|  | 					str = str.pad_decimals(min_decimals); | ||||||
|  | 
 | ||||||
|  | 					// Show sign
 | ||||||
|  | 					if (show_sign && value >= 0) { | ||||||
|  | 						str = str.insert(0, "+"); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// Padding
 | ||||||
|  | 					if (left_justified) { | ||||||
|  | 						str = str.rpad(min_chars); | ||||||
|  | 					} else { | ||||||
|  | 						str = str.lpad(min_chars); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					formatted += str; | ||||||
|  | 					++value_index; | ||||||
|  | 					in_format = false; | ||||||
|  | 					 | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				case 's': { // String
 | ||||||
|  | 					if (value_index >= values.size()) { | ||||||
|  | 						ERR_EXPLAIN("not enough arguments for format string"); | ||||||
|  | 						ERR_FAIL_V(""); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					String str = values[value_index]; | ||||||
|  | 					// Padding.
 | ||||||
|  | 					if (left_justified) { | ||||||
|  | 						str = str.rpad(min_chars); | ||||||
|  | 					} else { | ||||||
|  | 						str = str.lpad(min_chars); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					formatted += str; | ||||||
|  | 					++value_index; | ||||||
|  | 					in_format = false; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				case 'c': { | ||||||
|  | 					if (value_index >= values.size()) { | ||||||
|  | 						ERR_EXPLAIN("not enough arguments for format string"); | ||||||
|  | 						ERR_FAIL_V(""); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// Convert to character.
 | ||||||
|  | 					String str; | ||||||
|  | 					if (values[value_index].is_num()) { | ||||||
|  | 						int value = values[value_index]; | ||||||
|  | 						if (value < 0) { | ||||||
|  | 							ERR_EXPLAIN("unsigned byte integer is lower than maximum") | ||||||
|  | 							ERR_FAIL_V(""); | ||||||
|  | 						} else if (value > 255) { | ||||||
|  | 							ERR_EXPLAIN("unsigned byte integer is greater than maximum") | ||||||
|  | 							ERR_FAIL_V(""); | ||||||
|  | 						} | ||||||
|  | 						str = chr(values[value_index]); | ||||||
|  | 					} else if (values[value_index].get_type() == Variant::STRING) { | ||||||
|  | 						str = values[value_index]; | ||||||
|  | 						if (str.length() != 1) { | ||||||
|  | 							ERR_EXPLAIN("%c requires number or single-character string"); | ||||||
|  | 							ERR_FAIL_V(""); | ||||||
|  | 						} | ||||||
|  | 					} else { | ||||||
|  | 						ERR_EXPLAIN("%c requires number or single-character string"); | ||||||
|  | 						ERR_FAIL_V(""); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					// Padding.
 | ||||||
|  | 					if (left_justified) { | ||||||
|  | 						str = str.rpad(min_chars); | ||||||
|  | 					} else { | ||||||
|  | 						str = str.lpad(min_chars); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					formatted += str; | ||||||
|  | 					++value_index; | ||||||
|  | 					in_format = false; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				case '-': { // Left justify
 | ||||||
|  | 					left_justified = true; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				case '+': { // Show + if positive.
 | ||||||
|  | 					show_sign = true; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				case '0': case '1': case '2': case '3': case '4': | ||||||
|  | 				case '5': case '6': case '7': case '8': case '9': { | ||||||
|  | 					int n = c - '0'; | ||||||
|  | 					if (in_decimals) { | ||||||
|  | 						min_decimals *= 10; | ||||||
|  | 						min_decimals += n; | ||||||
|  | 					} else { | ||||||
|  | 						if (c == '0' && min_chars == 0) { | ||||||
|  | 							pad_with_zeroes = true; | ||||||
|  | 						} else { | ||||||
|  | 							min_chars *= 10; | ||||||
|  | 							min_chars += n; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 				case '.': { // Float separtor.
 | ||||||
|  | 					if (in_decimals) { | ||||||
|  | 						ERR_EXPLAIN("too many decimal points in format"); | ||||||
|  | 						ERR_FAIL_V(""); | ||||||
|  | 					} | ||||||
|  | 					in_decimals = true; | ||||||
|  | 					min_decimals = 0; // We want to add the value manually.
 | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				case '*': { // Dyanmic width, based on value.
 | ||||||
|  | 					if (value_index >= values.size()) { | ||||||
|  | 						ERR_EXPLAIN("not enough arguments for format string"); | ||||||
|  | 						ERR_FAIL_V(""); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (!values[value_index].is_num()) { | ||||||
|  | 						ERR_EXPLAIN("* wants number"); | ||||||
|  | 						ERR_FAIL_V(""); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					int size = values[value_index]; | ||||||
|  | 
 | ||||||
|  | 					if (in_decimals) { | ||||||
|  | 						min_decimals = size; | ||||||
|  | 					} else { | ||||||
|  | 						min_chars = size; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					++value_index; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				default: { | ||||||
|  | 					ERR_EXPLAIN("unsupported format character"); | ||||||
|  |   					ERR_FAIL_V(""); | ||||||
|  |   				} | ||||||
|  | 			} | ||||||
|  | 		} else { // Not in format string.
 | ||||||
|  | 			switch (c) { | ||||||
|  | 				case '%': | ||||||
|  | 					in_format = true; | ||||||
|  | 					// Back to defaults:
 | ||||||
|  | 					min_chars = 0; | ||||||
|  | 					min_decimals = 6; | ||||||
|  | 					pad_with_zeroes = false; | ||||||
|  | 					left_justified = false; | ||||||
|  | 					show_sign = false; | ||||||
|  | 					in_decimals = false; | ||||||
|  | 					break; | ||||||
|  | 				default: | ||||||
|  | 					formatted += chr(c); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (in_format) { | ||||||
|  | 		ERR_EXPLAIN("incomplete format"); | ||||||
|  |   		ERR_FAIL_V(""); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (value_index != values.size()) { | ||||||
|  | 		ERR_EXPLAIN("not all arguments converted during string formatting"); | ||||||
|  |   		ERR_FAIL_V(""); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return formatted; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -31,6 +31,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "typedefs.h" | #include "typedefs.h" | ||||||
| #include "vector.h" | #include "vector.h" | ||||||
|  | #include "array.h" | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| 	@author red <red@killy> | 	@author red <red@killy> | ||||||
|  | @ -127,10 +128,13 @@ public: | ||||||
| 	String insert(int p_at_pos,String p_string) const; | 	String insert(int p_at_pos,String p_string) const; | ||||||
| 	String pad_decimals(int p_digits) const; | 	String pad_decimals(int p_digits) const; | ||||||
| 	String pad_zeros(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(double p_num,int p_decimals=-1); | ||||||
| 	static String num_scientific(double p_num); | 	static String num_scientific(double p_num); | ||||||
| 	static String num_real(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 chr(CharType p_char); | ||||||
| 	static String md5(const uint8_t *p_md5); | 	static String md5(const uint8_t *p_md5); | ||||||
| 	bool is_numeric() const; | 	bool is_numeric() const; | ||||||
|  |  | ||||||
|  | @ -2631,8 +2631,13 @@ Variant Variant::call(const StringName& p_method,VARIANT_ARG_DECLARE) { | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Variant::construct_from_string(const String& p_string,Variant& r_value,ObjectConstruct p_obj_construct,void *p_construct_ud) { | ||||||
| 
 | 
 | ||||||
| String Variant::get_construct_string() const { | 	r_value=Variant(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | String Variant::get_construct_string(ObjectDeConstruct p_obj_deconstruct,void *p_deconstruct_ud) const { | ||||||
| 
 | 
 | ||||||
| 	switch( type ) { | 	switch( type ) { | ||||||
| 
 | 
 | ||||||
|  | @ -2640,7 +2645,7 @@ String Variant::get_construct_string() const { | ||||||
| 		case BOOL: return _data._bool ? "true" : "false"; | 		case BOOL: return _data._bool ? "true" : "false"; | ||||||
| 		case INT: return String::num(_data._int); | 		case INT: return String::num(_data._int); | ||||||
| 		case REAL: return String::num(_data._real); | 		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 VECTOR2: return "Vector2("+operator Vector2()+")"; | ||||||
| 		case RECT2: return "Rect2("+operator Rect2()+")"; | 		case RECT2: return "Rect2("+operator Rect2()+")"; | ||||||
| 		case MATRIX32: return "Matrix32("+operator Matrix32()+")"; | 		case MATRIX32: return "Matrix32("+operator Matrix32()+")"; | ||||||
|  | @ -2651,7 +2656,7 @@ String Variant::get_construct_string() const { | ||||||
| 		case QUAT: return "Quat("+operator Quat()+")"; | 		case QUAT: return "Quat("+operator Quat()+")"; | ||||||
| 		case MATRIX3: return "Matrix3("+operator Matrix3()+")"; | 		case MATRIX3: return "Matrix3("+operator Matrix3()+")"; | ||||||
| 		case TRANSFORM: return "Transform("+operator Transform()+")"; | 		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 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 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: { | 		case DICTIONARY: { | ||||||
|  | @ -2667,8 +2672,8 @@ String Variant::get_construct_string() const { | ||||||
| 			for(List<Variant>::Element *E=keys.front();E;E=E->next()) { | 			for(List<Variant>::Element *E=keys.front();E;E=E->next()) { | ||||||
| 
 | 
 | ||||||
| 				_VariantStrPair sp; | 				_VariantStrPair sp; | ||||||
| 				sp.key=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(); | 				sp.value=d[E->get()].get_construct_string(p_obj_deconstruct,p_deconstruct_ud); | ||||||
| 				pairs.push_back(sp); | 				pairs.push_back(sp); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | @ -2686,50 +2691,50 @@ String Variant::get_construct_string() const { | ||||||
| 		case VECTOR3_ARRAY: { | 		case VECTOR3_ARRAY: { | ||||||
| 
 | 
 | ||||||
| 			DVector<Vector3> vec = operator DVector<Vector3>(); | 			DVector<Vector3> vec = operator DVector<Vector3>(); | ||||||
| 			String str="["; | 			String str="Vector3Array(["; | ||||||
| 			for(int i=0;i<vec.size();i++) { | 			for(int i=0;i<vec.size();i++) { | ||||||
| 
 | 
 | ||||||
| 				if (i>0) | 				if (i>0) | ||||||
| 					str+=", "; | 					str+=", "; | ||||||
| 				str+=Variant( vec[i] ).get_construct_string(); | 				str+=Variant( vec[i] ).get_construct_string(); | ||||||
| 			} | 			} | ||||||
| 			return str+"]"; | 			return str+"])"; | ||||||
| 		} break; | 		} break; | ||||||
| 		case STRING_ARRAY: { | 		case STRING_ARRAY: { | ||||||
| 
 | 
 | ||||||
| 			DVector<String> vec = operator DVector<String>(); | 			DVector<String> vec = operator DVector<String>(); | ||||||
| 			String str="["; | 			String str="StringArray(["; | ||||||
| 			for(int i=0;i<vec.size();i++) { | 			for(int i=0;i<vec.size();i++) { | ||||||
| 
 | 
 | ||||||
| 				if (i>0) | 				if (i>0) | ||||||
| 					str+=", "; | 					str+=", "; | ||||||
| 				str=str+=Variant( vec[i] ).get_construct_string(); | 				str=str+=Variant( vec[i] ).get_construct_string(); | ||||||
| 			} | 			} | ||||||
| 			return str+"]"; | 			return str+"])"; | ||||||
| 		} break; | 		} break; | ||||||
| 		case INT_ARRAY: { | 		case INT_ARRAY: { | ||||||
| 
 | 
 | ||||||
| 			DVector<int> vec = operator DVector<int>(); | 			DVector<int> vec = operator DVector<int>(); | ||||||
| 			String str="["; | 			String str="IntArray(["; | ||||||
| 			for(int i=0;i<vec.size();i++) { | 			for(int i=0;i<vec.size();i++) { | ||||||
| 
 | 
 | ||||||
| 				if (i>0) | 				if (i>0) | ||||||
| 					str+=", "; | 					str+=", "; | ||||||
| 				str=str+itos(vec[i]); | 				str=str+itos(vec[i]); | ||||||
| 			} | 			} | ||||||
| 			return str+"]"; | 			return str+"])"; | ||||||
| 		} break; | 		} break; | ||||||
| 		case REAL_ARRAY: { | 		case REAL_ARRAY: { | ||||||
| 
 | 
 | ||||||
| 			DVector<real_t> vec = operator DVector<real_t>(); | 			DVector<real_t> vec = operator DVector<real_t>(); | ||||||
| 			String str="["; | 			String str="FloatArray(["; | ||||||
| 			for(int i=0;i<vec.size();i++) { | 			for(int i=0;i<vec.size();i++) { | ||||||
| 
 | 
 | ||||||
| 				if (i>0) | 				if (i>0) | ||||||
| 					str+=", "; | 					str+=", "; | ||||||
| 				str=str+rtos(vec[i]); | 				str=str+rtos(vec[i]); | ||||||
| 			} | 			} | ||||||
| 			return str+"]"; | 			return str+"])"; | ||||||
| 		} break; | 		} break; | ||||||
| 		case ARRAY: { | 		case ARRAY: { | ||||||
| 
 | 
 | ||||||
|  | @ -2738,16 +2743,20 @@ String Variant::get_construct_string() const { | ||||||
| 			for (int i=0; i<arr.size(); i++) { | 			for (int i=0; i<arr.size(); i++) { | ||||||
| 				if (i) | 				if (i) | ||||||
| 					str+=", "; | 					str+=", "; | ||||||
| 				str += arr[i].get_construct_string(); | 				str += arr[i].get_construct_string(p_obj_deconstruct,p_deconstruct_ud); | ||||||
| 			}; | 			}; | ||||||
| 			return str+"]"; | 			return str+"]"; | ||||||
| 
 | 
 | ||||||
| 		} break; | 		} break; | ||||||
| 		case OBJECT: { | 		case OBJECT: { | ||||||
| 
 | 
 | ||||||
| 			if (_get_obj().obj) | 			if (_get_obj().obj) { | ||||||
| 				return _get_obj().obj->get_type()+".new()"; | 				if (p_obj_deconstruct) { | ||||||
| 			else | 					return "Object(\""+p_obj_deconstruct(Variant(*this),p_deconstruct_ud).c_escape()+")"; | ||||||
|  | 				} else { | ||||||
|  | 					return _get_obj().obj->get_type()+".new()"; | ||||||
|  | 				} | ||||||
|  | 			} else | ||||||
| 				return "null"; | 				return "null"; | ||||||
| 
 | 
 | ||||||
| 		} break; | 		} break; | ||||||
|  |  | ||||||
|  | @ -419,7 +419,11 @@ public: | ||||||
| 	static bool has_numeric_constant(Variant::Type p_type, const StringName& p_value); | 	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); | 	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
 | 	void operator=(const Variant& p_variant); // only this is enough for all the other types
 | ||||||
| 	Variant(const Variant& p_variant); | 	Variant(const Variant& p_variant); | ||||||
|  |  | ||||||
|  | @ -1263,8 +1263,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl | ||||||
| 	ADDFUNC1(VECTOR2,VECTOR2,Vector2,snapped,VECTOR2,"by",varray()); | 	ADDFUNC1(VECTOR2,VECTOR2,Vector2,snapped,VECTOR2,"by",varray()); | ||||||
| 	ADDFUNC0(VECTOR2,REAL,Vector2,get_aspect,varray()); | 	ADDFUNC0(VECTOR2,REAL,Vector2,get_aspect,varray()); | ||||||
| 	ADDFUNC1(VECTOR2,REAL,Vector2,dot,VECTOR2,"with",varray()); | 	ADDFUNC1(VECTOR2,REAL,Vector2,dot,VECTOR2,"with",varray()); | ||||||
| 	ADDFUNC1(VECTOR2,REAL,Vector2,slide,VECTOR2,"vec",varray()); | 	ADDFUNC1(VECTOR2,VECTOR2,Vector2,slide,VECTOR2,"vec",varray()); | ||||||
| 	ADDFUNC1(VECTOR2,REAL,Vector2,reflect,VECTOR2,"vec",varray()); | 	ADDFUNC1(VECTOR2,VECTOR2,Vector2,reflect,VECTOR2,"vec",varray()); | ||||||
| 	//ADDFUNC1(VECTOR2,REAL,Vector2,cross,VECTOR2,"with",varray());
 | 	//ADDFUNC1(VECTOR2,REAL,Vector2,cross,VECTOR2,"with",varray());
 | ||||||
| 
 | 
 | ||||||
| 	ADDFUNC0(RECT2,REAL,Rect2,get_area,varray()); | 	ADDFUNC0(RECT2,REAL,Rect2,get_area,varray()); | ||||||
|  |  | ||||||
							
								
								
									
										433
									
								
								core/variant_construct_string.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										433
									
								
								core/variant_construct_string.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,433 @@ | ||||||
|  | 
 | ||||||
|  | #include "variant.h" | ||||||
|  | 
 | ||||||
|  | class VariantConstruct { | ||||||
|  | 
 | ||||||
|  | 	enum TokenType { | ||||||
|  | 		TK_CURLY_BRACKET_OPEN, | ||||||
|  | 		TK_CURLY_BRACKET_CLOSE, | ||||||
|  | 		TK_BRACKET_OPEN, | ||||||
|  | 		TK_BRACKET_CLOSE, | ||||||
|  | 		TK_IDENTIFIER, | ||||||
|  | 		TK_STRING, | ||||||
|  | 		TK_NUMBER, | ||||||
|  | 		TK_COLON, | ||||||
|  | 		TK_COMMA, | ||||||
|  | 		TK_EOF, | ||||||
|  | 		TK_MAX | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	enum Expecting { | ||||||
|  | 
 | ||||||
|  | 		EXPECT_OBJECT, | ||||||
|  | 		EXPECT_OBJECT_KEY, | ||||||
|  | 		EXPECT_COLON, | ||||||
|  | 		EXPECT_OBJECT_VALUE, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	struct Token { | ||||||
|  | 
 | ||||||
|  | 		TokenType type; | ||||||
|  | 		Variant value; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	static const char * tk_name[TK_MAX]; | ||||||
|  | 
 | ||||||
|  | 	static String _print_var(const Variant& p_var); | ||||||
|  | 
 | ||||||
|  | 	static Error _get_token(const CharType *p_str,int &index, int p_len,Token& r_token,int &line,String &r_err_str); | ||||||
|  | 	static Error _parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud); | ||||||
|  | 	static Error _parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud); | ||||||
|  | 	static Error _parse_dict(Dictionary &object,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud); | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 	static Error parse(const String& p_string,Variant& r_ret,String &r_err_str,int &r_err_line,Variant::ObjectConstruct* p_construct,void* p_ud); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | const char * VariantConstruct::tk_name[TK_MAX] = { | ||||||
|  | 	"'{'", | ||||||
|  | 	"'}'", | ||||||
|  | 	"'['", | ||||||
|  | 	"']'", | ||||||
|  | 	"identifier", | ||||||
|  | 	"string", | ||||||
|  | 	"number", | ||||||
|  | 	"':'", | ||||||
|  | 	"','", | ||||||
|  | 	"EOF", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Error VariantConstruct::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_token,int &line,String &r_err_str) { | ||||||
|  | 
 | ||||||
|  | 	while (true) { | ||||||
|  | 		switch(p_str[idx]) { | ||||||
|  | 
 | ||||||
|  | 			case '\n': { | ||||||
|  | 
 | ||||||
|  | 				line++; | ||||||
|  | 				idx++; | ||||||
|  | 				break; | ||||||
|  | 			}; | ||||||
|  | 			case 0: { | ||||||
|  | 				r_token.type=TK_EOF; | ||||||
|  | 				return OK; | ||||||
|  | 			} break; | ||||||
|  | 			case '{': { | ||||||
|  | 
 | ||||||
|  | 				r_token.type=TK_CURLY_BRACKET_OPEN; | ||||||
|  | 				idx++; | ||||||
|  | 				return OK; | ||||||
|  | 			}; | ||||||
|  | 			case '}': { | ||||||
|  | 
 | ||||||
|  | 				r_token.type=TK_CURLY_BRACKET_CLOSE; | ||||||
|  | 				idx++; | ||||||
|  | 				return OK; | ||||||
|  | 			}; | ||||||
|  | 			case '[': { | ||||||
|  | 
 | ||||||
|  | 				r_token.type=TK_BRACKET_OPEN; | ||||||
|  | 				idx++; | ||||||
|  | 				return OK; | ||||||
|  | 			}; | ||||||
|  | 			case ']': { | ||||||
|  | 
 | ||||||
|  | 				r_token.type=TK_BRACKET_CLOSE; | ||||||
|  | 				idx++; | ||||||
|  | 				return OK; | ||||||
|  | 			}; | ||||||
|  | 			case ':': { | ||||||
|  | 
 | ||||||
|  | 				r_token.type=TK_COLON; | ||||||
|  | 				idx++; | ||||||
|  | 				return OK; | ||||||
|  | 			}; | ||||||
|  | 			case ',': { | ||||||
|  | 
 | ||||||
|  | 				r_token.type=TK_COMMA; | ||||||
|  | 				idx++; | ||||||
|  | 				return OK; | ||||||
|  | 			}; | ||||||
|  | 			case '"': { | ||||||
|  | 
 | ||||||
|  | 				idx++; | ||||||
|  | 				String str; | ||||||
|  | 				while(true) { | ||||||
|  | 					if (p_str[idx]==0) { | ||||||
|  | 						r_err_str="Unterminated String"; | ||||||
|  | 						return ERR_PARSE_ERROR; | ||||||
|  | 					} else if (p_str[idx]=='"') { | ||||||
|  | 						idx++; | ||||||
|  | 						break; | ||||||
|  | 					} else if (p_str[idx]=='\\') { | ||||||
|  | 						//escaped characters...
 | ||||||
|  | 						idx++; | ||||||
|  | 						CharType next = p_str[idx]; | ||||||
|  | 						if (next==0) { | ||||||
|  | 							r_err_str="Unterminated String"; | ||||||
|  | 							return  ERR_PARSE_ERROR; | ||||||
|  | 						} | ||||||
|  | 						CharType res=0; | ||||||
|  | 
 | ||||||
|  | 						switch(next) { | ||||||
|  | 
 | ||||||
|  | 							case 'b': res=8; break; | ||||||
|  | 							case 't': res=9; break; | ||||||
|  | 							case 'n': res=10; break; | ||||||
|  | 							case 'f': res=12; break; | ||||||
|  | 							case 'r': res=13; break; | ||||||
|  | 							case '\"': res='\"'; break; | ||||||
|  | 							case '\\': res='\\'; break; | ||||||
|  | 							case '/': res='/'; break; //wtf
 | ||||||
|  | 							case 'u': { | ||||||
|  | 								//hexnumbarh - oct is deprecated
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 								for(int j=0;j<4;j++) { | ||||||
|  | 									CharType c = p_str[idx+j+1]; | ||||||
|  | 									if (c==0) { | ||||||
|  | 										r_err_str="Unterminated String"; | ||||||
|  | 										return ERR_PARSE_ERROR; | ||||||
|  | 									} | ||||||
|  | 									if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) { | ||||||
|  | 
 | ||||||
|  | 										r_err_str="Malformed hex constant in string"; | ||||||
|  | 										return ERR_PARSE_ERROR; | ||||||
|  | 									} | ||||||
|  | 									CharType v; | ||||||
|  | 									if (c>='0' && c<='9') { | ||||||
|  | 										v=c-'0'; | ||||||
|  | 									} else if (c>='a' && c<='f') { | ||||||
|  | 										v=c-'a'; | ||||||
|  | 										v+=10; | ||||||
|  | 									} else if (c>='A' && c<='F') { | ||||||
|  | 										v=c-'A'; | ||||||
|  | 										v+=10; | ||||||
|  | 									} else { | ||||||
|  | 										ERR_PRINT("BUG"); | ||||||
|  | 										v=0; | ||||||
|  | 									} | ||||||
|  | 
 | ||||||
|  | 									res<<=4; | ||||||
|  | 									res|=v; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 								} | ||||||
|  | 								idx+=4; //will add at the end anyway
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 							} break; | ||||||
|  | 							default: { | ||||||
|  | 
 | ||||||
|  | 								r_err_str="Invalid escape sequence"; | ||||||
|  | 								return ERR_PARSE_ERROR; | ||||||
|  | 							} break; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						str+=res; | ||||||
|  | 
 | ||||||
|  | 					} else { | ||||||
|  | 						if (p_str[idx]=='\n') | ||||||
|  | 							line++; | ||||||
|  | 						str+=p_str[idx]; | ||||||
|  | 					} | ||||||
|  | 					idx++; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				r_token.type=TK_STRING; | ||||||
|  | 				r_token.value=str; | ||||||
|  | 				return OK; | ||||||
|  | 
 | ||||||
|  | 			} break; | ||||||
|  | 			default: { | ||||||
|  | 
 | ||||||
|  | 				if (p_str[idx]<=32) { | ||||||
|  | 					idx++; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) { | ||||||
|  | 					//a number
 | ||||||
|  | 					const CharType *rptr; | ||||||
|  | 					double number = String::to_double(&p_str[idx],&rptr); | ||||||
|  | 					idx+=(rptr - &p_str[idx]); | ||||||
|  | 					r_token.type=TK_NUMBER; | ||||||
|  | 					r_token.value=number; | ||||||
|  | 					return OK; | ||||||
|  | 
 | ||||||
|  | 				} else if ((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) { | ||||||
|  | 
 | ||||||
|  | 					String id; | ||||||
|  | 
 | ||||||
|  | 					while((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) { | ||||||
|  | 
 | ||||||
|  | 						id+=p_str[idx]; | ||||||
|  | 						idx++; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					r_token.type=TK_IDENTIFIER; | ||||||
|  | 					r_token.value=id; | ||||||
|  | 					return OK; | ||||||
|  | 				} else { | ||||||
|  | 					r_err_str="Unexpected character."; | ||||||
|  | 					return ERR_PARSE_ERROR; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ERR_PARSE_ERROR; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Error VariantConstruct::_parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	if (token.type==TK_CURLY_BRACKET_OPEN) { | ||||||
|  | 
 | ||||||
|  | 		Dictionary d; | ||||||
|  | 		Error err = _parse_dict(d,p_str,index,p_len,line,r_err_str,p_construct,p_ud); | ||||||
|  | 		if (err) | ||||||
|  | 			return err; | ||||||
|  | 		value=d; | ||||||
|  | 		return OK; | ||||||
|  | 	} else if (token.type==TK_BRACKET_OPEN) { | ||||||
|  | 
 | ||||||
|  | 		Array a; | ||||||
|  | 		Error err = _parse_array(a,p_str,index,p_len,line,r_err_str,p_construct,p_ud); | ||||||
|  | 		if (err) | ||||||
|  | 			return err; | ||||||
|  | 		value=a; | ||||||
|  | 		return OK; | ||||||
|  | 
 | ||||||
|  | 	} else if (token.type==TK_IDENTIFIER) { | ||||||
|  | 
 | ||||||
|  | 		String id = token.value; | ||||||
|  | 		if (id=="true") | ||||||
|  | 			value=true; | ||||||
|  | 		else if (id=="false") | ||||||
|  | 			value=false; | ||||||
|  | 		else if (id=="null") | ||||||
|  | 			value=Variant(); | ||||||
|  | 		else { | ||||||
|  | 			r_err_str="Expected 'true','false' or 'null', got '"+id+"'."; | ||||||
|  | 			return ERR_PARSE_ERROR; | ||||||
|  | 		} | ||||||
|  | 		return OK; | ||||||
|  | 
 | ||||||
|  | 	} else if (token.type==TK_NUMBER) { | ||||||
|  | 
 | ||||||
|  | 		value=token.value; | ||||||
|  | 		return OK; | ||||||
|  | 	} else if (token.type==TK_STRING) { | ||||||
|  | 
 | ||||||
|  | 		value=token.value; | ||||||
|  | 		return OK; | ||||||
|  | 	} else { | ||||||
|  | 		r_err_str="Expected value, got "+String(tk_name[token.type])+"."; | ||||||
|  | 		return ERR_PARSE_ERROR; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ERR_PARSE_ERROR; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Error VariantConstruct::_parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) { | ||||||
|  | 
 | ||||||
|  | 	Token token; | ||||||
|  | 	bool need_comma=false; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	while(index<p_len) { | ||||||
|  | 
 | ||||||
|  | 		Error err = _get_token(p_str,index,p_len,token,line,r_err_str); | ||||||
|  | 		if (err!=OK) | ||||||
|  | 			return err; | ||||||
|  | 
 | ||||||
|  | 		if (token.type==TK_BRACKET_CLOSE) { | ||||||
|  | 
 | ||||||
|  | 			return OK; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (need_comma) { | ||||||
|  | 
 | ||||||
|  | 			if (token.type!=TK_COMMA) { | ||||||
|  | 
 | ||||||
|  | 				r_err_str="Expected ','"; | ||||||
|  | 				return ERR_PARSE_ERROR; | ||||||
|  | 			} else { | ||||||
|  | 				need_comma=false; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		Variant v; | ||||||
|  | 		err = _parse_value(v,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud); | ||||||
|  | 		if (err) | ||||||
|  | 			return err; | ||||||
|  | 
 | ||||||
|  | 		array.push_back(v); | ||||||
|  | 		need_comma=true; | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Error VariantConstruct::_parse_dict(Dictionary &dict,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str,Variant::ObjectConstruct* p_construct,void* p_ud) { | ||||||
|  | 
 | ||||||
|  | 	bool at_key=true; | ||||||
|  | 	Variant key; | ||||||
|  | 	Token token; | ||||||
|  | 	bool need_comma=false; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	while(index<p_len) { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 		if (at_key) { | ||||||
|  | 
 | ||||||
|  | 			Error err = _get_token(p_str,index,p_len,token,line,r_err_str); | ||||||
|  | 			if (err!=OK) | ||||||
|  | 				return err; | ||||||
|  | 
 | ||||||
|  | 			if (token.type==TK_CURLY_BRACKET_CLOSE) { | ||||||
|  | 
 | ||||||
|  | 				return OK; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (need_comma) { | ||||||
|  | 
 | ||||||
|  | 				if (token.type!=TK_COMMA) { | ||||||
|  | 
 | ||||||
|  | 					r_err_str="Expected '}' or ','"; | ||||||
|  | 					return ERR_PARSE_ERROR; | ||||||
|  | 				} else { | ||||||
|  | 					need_comma=false; | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			err = _parse_value(key,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 			if (err!=OK) | ||||||
|  | 				return err; | ||||||
|  | 
 | ||||||
|  | 			err = _get_token(p_str,index,p_len,token,line,r_err_str); | ||||||
|  | 
 | ||||||
|  | 			if (err!=OK) | ||||||
|  | 				return err; | ||||||
|  | 
 | ||||||
|  | 			if (token.type!=TK_COLON) { | ||||||
|  | 
 | ||||||
|  | 				r_err_str="Expected ':'"; | ||||||
|  | 				return ERR_PARSE_ERROR; | ||||||
|  | 			} | ||||||
|  | 			at_key=false; | ||||||
|  | 		} else { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 			Error err = _get_token(p_str,index,p_len,token,line,r_err_str); | ||||||
|  | 			if (err!=OK) | ||||||
|  | 				return err; | ||||||
|  | 
 | ||||||
|  | 			Variant v; | ||||||
|  | 			err = _parse_value(v,token,p_str,index,p_len,line,r_err_str,p_construct,p_ud); | ||||||
|  | 			if (err) | ||||||
|  | 				return err; | ||||||
|  | 			dict[key]=v; | ||||||
|  | 			need_comma=true; | ||||||
|  | 			at_key=true; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Error VariantConstruct::parse(const String& p_string,Variant& r_ret,String &r_err_str,int &r_err_line,Variant::ObjectConstruct* p_construct,void* p_ud) { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	const CharType *str = p_string.ptr(); | ||||||
|  | 	int idx = 0; | ||||||
|  | 	int len = p_string.length(); | ||||||
|  | 	Token token; | ||||||
|  | 	r_err_line=0; | ||||||
|  | 	String aux_key; | ||||||
|  | 
 | ||||||
|  | 	Error err = _get_token(str,idx,len,token,r_err_line,r_err_str); | ||||||
|  | 	if (err) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	return _parse_value(r_ret,token,str,idx,len,r_err_line,r_err_str,p_construct,p_ud); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @ -552,6 +552,9 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant& | ||||||
| 					if (p_b.type==MATRIX32) { | 					if (p_b.type==MATRIX32) { | ||||||
| 						_RETURN( *p_a._data._matrix32 * *p_b._data._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; | 					r_valid=false; | ||||||
| 					return; | 					return; | ||||||
| 				} break; | 				} break; | ||||||
|  | @ -736,6 +739,20 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant& | ||||||
| 				} | 				} | ||||||
| #endif | #endif | ||||||
| 				_RETURN( p_a._data._int % p_b._data._int ); | 				_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; | 			r_valid=false; | ||||||
|  | @ -1687,6 +1704,19 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid) | ||||||
| 					return; | 					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; | 		} break; | ||||||
| 		case DICTIONARY: { | 		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); | 					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; | 		} break; | ||||||
| 		case DICTIONARY: { | 		case DICTIONARY: { | ||||||
|  |  | ||||||
|  | @ -1,33 +0,0 @@ | ||||||
| ::res://::1412302385 |  | ||||||
| WWT-01.png::ImageTexture::1412126473:: |  | ||||||
| WWT-02.png::ImageTexture::1412126474:: |  | ||||||
| WWT-03.png::ImageTexture::1412126474:: |  | ||||||
| WWT-04.png::ImageTexture::1412126474:: |  | ||||||
| WWT-05.png::ImageTexture::1412126474:: |  | ||||||
| WWT-06.png::ImageTexture::1412126474:: |  | ||||||
| WWT-07.png::ImageTexture::1412126474:: |  | ||||||
| WWT-08.png::ImageTexture::1412126474:: |  | ||||||
| WWT-09.png::ImageTexture::1412126474:: |  | ||||||
| WWT-10.png::ImageTexture::1412126474:: |  | ||||||
| WWT-11.png::ImageTexture::1412126475:: |  | ||||||
| WWT-12.png::ImageTexture::1412126475:: |  | ||||||
| WWT-13.png::ImageTexture::1412126475:: |  | ||||||
| WWT-14.png::ImageTexture::1412126475:: |  | ||||||
| WWT-15.png::ImageTexture::1412126475:: |  | ||||||
| WWT-16.png::ImageTexture::1412126475:: |  | ||||||
| WWT-17.png::ImageTexture::1412126475:: |  | ||||||
| WWT-18.png::ImageTexture::1412126475:: |  | ||||||
| WWT-19.png::ImageTexture::1412126476:: |  | ||||||
| WWT-20.png::ImageTexture::1412126476:: |  | ||||||
| WWT-21.png::ImageTexture::1412126476:: |  | ||||||
| WWT-22.png::ImageTexture::1412126476:: |  | ||||||
| WWT-23.png::ImageTexture::1412126476:: |  | ||||||
| WWT-24.png::ImageTexture::1412126476:: |  | ||||||
| WWT-25.png::ImageTexture::1412126476:: |  | ||||||
| WWT-26.png::ImageTexture::1412126476:: |  | ||||||
| map.scn::PackedScene::1412127344:: |  | ||||||
| tiles.scn::PackedScene::1412126994:: |  | ||||||
| tileset.res::TileSet::1412127001:: |  | ||||||
| troll.gd::GDScript::1412302377:: |  | ||||||
| troll.png::ImageTexture::1412302385:: |  | ||||||
| troll.scn::PackedScene::1412302380:: |  | ||||||
							
								
								
									
										
											BIN
										
									
								
								demos/2d/navpoly/agent.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								demos/2d/navpoly/agent.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 2.4 KiB | 
							
								
								
									
										4
									
								
								demos/2d/navpoly/engine.cfg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								demos/2d/navpoly/engine.cfg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | ||||||
|  | [application] | ||||||
|  | 
 | ||||||
|  | name="Navigation Polygon (2D)" | ||||||
|  | main_scene="res://navigation.scn" | ||||||
							
								
								
									
										63
									
								
								demos/2d/navpoly/navigation.gd
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								demos/2d/navpoly/navigation.gd
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | ||||||
|  | 
 | ||||||
|  | extends Navigation2D | ||||||
|  | 
 | ||||||
|  | # member variables here, example: | ||||||
|  | # var a=2 | ||||||
|  | # var b="textvar" | ||||||
|  | var begin=Vector2() | ||||||
|  | var end=Vector2() | ||||||
|  | var path=[] | ||||||
|  | 
 | ||||||
|  | const SPEED=200.0 | ||||||
|  | 
 | ||||||
|  | func _process(delta): | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	if (path.size()>1): | ||||||
|  | 	 | ||||||
|  | 		var to_walk = delta*SPEED | ||||||
|  | 		while(to_walk>0 and path.size()>=2): | ||||||
|  | 			var pfrom = path[path.size()-1] | ||||||
|  | 			var pto = path[path.size()-2] | ||||||
|  | 			var d = pfrom.distance_to(pto) | ||||||
|  | 			if (d<=to_walk): | ||||||
|  | 				path.remove(path.size()-1) | ||||||
|  | 				to_walk-=d | ||||||
|  | 			else: | ||||||
|  | 				path[path.size()-1] = pfrom.linear_interpolate(pto,to_walk/d) | ||||||
|  | 				to_walk=0 | ||||||
|  | 				 | ||||||
|  | 		var atpos = path[path.size()-1]	 | ||||||
|  | 		get_node("agent").set_pos(atpos) | ||||||
|  | 		 | ||||||
|  | 		if (path.size()<2): | ||||||
|  | 			path=[] | ||||||
|  | 			set_process(false) | ||||||
|  | 				 | ||||||
|  | 	else: | ||||||
|  | 		set_process(false) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | func _update_path(): | ||||||
|  | 
 | ||||||
|  | 	var p = get_simple_path(begin,end,true) | ||||||
|  | 	path=Array(p) # Vector2array to complex to use, convert to regular array | ||||||
|  | 	path.invert() | ||||||
|  | 	 | ||||||
|  | 	set_process(true) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | func _input(ev): | ||||||
|  | 	if (ev.type==InputEvent.MOUSE_BUTTON and ev.pressed and ev.button_index==1): | ||||||
|  | 		begin=get_node("agent").get_pos() | ||||||
|  | 		#mouse to local navigatio cooards | ||||||
|  | 		end=ev.pos - get_pos() | ||||||
|  | 		_update_path() | ||||||
|  | 
 | ||||||
|  | func _ready(): | ||||||
|  | 	# Initialization here | ||||||
|  | 	set_process_input(true) | ||||||
|  | 	pass | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
							
								
								
									
										
											BIN
										
									
								
								demos/2d/navpoly/navigation.scn
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								demos/2d/navpoly/navigation.scn
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								demos/2d/navpoly/navigation2.scn
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								demos/2d/navpoly/navigation2.scn
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								demos/2d/navpoly/path.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								demos/2d/navpoly/path.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 302 KiB | 
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.8 KiB | 
|  | @ -1,134 +1,191 @@ | ||||||
| <?xml version="1.0" encoding="UTF-8" ?> | <?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> | 	<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"> | 	<resource type="ConvexPolygonShape2D" path="local://1"> | ||||||
| 		<string name="resource/name"> "" </string> |  | ||||||
| 		<real name="custom_solver_bias"> 0 </real> | 		<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, -24, 32, -24, 32, 32, -32, 32 </vector2_array> | ||||||
| 		<resource name="script/script"></resource> | 
 | ||||||
| 	</resource> | 	</resource> | ||||||
| 	<resource type="ConvexPolygonShape2D" path="local://2"> | 	<resource type="ConvexPolygonShape2D" path="local://2"> | ||||||
| 		<string name="resource/name"> "" </string> |  | ||||||
| 		<real name="custom_solver_bias"> 0 </real> | 		<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, -24, 24, -24, 24, 32 </vector2_array> | ||||||
| 		<resource name="script/script"></resource> | 
 | ||||||
| 	</resource> | 	</resource> | ||||||
| 	<resource type="ConvexPolygonShape2D" path="local://3"> | 	<resource type="ConvexPolygonShape2D" path="local://3"> | ||||||
| 		<string name="resource/name"> "" </string> |  | ||||||
| 		<real name="custom_solver_bias"> 0 </real> | 		<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 name="script/script"></resource> | 
 | ||||||
| 	</resource> | 	</resource> | ||||||
| 	<resource type="ConvexPolygonShape2D" path="local://4"> | 	<resource type="ConvexPolygonShape2D" path="local://4"> | ||||||
| 		<string name="resource/name"> "" </string> |  | ||||||
| 		<real name="custom_solver_bias"> 0 </real> | 		<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="4"> 			-64, 32, -64, -32, -8, -32, -8, 32 </vector2_array> | ||||||
| 		<resource name="script/script"></resource> | 
 | ||||||
| 	</resource> | 	</resource> | ||||||
| 	<resource type="ConvexPolygonShape2D" path="local://5"> | 	<resource type="ConvexPolygonShape2D" path="local://5"> | ||||||
| 		<string name="resource/name"> "" </string> |  | ||||||
| 		<real name="custom_solver_bias"> 0 </real> | 		<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="5"> 			-32, 32, -32, -32, 24, -32, 32, -24, 32, 32 </vector2_array> | ||||||
| 		<resource name="script/script"></resource> | 
 | ||||||
| 	</resource> | 	</resource> | ||||||
| 	<resource type="ConvexPolygonShape2D" path="local://6"> | 	<resource type="ConvexPolygonShape2D" path="local://6"> | ||||||
| 		<string name="resource/name"> "" </string> |  | ||||||
| 		<real name="custom_solver_bias"> 0 </real> | 		<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 name="script/script"></resource> | 
 | ||||||
| 	</resource> | 	</resource> | ||||||
| 	<resource type="ConvexPolygonShape2D" path="local://7"> | 	<resource type="ConvexPolygonShape2D" path="local://7"> | ||||||
| 		<string name="resource/name"> "" </string> |  | ||||||
| 		<real name="custom_solver_bias"> 0 </real> | 		<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, 32, -32, -24, 32, -24, 32, 32 </vector2_array> | ||||||
| 		<resource name="script/script"></resource> | 
 | ||||||
| 	</resource> | 	</resource> | ||||||
| 	<resource type="ConvexPolygonShape2D" path="local://8"> | 	<resource type="ConvexPolygonShape2D" path="local://8"> | ||||||
| 		<string name="resource/name"> "" </string> |  | ||||||
| 		<real name="custom_solver_bias"> 0 </real> | 		<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, -32, 32, 32, -32, 32 </vector2_array> | ||||||
| 		<resource name="script/script"></resource> | 
 | ||||||
| 	</resource> | 	</resource> | ||||||
| 	<resource type="ConvexPolygonShape2D" path="local://9"> | 	<resource type="ConvexPolygonShape2D" path="local://9"> | ||||||
| 		<string name="resource/name"> "" </string> |  | ||||||
| 		<real name="custom_solver_bias"> 0 </real> | 		<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, -56, 32, 8, 32, 64, -32, 64 </vector2_array> | ||||||
| 		<resource name="script/script"></resource> | 
 | ||||||
|  | 	</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> | 	</resource> | ||||||
| 	<main_resource> | 	<main_resource> | ||||||
| 		<string name="resource/name"> "" </string> |  | ||||||
| 		<string name="0/name"> "floor" </string> | 		<string name="0/name"> "floor" </string> | ||||||
| 		<resource name="0/texture" resource_type="Texture" path="res://tiles_demo.png">  </resource> | 		<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> | 		<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> | 		<string name="1/name"> "edge" </string> | ||||||
| 		<resource name="1/texture" resource_type="Texture" path="res://tiles_demo.png">  </resource> | 		<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> | 		<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> | 		<string name="2/name"> "wall" </string> | ||||||
| 		<resource name="2/texture" resource_type="Texture" path="res://tiles_demo.png">  </resource> | 		<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> | 		<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> | 		<string name="3/name"> "wall_deco" </string> | ||||||
| 		<resource name="3/texture" resource_type="Texture" path="res://tiles_demo.png">  </resource> | 		<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> | 		<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> | 		<string name="4/name"> "corner" </string> | ||||||
| 		<resource name="4/texture" resource_type="Texture" path="res://tiles_demo.png">  </resource> | 		<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> | 		<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> | 		<string name="5/name"> "flowers" </string> | ||||||
| 		<resource name="5/texture" resource_type="Texture" path="res://tiles_demo.png">  </resource> | 		<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> | 		<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> | 		<string name="6/name"> "tree_base" </string> | ||||||
| 		<resource name="6/texture" resource_type="Texture" path="res://tiles_demo.png">  </resource> | 		<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> | 		<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> | 		<string name="7/name"> "tree_mid" </string> | ||||||
| 		<resource name="7/texture" resource_type="Texture" path="res://tiles_demo.png">  </resource> | 		<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> | 		<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> | 		<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> | 		<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> | 		<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> | 		<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> | 		<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> | 		<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> | 		<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> | 		<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> | 		<string name="12/name"> "ramp" </string> | ||||||
| 		<resource name="12/texture" resource_type="Texture" path="res://tiles_demo.png">  </resource> | 		<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> | 		<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> | 		<string name="13/name"> "ceiling2wall" </string> | ||||||
| 		<resource name="13/texture" resource_type="Texture" path="res://tiles_demo.png">  </resource> | 		<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> | 		<rect2 name="13/region"> 448, 64, 64, 64 </rect2> | ||||||
| 		<resource name="13/shape" resource_type="ConvexPolygonShape2D" path="local://9">  </resource> | 		<array name="13/shapes" len="1" shared="false"> | ||||||
| 		<resource name="script/script"></resource> | 			<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> | 	</main_resource> | ||||||
| </resource_file> | </resource_file> | ||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -1,4 +0,0 @@ | ||||||
| ::res://::1421147952 |  | ||||||
| icon.png::ImageTexture::1420046079:: |  | ||||||
| new_scene_poly_with_holes.scn::PackedScene::1421147952:: |  | ||||||
| polygonpathfinder.gd::GDScript::1421146502:: |  | ||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -10,7 +10,6 @@ SConscript('alsa/SCsub'); | ||||||
| SConscript('pulseaudio/SCsub'); | SConscript('pulseaudio/SCsub'); | ||||||
| SConscript('windows/SCsub'); | SConscript('windows/SCsub'); | ||||||
| SConscript('gles2/SCsub'); | SConscript('gles2/SCsub'); | ||||||
| SConscript('gles1/SCsub'); |  | ||||||
| SConscript('gl_context/SCsub'); | SConscript('gl_context/SCsub'); | ||||||
| SConscript('openssl/SCsub'); | SConscript('openssl/SCsub'); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -51,6 +51,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "drivers/gles2/shaders/material.glsl.h" | #include "drivers/gles2/shaders/material.glsl.h" | ||||||
| #include "drivers/gles2/shaders/canvas.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/blur.glsl.h" | ||||||
| #include "drivers/gles2/shaders/copy.glsl.h" | #include "drivers/gles2/shaders/copy.glsl.h" | ||||||
| #include "drivers/gles2/shader_compiler_gles2.h" | #include "drivers/gles2/shader_compiler_gles2.h" | ||||||
|  | @ -65,7 +66,7 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 
 | 
 | ||||||
| 		MAX_SCENE_LIGHTS=2048, | 		MAX_SCENE_LIGHTS=2048, | ||||||
| 		LIGHT_SPOT_BIT=0x80, | 		LIGHT_SPOT_BIT=0x80, | ||||||
| 		DEFAULT_SKINNED_BUFFER_SIZE = 2048 * 1024, // 10k vertices
 | 		DEFAULT_SKINNED_BUFFER_SIZE = 2048, // 10k vertices
 | ||||||
| 		MAX_HW_LIGHTS = 1, | 		MAX_HW_LIGHTS = 1, | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  | @ -816,6 +817,7 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 	bool current_depth_mask; | 	bool current_depth_mask; | ||||||
| 	VS::MaterialBlendMode current_blend_mode; | 	VS::MaterialBlendMode current_blend_mode; | ||||||
| 	bool use_fast_texture_filter; | 	bool use_fast_texture_filter; | ||||||
|  | 	int max_texture_size; | ||||||
| 
 | 
 | ||||||
| 	bool fragment_lighting; | 	bool fragment_lighting; | ||||||
| 	RID shadow_material; | 	RID shadow_material; | ||||||
|  | @ -827,15 +829,18 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 	GLuint gui_quad_buffer; | 	GLuint gui_quad_buffer; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	struct RenderList { | 	struct RenderList { | ||||||
| 
 | 
 | ||||||
| 		enum { | 		enum { | ||||||
| 			MAX_ELEMENTS=4096, | 			DEFAULT_MAX_ELEMENTS=4096, | ||||||
| 			MAX_LIGHTS=4, | 			MAX_LIGHTS=4, | ||||||
| 			SORT_FLAG_SKELETON=1, | 			SORT_FLAG_SKELETON=1, | ||||||
| 			SORT_FLAG_INSTANCING=2, | 			SORT_FLAG_INSTANCING=2, | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
|  | 		static int max_elements; | ||||||
|  | 
 | ||||||
| 		struct Element { | 		struct Element { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -868,8 +873,8 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 		Element _elements[MAX_ELEMENTS]; | 		Element *_elements; | ||||||
| 		Element *elements[MAX_ELEMENTS]; | 		Element **elements; | ||||||
| 		int element_count; | 		int element_count; | ||||||
| 
 | 
 | ||||||
| 		void clear() { | 		void clear() { | ||||||
|  | @ -1004,17 +1009,28 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 		} | 		} | ||||||
| 		_FORCE_INLINE_ Element* add_element() { | 		_FORCE_INLINE_ Element* add_element() { | ||||||
| 
 | 
 | ||||||
| 			if (element_count>MAX_ELEMENTS) | 			if (element_count>=max_elements) | ||||||
| 				return NULL; | 				return NULL; | ||||||
| 			elements[element_count]=&_elements[element_count]; | 			elements[element_count]=&_elements[element_count]; | ||||||
| 			return elements[element_count++]; | 			return elements[element_count++]; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		RenderList() { | 		void init() { | ||||||
| 
 | 
 | ||||||
| 			element_count = 0; | 			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
 | 				elements[i]=&_elements[i]; // assign elements
 | ||||||
|  | 
 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		RenderList() { | ||||||
|  | 
 | ||||||
|  | 		} | ||||||
|  | 		~RenderList() { | ||||||
|  | 			memdelete_arr(elements); | ||||||
|  | 			memdelete_arr(_elements); | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  | @ -1113,6 +1129,7 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 		bool active; | 		bool active; | ||||||
| 
 | 
 | ||||||
| 		int blur_size; | 		int blur_size; | ||||||
|  | 
 | ||||||
| 		struct Blur { | 		struct Blur { | ||||||
| 
 | 
 | ||||||
| 			GLuint fbo; | 			GLuint fbo; | ||||||
|  | @ -1145,6 +1162,7 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 	void _process_glow_and_bloom(); | 	void _process_glow_and_bloom(); | ||||||
| 	//void _update_blur_buffer();
 | 	//void _update_blur_buffer();
 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	/*********/ | 	/*********/ | ||||||
| 	/* FRAME */ | 	/* FRAME */ | ||||||
| 	/*********/ | 	/*********/ | ||||||
|  | @ -1163,6 +1181,45 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 	} _rinfo; | 	} _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; | 	RenderTarget *current_rt; | ||||||
| 	bool current_rt_transparent; | 	bool current_rt_transparent; | ||||||
| 	bool current_rt_vflip; | 	bool current_rt_vflip; | ||||||
|  | @ -1172,11 +1229,15 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 	GLuint white_tex; | 	GLuint white_tex; | ||||||
| 	RID canvas_tex; | 	RID canvas_tex; | ||||||
| 	float canvas_opacity; | 	float canvas_opacity; | ||||||
|  | 	Color canvas_modulate; | ||||||
|  | 	bool canvas_use_modulate; | ||||||
| 	bool uses_texpixel_size; | 	bool uses_texpixel_size; | ||||||
| 	bool rebind_texpixel_size; | 	bool rebind_texpixel_size; | ||||||
| 	Transform canvas_transform; | 	Transform canvas_transform; | ||||||
| 	RID canvas_last_shader; | 	CanvasItemMaterial *canvas_last_material; | ||||||
| 	bool canvas_texscreen_used; | 	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); | 	_FORCE_INLINE_ Texture* _bind_canvas_texture(const RID& p_texture); | ||||||
|  | @ -1208,17 +1269,19 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 	VS::ScenarioDebugMode current_debug; | 	VS::ScenarioDebugMode current_debug; | ||||||
| 	RID overdraw_material; | 	RID overdraw_material; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	mutable MaterialShaderGLES2 material_shader; | 	mutable MaterialShaderGLES2 material_shader; | ||||||
| 	mutable CanvasShaderGLES2 canvas_shader; | 	mutable CanvasShaderGLES2 canvas_shader; | ||||||
| 	BlurShaderGLES2 blur_shader; | 	BlurShaderGLES2 blur_shader; | ||||||
| 	CopyShaderGLES2 copy_shader; | 	CopyShaderGLES2 copy_shader; | ||||||
|  | 	mutable CanvasShadowShaderGLES2 canvas_shadow_shader; | ||||||
| 
 | 
 | ||||||
| 	mutable ShaderCompilerGLES2 shader_precompiler; | 	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); | 	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_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); | 	_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 _draw_quad(const Rect2& p_rect); | ||||||
| 	void _copy_screen_quad(); | 	void _copy_screen_quad(); | ||||||
| 	void _copy_to_texscreen(); | 	void _copy_to_texscreen(); | ||||||
|  | @ -1233,6 +1296,10 @@ class RasterizerGLES2 : public Rasterizer { | ||||||
| 	GLuint tc0_id_cache; | 	GLuint tc0_id_cache; | ||||||
| 	GLuint tc0_idx; | 	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: | public: | ||||||
| 
 | 
 | ||||||
| 	/* TEXTURE API */ | 	/* 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_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_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 */ | 	/* ENVIRONMENT */ | ||||||
| 
 | 
 | ||||||
|  | @ -1587,6 +1665,8 @@ public: | ||||||
| 	virtual bool is_environment(const RID& p_rid) const; | 	virtual bool is_environment(const RID& p_rid) const; | ||||||
| 	virtual bool is_shader(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 free(const RID& p_rid); | ||||||
| 
 | 
 | ||||||
| 	virtual void init(); | 	virtual void init(); | ||||||
|  |  | ||||||
|  | @ -226,6 +226,9 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a | ||||||
| 				if (vnode->name==vname_var2_interp) { | 				if (vnode->name==vname_var2_interp) { | ||||||
| 					flags->use_var2_interp=true; | 					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; | 					uses_light=true; | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | 				if (vnode->name==vname_normal) { | ||||||
|  | 					uses_normal=true; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (vnode->name==vname_time) { | 			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_l=dump_node_code(onode->arguments[0],p_level,true); | ||||||
| 						String mul_r=dump_node_code(onode->arguments[1],p_level); | 						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; | 						break; | ||||||
| 					} else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT4 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) { | 					} 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_l=dump_node_code(onode->arguments[0],p_level,true); | ||||||
| 						String mul_r=dump_node_code(onode->arguments[1],p_level); | 						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; | 						break; | ||||||
| 					} else if (onode->arguments[0]->get_datatype()==SL::TYPE_VEC2 && onode->arguments[1]->get_datatype()==SL::TYPE_MAT3) { | 					} 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); | 						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; | 						break; | ||||||
| 					} else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT4 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) { | 					} 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; | 						break; | ||||||
| 					} else if (onode->arguments[0]->get_datatype()==SL::TYPE_VEC2 && onode->arguments[1]->get_datatype()==SL::TYPE_MAT4) { | 					} 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; | 						break; | ||||||
| 					} else if (onode->arguments[0]->get_datatype()==SL::TYPE_MAT3 && onode->arguments[1]->get_datatype()==SL::TYPE_VEC2) { | 					} 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_normalmap=false; | ||||||
| 	uses_normal=false; | 	uses_normal=false; | ||||||
| 	uses_texpixel_size=false; | 	uses_texpixel_size=false; | ||||||
|  | 	uses_worldvec=false; | ||||||
| 	vertex_code_writes_vertex=false; | 	vertex_code_writes_vertex=false; | ||||||
| 	uniforms=r_uniforms; | 	uniforms=r_uniforms; | ||||||
| 	flags=&r_flags; | 	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_light=uses_light; | ||||||
| 	r_flags.uses_time=uses_time; | 	r_flags.uses_time=uses_time; | ||||||
| 	r_flags.uses_normalmap=uses_normalmap; | 	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_texpixel_size=uses_texpixel_size; | ||||||
|  | 	r_flags.uses_worldvec=uses_worldvec; | ||||||
| 	r_code_line=code; | 	r_code_line=code; | ||||||
| 	r_globals_line=global_code; | 	r_globals_line=global_code; | ||||||
| 
 | 
 | ||||||
|  | @ -774,6 +784,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { | ||||||
| 
 | 
 | ||||||
| 	mode_replace_table[3]["SRC_VERTEX"]="src_vtx"; | 	mode_replace_table[3]["SRC_VERTEX"]="src_vtx"; | ||||||
| 	mode_replace_table[3]["VERTEX"]="outvec.xy"; | 	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]["UV"]="uv_interp"; | ||||||
| 	mode_replace_table[3]["COLOR"]="color_interp"; | 	mode_replace_table[3]["COLOR"]="color_interp"; | ||||||
| 	mode_replace_table[3]["VAR1"]="var1_interp"; | 	mode_replace_table[3]["VAR1"]="var1_interp"; | ||||||
|  | @ -830,5 +841,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { | ||||||
| 	vname_normalmap="NORMALMAP"; | 	vname_normalmap="NORMALMAP"; | ||||||
| 	vname_normal="NORMAL"; | 	vname_normal="NORMAL"; | ||||||
| 	vname_texpixel_size="TEXTURE_PIXEL_SIZE"; | 	vname_texpixel_size="TEXTURE_PIXEL_SIZE"; | ||||||
|  | 	vname_world_vec="WORLD_VERTEX"; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -53,6 +53,7 @@ private: | ||||||
| 	bool uses_normalmap; | 	bool uses_normalmap; | ||||||
| 	bool uses_normal; | 	bool uses_normal; | ||||||
| 	bool uses_texpixel_size; | 	bool uses_texpixel_size; | ||||||
|  | 	bool uses_worldvec; | ||||||
| 	bool vertex_code_writes_vertex; | 	bool vertex_code_writes_vertex; | ||||||
| 	Flags *flags; | 	Flags *flags; | ||||||
| 
 | 
 | ||||||
|  | @ -72,6 +73,7 @@ private: | ||||||
| 	StringName vname_normalmap; | 	StringName vname_normalmap; | ||||||
| 	StringName vname_normal; | 	StringName vname_normal; | ||||||
| 	StringName vname_texpixel_size; | 	StringName vname_texpixel_size; | ||||||
|  | 	StringName vname_world_vec; | ||||||
| 
 | 
 | ||||||
| 	Map<StringName,ShaderLanguage::Uniform> *uniforms; | 	Map<StringName,ShaderLanguage::Uniform> *uniforms; | ||||||
| 
 | 
 | ||||||
|  | @ -107,6 +109,7 @@ public: | ||||||
| 		bool uses_time; | 		bool uses_time; | ||||||
| 		bool uses_normal; | 		bool uses_normal; | ||||||
| 		bool uses_texpixel_size; | 		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); | 	Error compile(const String& p_code, ShaderLanguage::ShaderType p_type, String& r_code_line, String& r_globals_line, Flags& r_flags, Map<StringName,ShaderLanguage::Uniform> *r_uniforms=NULL); | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ Import('env') | ||||||
| if env['BUILDERS'].has_key('GLSL120GLES'): | if env['BUILDERS'].has_key('GLSL120GLES'): | ||||||
| 	env.GLSL120GLES('material.glsl'); | 	env.GLSL120GLES('material.glsl'); | ||||||
| 	env.GLSL120GLES('canvas.glsl'); | 	env.GLSL120GLES('canvas.glsl'); | ||||||
|  | 	env.GLSL120GLES('canvas_shadow.glsl'); | ||||||
| 	env.GLSL120GLES('blur.glsl'); | 	env.GLSL120GLES('blur.glsl'); | ||||||
| 	env.GLSL120GLES('copy.glsl'); | 	env.GLSL120GLES('copy.glsl'); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,7 +26,17 @@ uniform float time; | ||||||
| #ifdef USE_LIGHTING | #ifdef USE_LIGHTING | ||||||
| 
 | 
 | ||||||
| uniform highp mat4 light_matrix; | 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 | #endif | ||||||
| 
 | 
 | ||||||
|  | @ -46,29 +56,42 @@ void main() { | ||||||
| 
 | 
 | ||||||
| 	color_interp = color_attrib; | 	color_interp = color_attrib; | ||||||
| 	uv_interp = uv_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 | VERTEX_SHADER_CODE | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 	outvec = extra_matrix * outvec; | #if !defined(USE_WORLD_VEC) | ||||||
| 	outvec = modelview_matrix * outvec; |         outvec = extra_matrix * outvec; | ||||||
|  |         outvec = modelview_matrix * outvec; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| #ifdef USE_PIXEL_SNAP | #ifdef USE_PIXEL_SNAP | ||||||
| 
 | 
 | ||||||
| 	outvec.xy=floor(outvec.xy+0.5); | 	outvec.xy=floor(outvec.xy+0.5); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 	gl_Position = projection_matrix * outvec; | ||||||
|  | 
 | ||||||
| #ifdef USE_LIGHTING | #ifdef USE_LIGHTING | ||||||
| 
 | 
 | ||||||
| 	light_tex_pos.xy = light_matrix * outvec; | 	light_uv_interp.xy = (light_matrix * outvec).xy; | ||||||
| 	light_tex_pos.zw=outvec.xy - light_matrix[4].xy; //likely wrong | 	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 | #endif | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	gl_Position = projection_matrix * outvec; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [fragment] | [fragment] | ||||||
|  | @ -118,17 +141,37 @@ varying vec4 var2_interp; | ||||||
| uniform float time; | uniform float time; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef USE_MODULATE | ||||||
|  | 
 | ||||||
|  | uniform vec4 modulate; | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef USE_LIGHTING | #ifdef USE_LIGHTING | ||||||
| 
 | 
 | ||||||
| uniform sampler2D light_texture; | 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 | #ifdef USE_SHADOWS | ||||||
| 
 | 
 | ||||||
| uniform sampler2D shadow_texture; | uniform sampler2D shadow_texture; | ||||||
| uniform float shadow_attenuation; | 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 | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | @ -148,6 +191,7 @@ void main() { | ||||||
| 	vec3 normal = vec3(0,0,1); | 	vec3 normal = vec3(0,0,1); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	color *= texture2D( texture,  uv_interp ); | 	color *= texture2D( texture,  uv_interp ); | ||||||
| #if defined(ENABLE_SCREEN_UV) | #if defined(ENABLE_SCREEN_UV) | ||||||
| 	vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult; | 	vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult; | ||||||
|  | @ -161,37 +205,141 @@ FRAGMENT_SHADER_CODE | ||||||
| 	color = vec4(vec3(enc32),1.0); | 	color = vec4(vec3(enc32),1.0); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef USE_MODULATE | ||||||
|  | 
 | ||||||
|  | 	color*=modulate; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| #ifdef USE_LIGHTING | #ifdef USE_LIGHTING | ||||||
| 
 | 
 | ||||||
|  | #if defined(NORMAL_USED) | ||||||
|  | 	normal.xy =  mat2(local_rot.xy,local_rot.zw) * normal.xy; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	float att=1.0; | 	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 | #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; | 	vec2 lpos = (light_local_matrix * vec4(pos,0.0,1.0)).xy; | ||||||
| 	float shadow_dist = texture2D(shadow_texture,vec2(light_angle,0)); | 	float angle_to_light = -atan(lpos.x,lpos.y); | ||||||
| 	if (light_dist>shadow_dist) { | 	float PI = 3.14159265358979323846264; | ||||||
| 		light*=shadow_attenuation; | 	/*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 | //use shadows | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #if defined(USE_LIGHT_SHADER_CODE) | #if defined(USE_LIGHT_SHADER_CODE) | ||||||
| //light is written by the light shader | //light is written by the light shader | ||||||
| { | { | ||||||
| 	vec2 light_dir = normalize(light_tex_pos.zw); | 	vec2 light_dir = normalize(light_uv_interp.zw); | ||||||
| 	float light_distance = length(light_tex_pos.zw); | 	float light_distance = length(light_uv_interp.zw); | ||||||
| LIGHT_SHADER_CODE | LIGHT_SHADER_CODE | ||||||
| } | } | ||||||
|  | 
 | ||||||
| #else | #else | ||||||
| 
 | 
 | ||||||
| #if defined(NORMAL_USED) | #if defined(NORMAL_USED) | ||||||
| 	vec2 light_normal = normalize(light_tex_pos.zw); | 	vec3 light_normal = normalize(vec3(light_uv_interp.zw,-light_height)); | ||||||
| 	light = color.rgb * light * max(dot(light_normal,normal),0); | 	light*=max(dot(-light_normal,normal),0); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	color.rgb=light; | 	color*=light; | ||||||
|  | /* | ||||||
|  | #ifdef USE_NORMAL | ||||||
|  | 	color.xy=local_rot.xy;//normal.xy; | ||||||
|  | 	color.zw=vec2(0.0,1.0); | ||||||
|  | #endif | ||||||
|  | */ | ||||||
|  | 	if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) { | ||||||
|  | 		color.a=0.0; //invisible | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| //light shader code | //light shader code | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										62
									
								
								drivers/gles2/shaders/canvas_shadow.glsl
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								drivers/gles2/shaders/canvas_shadow.glsl
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | ||||||
|  | [vertex] | ||||||
|  | 
 | ||||||
|  | #ifdef USE_GLES_OVER_GL | ||||||
|  | #define mediump | ||||||
|  | #define highp | ||||||
|  | #else | ||||||
|  | precision mediump float; | ||||||
|  | precision mediump int; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | uniform highp mat4 projection_matrix; | ||||||
|  | uniform highp mat4 light_matrix; | ||||||
|  | uniform highp mat4 world_matrix; | ||||||
|  | 
 | ||||||
|  | attribute highp vec3 vertex; // attrib:0 | ||||||
|  | 
 | ||||||
|  | #ifndef USE_DEPTH_SHADOWS | ||||||
|  | 
 | ||||||
|  | varying vec4 position_interp; | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void main() { | ||||||
|  | 
 | ||||||
|  | 	gl_Position = projection_matrix * (light_matrix * (world_matrix *  vec4(vertex,1.0))); | ||||||
|  | 
 | ||||||
|  | #ifndef USE_DEPTH_SHADOWS | ||||||
|  | 	position_interp = gl_Position; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | [fragment] | ||||||
|  | 
 | ||||||
|  | #ifdef USE_GLES_OVER_GL | ||||||
|  | #define mediump | ||||||
|  | #define highp | ||||||
|  | #else | ||||||
|  | precision mediump float; | ||||||
|  | precision mediump int; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef USE_DEPTH_SHADOWS | ||||||
|  | 
 | ||||||
|  | varying vec4 position_interp; | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | void main() { | ||||||
|  | 
 | ||||||
|  | #ifdef USE_DEPTH_SHADOWS | ||||||
|  | 
 | ||||||
|  | #else | ||||||
|  | 	highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias; | ||||||
|  | 	highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); | ||||||
|  | 	comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); | ||||||
|  | 	gl_FragColor = comp; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @ -50,11 +50,16 @@ | ||||||
|  #ifdef ANDROID_ENABLED |  #ifdef ANDROID_ENABLED | ||||||
|   #include "platform/android/ifaddrs_android.h" |   #include "platform/android/ifaddrs_android.h" | ||||||
|  #else |  #else | ||||||
|  |   #ifdef __FreeBSD__ | ||||||
|  |    #include <sys/types.h> | ||||||
|  |   #endif | ||||||
|   #include <ifaddrs.h> |   #include <ifaddrs.h> | ||||||
|  #endif |  #endif | ||||||
|  #include <arpa/inet.h> |  #include <arpa/inet.h> | ||||||
|  #include <sys/socket.h> |  #include <sys/socket.h> | ||||||
| 
 |  #ifdef __FreeBSD__ | ||||||
|  |   #include <netinet/in.h> | ||||||
|  |  #endif | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) { | IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) { | ||||||
|  |  | ||||||
|  | @ -44,7 +44,9 @@ | ||||||
| #include "stream_peer_tcp_posix.h" | #include "stream_peer_tcp_posix.h" | ||||||
| #include "packet_peer_udp_posix.h" | #include "packet_peer_udp_posix.h" | ||||||
| 
 | 
 | ||||||
| 
 | #ifdef __FreeBSD__ | ||||||
|  | #include <sys/param.h> | ||||||
|  | #endif | ||||||
| #include <stdarg.h> | #include <stdarg.h> | ||||||
| #include <sys/time.h> | #include <sys/time.h> | ||||||
| #include <sys/wait.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((char*)cs[i].get_data());// shitty C cast
 | ||||||
| 		args.push_back(0); | 		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]); | 		execv(p_path.utf8().get_data(),&args[0]); | ||||||
|  | #endif | ||||||
| 		// still alive? something failed..
 | 		// still alive? something failed..
 | ||||||
| 		fprintf(stderr,"**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n",p_path.utf8().get_data()); | 		fprintf(stderr,"**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n",p_path.utf8().get_data()); | ||||||
| 		abort(); | 		abort(); | ||||||
|  | @ -421,6 +433,12 @@ String OS_Unix::get_executable_path() const { | ||||||
| 		return OS::get_executable_path(); | 		return OS::get_executable_path(); | ||||||
| 	} | 	} | ||||||
| 	return b; | 	return b; | ||||||
|  | #elif defined(__FreeBSD__) | ||||||
|  | 	char resolved_path[MAXPATHLEN]; | ||||||
|  | 
 | ||||||
|  | 	realpath(OS::get_executable_path().utf8().get_data(), resolved_path); | ||||||
|  | 
 | ||||||
|  | 	return String(resolved_path); | ||||||
| #else | #else | ||||||
| 	ERR_PRINT("Warning, don't know how to obtain executable path on this OS! Please override this function properly."); | 	ERR_PRINT("Warning, don't know how to obtain executable path on this OS! Please override this function properly."); | ||||||
| 	return OS::get_executable_path(); | 	return OS::get_executable_path(); | ||||||
|  |  | ||||||
|  | @ -28,14 +28,18 @@ | ||||||
| /*************************************************************************/ | /*************************************************************************/ | ||||||
| #ifdef WINDOWS_ENABLED | #ifdef WINDOWS_ENABLED | ||||||
| 
 | 
 | ||||||
|  | #include <Windows.h> | ||||||
|  | #include "Shlwapi.h" | ||||||
| #include "file_access_windows.h" | #include "file_access_windows.h" | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <wchar.h> | #include <wchar.h> | ||||||
| #include <tchar.h> | #include <tchar.h> | ||||||
| #include "print_string.h" | #include "print_string.h" | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| #ifdef _MSC_VER | #ifdef _MSC_VER | ||||||
|  #define S_ISREG(m) ((m)&_S_IFREG) |  #define S_ISREG(m) ((m)&_S_IFREG) | ||||||
| #endif | #endif | ||||||
|  | @ -111,10 +115,20 @@ void FileAccessWindows::close() { | ||||||
| 
 | 
 | ||||||
| 		//unlink(save_path.utf8().get_data());
 | 		//unlink(save_path.utf8().get_data());
 | ||||||
| 		//print_line("renaming..");
 | 		//print_line("renaming..");
 | ||||||
| 		_wunlink(save_path.c_str()); //unlink if exists
 | 		//_wunlink(save_path.c_str()); //unlink if exists
 | ||||||
| 		int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str()); | 		//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=""; | 		save_path=""; | ||||||
| 		ERR_FAIL_COND( rename_error != 0); | 		ERR_FAIL_COND( rename_error ); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ String GDScriptLanguage::get_template(const String& p_class_name, const String& | ||||||
| 	"# var a=2\n"+ | 	"# var a=2\n"+ | ||||||
| 	"# var b=\"textvar\"\n\n"+ | 	"# var b=\"textvar\"\n\n"+ | ||||||
| 	"func _ready():\n"+ | 	"func _ready():\n"+ | ||||||
| 	"\t# Initalization here\n"+ | 	"\t# Initialization here\n"+ | ||||||
| 	"\tpass\n"+ | 	"\tpass\n"+ | ||||||
| 	"\n"+ | 	"\n"+ | ||||||
| 	"\n"; | 	"\n"; | ||||||
|  |  | ||||||
|  | @ -89,6 +89,8 @@ const char *GDFunctions::get_func_name(Function p_func) { | ||||||
| 		"printt", | 		"printt", | ||||||
| 		"printerr", | 		"printerr", | ||||||
| 		"printraw", | 		"printraw", | ||||||
|  | 		"var2str", | ||||||
|  | 		"str2var", | ||||||
| 		"range", | 		"range", | ||||||
| 		"load", | 		"load", | ||||||
| 		"inst2dict", | 		"inst2dict", | ||||||
|  | @ -577,10 +579,23 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va | ||||||
| 			r_ret=Variant(); | 			r_ret=Variant(); | ||||||
| 
 | 
 | ||||||
| 		} break; | 		} 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: { | 		case GEN_RANGE: { | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 			switch(p_arg_count) { | 			switch(p_arg_count) { | ||||||
| 
 | 
 | ||||||
| 				case 0: { | 				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); | 			r_ret = gdscr->_new(NULL,0,r_error); | ||||||
| 
 | 
 | ||||||
| 		} break; | 		} break; | ||||||
|  | @ -1224,6 +1238,18 @@ MethodInfo GDFunctions::get_info(Function p_func) { | ||||||
| 			return mi; | 			return mi; | ||||||
| 
 | 
 | ||||||
| 		} break; | 		} 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: { | 		case GEN_RANGE: { | ||||||
| 
 | 
 | ||||||
| 			MethodInfo mi("range",PropertyInfo(Variant::NIL,"...")); | 			MethodInfo mi("range",PropertyInfo(Variant::NIL,"...")); | ||||||
|  |  | ||||||
|  | @ -85,6 +85,8 @@ public: | ||||||
| 		TEXT_PRINT_TABBED, | 		TEXT_PRINT_TABBED, | ||||||
| 		TEXT_PRINTERR, | 		TEXT_PRINTERR, | ||||||
| 		TEXT_PRINTRAW, | 		TEXT_PRINTRAW, | ||||||
|  | 		VAR_TO_STR, | ||||||
|  | 		STR_TO_VAR, | ||||||
| 		GEN_RANGE, | 		GEN_RANGE, | ||||||
| 		RESOURCE_LOAD, | 		RESOURCE_LOAD, | ||||||
| 		INST2DICT, | 		INST2DICT, | ||||||
|  |  | ||||||
|  | @ -2696,7 +2696,10 @@ Error ResourceFormatSaverGDScript::save(const String &p_path,const RES& p_resour | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	file->store_string(source); | 	file->store_string(source); | ||||||
| 
 | 	if (file->get_error()!=OK && file->get_error()!=ERR_FILE_EOF) { | ||||||
|  | 		memdelete(file); | ||||||
|  | 		return ERR_CANT_CREATE; | ||||||
|  | 	} | ||||||
| 	file->close(); | 	file->close(); | ||||||
| 	memdelete(file); | 	memdelete(file); | ||||||
| 	return OK; | 	return OK; | ||||||
|  |  | ||||||
|  | @ -543,6 +543,7 @@ void GDTokenizerText::_advance() { | ||||||
| 				if (GETCHAR(0)=='\'') | 				if (GETCHAR(0)=='\'') | ||||||
| 					string_mode=STRING_SINGLE_QUOTE; | 					string_mode=STRING_SINGLE_QUOTE; | ||||||
| 																	 | 																	 | ||||||
|  | 																	 | ||||||
| 				int i=1; | 				int i=1; | ||||||
| 				if (string_mode==STRING_DOUBLE_QUOTE && GETCHAR(i)=='"' && GETCHAR(i+1)=='"') { | 				if (string_mode==STRING_DOUBLE_QUOTE && GETCHAR(i)=='"' && GETCHAR(i+1)=='"') { | ||||||
| 					i+=2; | 					i+=2; | ||||||
|  |  | ||||||
|  | @ -396,6 +396,14 @@ void AudioDriverOpenSL::finish(){ | ||||||
| void AudioDriverOpenSL::set_pause(bool p_pause) { | void AudioDriverOpenSL::set_pause(bool p_pause) { | ||||||
| 
 | 
 | ||||||
| 	pause=p_pause; | 	pause=p_pause; | ||||||
|  | 
 | ||||||
|  | 	if (active) { | ||||||
|  | 		if (pause) { | ||||||
|  | 			(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED); | ||||||
|  | 		} else { | ||||||
|  | 			(*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -151,7 +151,7 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_ | ||||||
| 	sample_manager = memnew( SampleManagerMallocSW ); | 	sample_manager = memnew( SampleManagerMallocSW ); | ||||||
| 	audio_server = memnew( AudioServerSW(sample_manager) ); | 	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(); | 	audio_server->init(); | ||||||
| 
 | 
 | ||||||
| 	spatial_sound_server = memnew( SpatialSoundServerSW ); | 	spatial_sound_server = memnew( SpatialSoundServerSW ); | ||||||
|  |  | ||||||
|  | @ -84,13 +84,11 @@ static int frame_count = 0; | ||||||
| 	switch (frame_count) { | 	switch (frame_count) { | ||||||
| 
 | 
 | ||||||
| 	case 0: { | 	case 0: { | ||||||
|  |         int backingWidth; | ||||||
|  |         int backingHeight; | ||||||
|  |         glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); | ||||||
|  |         glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); | ||||||
| 		 | 		 | ||||||
| 		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); |  | ||||||
| 
 | 
 | ||||||
| 		OS::VideoMode vm; | 		OS::VideoMode vm; | ||||||
| 		vm.fullscreen = true; | 		vm.fullscreen = true; | ||||||
|  | @ -198,6 +196,13 @@ static int frame_count = 0; | ||||||
| 	//glView.autoresizesSubviews = YES; | 	//glView.autoresizesSubviews = YES; | ||||||
| 	//[glView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth]; | 	//[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 = [[ViewController alloc] init]; | ||||||
| 	view_controller.view = glView; | 	view_controller.view = glView; | ||||||
| 	window.rootViewController = view_controller; | 	window.rootViewController = view_controller; | ||||||
|  |  | ||||||
|  | @ -34,6 +34,8 @@ | ||||||
| #import <MediaPlayer/MediaPlayer.h> | #import <MediaPlayer/MediaPlayer.h> | ||||||
| #import <AVFoundation/AVFoundation.h> | #import <AVFoundation/AVFoundation.h> | ||||||
| 
 | 
 | ||||||
|  | #define USE_CADISPLAYLINK      1   //iOS version 3.1+ is required
 | ||||||
|  | 
 | ||||||
| @protocol GLViewDelegate; | @protocol GLViewDelegate; | ||||||
| 
 | 
 | ||||||
| @interface GLView : UIView<UIKeyInput> | @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)
 | 	// OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist)
 | ||||||
| 	GLuint depthRenderbuffer; | 	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.
 | 	// An animation timer that, when animation is started, will periodically call -drawView at the given rate.
 | ||||||
| 	NSTimer *animationTimer; | 	NSTimer *animationTimer; | ||||||
|  | #endif | ||||||
|  | 	 | ||||||
| 	NSTimeInterval animationInterval; | 	NSTimeInterval animationInterval; | ||||||
| 	 | 	 | ||||||
| 	// Delegate to do our drawing, called by -drawView, which can be called manually or via the animation timer.
 | 	// Delegate to do our drawing, called by -drawView, which can be called manually or via the animation timer.
 | ||||||
|  |  | ||||||
|  | @ -415,7 +415,19 @@ static void clear_touches() { | ||||||
| 		return; | 		return; | ||||||
| 	active = TRUE; | 	active = TRUE; | ||||||
| 	printf("start animation!\n"); | 	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]; | 	animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES]; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	if (video_playing) | 	if (video_playing) | ||||||
| 	{ | 	{ | ||||||
|  | @ -429,8 +441,13 @@ static void clear_touches() { | ||||||
| 		return; | 		return; | ||||||
| 	active = FALSE; | 	active = FALSE; | ||||||
| 	printf("******** stop animation!\n"); | 	printf("******** stop animation!\n"); | ||||||
|  | #if USE_CADISPLAYLINK | ||||||
|  | 	[displayLink invalidate]; | ||||||
|  | 	displayLink = nil; | ||||||
|  | #else | ||||||
| 	[animationTimer invalidate]; | 	[animationTimer invalidate]; | ||||||
| 	animationTimer = nil; | 	animationTimer = nil; | ||||||
|  | #endif | ||||||
| 	clear_touches(); | 	clear_touches(); | ||||||
| 
 | 
 | ||||||
| 	if (video_playing) | 	if (video_playing) | ||||||
|  | @ -443,7 +460,11 @@ static void clear_touches() { | ||||||
| { | { | ||||||
| 	animationInterval = interval; | 	animationInterval = interval; | ||||||
| 	 | 	 | ||||||
|  | #if USE_CADISPLAYLINK | ||||||
|  | 	if(displayLink) | ||||||
|  | #else | ||||||
| 	if(animationTimer) | 	if(animationTimer) | ||||||
|  | #endif | ||||||
| 	{ | 	{ | ||||||
| 		[self stopAnimation]; | 		[self stopAnimation]; | ||||||
| 		[self startAnimation]; | 		[self startAnimation]; | ||||||
|  | @ -453,6 +474,17 @@ static void clear_touches() { | ||||||
| // Updates the OpenGL view when the timer fires | // Updates the OpenGL view when the timer fires | ||||||
| - (void)drawView | - (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) { | 	if (!active) { | ||||||
| 		printf("draw view not active!\n"); | 		printf("draw view not active!\n"); | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
|  | @ -22,7 +22,7 @@ def get_opts(): | ||||||
| 	return [ | 	return [ | ||||||
| 		('ISIMPLATFORM', 'name of the iphone platform', 'iPhoneSimulator'), | 		('ISIMPLATFORM', 'name of the iphone platform', 'iPhoneSimulator'), | ||||||
| 		('ISIMPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Platforms/${ISIMPLATFORM}.platform'), | 		('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'), | 		('game_center', 'Support for game center', 'yes'), | ||||||
| 		('store_kit', 'Support for in-app store', 'yes'), | 		('store_kit', 'Support for in-app store', 'yes'), | ||||||
| 		('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'), | 		('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'), | ||||||
|  |  | ||||||
|  | @ -1093,8 +1093,19 @@ void OS_OSX::warp_mouse_pos(const Point2& p_to) { | ||||||
|         mouse_y = p_to.y; |         mouse_y = p_to.y; | ||||||
|     } |     } | ||||||
|     else{ //set OS position |     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); |         CGEventSourceRef lEventRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState); | ||||||
|         CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0); |         CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0); | ||||||
|         CGAssociateMouseAndMouseCursorPosition(false); |         CGAssociateMouseAndMouseCursorPosition(false); | ||||||
|  |  | ||||||
|  | @ -115,7 +115,7 @@ def configure(env): | ||||||
| 		env.Append(CCFLAGS=['/DGLES2_ENABLED']) | 		env.Append(CCFLAGS=['/DGLES2_ENABLED']) | ||||||
| 
 | 
 | ||||||
| 		env.Append(CCFLAGS=['/DGLEW_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(LINKFLAGS=[p+env["LIBSUFFIX"] for p in LIBS]) | ||||||
| 		 | 		 | ||||||
| 		env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"]) | 		env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"]) | ||||||
|  | @ -229,7 +229,7 @@ def configure(env): | ||||||
| 		env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows']) | 		env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows']) | ||||||
| 		env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED']) | 		env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED']) | ||||||
| 		env.Append(CCFLAGS=['-DGLES2_ENABLED','-DGLEW_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"): | 		if (env["bits"]=="32" and env["mingw64_for_32"]!="yes"): | ||||||
| #			env.Append(LIBS=['gcc_s']) | #			env.Append(LIBS=['gcc_s']) | ||||||
|  |  | ||||||
|  | @ -54,10 +54,16 @@ | ||||||
| #include "io/marshalls.h" | #include "io/marshalls.h" | ||||||
| 
 | 
 | ||||||
| #include "shlobj.h" | #include "shlobj.h" | ||||||
|  | #include <regstr.h> | ||||||
|  | 
 | ||||||
| static const WORD MAX_CONSOLE_LINES = 1500; | static const WORD MAX_CONSOLE_LINES = 1500; | ||||||
| 
 | 
 | ||||||
| extern "C" { | extern "C" { | ||||||
|  | #ifdef _MSC_VER | ||||||
| 	_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; | 	_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; | ||||||
|  | #else | ||||||
|  | 	__attribute__((visibility("default"))) DWORD NvOptimusEnablement = 0x00000001; | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //#define STDOUT_FILE
 | //#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); | 			ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE); | ||||||
| 
 | 
 | ||||||
|  | 			// Make sure we don't include modifiers for the modifier key itself.
 | ||||||
| 			KeyEvent ke; | 			KeyEvent ke; | ||||||
| 			ke.mod_state.shift=shift_mem; | 			ke.mod_state.shift= (wParam != VK_SHIFT) ? shift_mem : false; | ||||||
| 			ke.mod_state.alt=alt_mem; | 			ke.mod_state.alt= (! (wParam == VK_MENU && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN))) ? alt_mem : false; | ||||||
| 			ke.mod_state.control=control_mem; | 			ke.mod_state.control= (wParam != VK_CONTROL) ? control_mem : false; | ||||||
| 			ke.mod_state.meta=meta_mem; | 			ke.mod_state.meta=meta_mem; | ||||||
| 			ke.uMsg=uMsg; | 			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() { | void OS_Windows::probe_joysticks() { | ||||||
| 
 | 
 | ||||||
| 	static uint32_t last_attached = 0; | 	static uint32_t last_attached = 0; | ||||||
|  | @ -721,7 +775,13 @@ void OS_Windows::probe_joysticks() { | ||||||
| 			JOYCAPS jcaps; | 			JOYCAPS jcaps; | ||||||
| 			MMRESULT res = joyGetDevCaps(JOYSTICKID1 + i, &jcaps, sizeof(jcaps)); | 			MMRESULT res = joyGetDevCaps(JOYSTICKID1 + i, &jcaps, sizeof(jcaps)); | ||||||
| 			if (res == JOYERR_NOERROR) { | 			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; | 		old_y=p_to.y; | ||||||
| 	} else { | 	} 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 { | Point2 OS_Windows::get_mouse_pos() const { | ||||||
|  |  | ||||||
|  | @ -187,6 +187,7 @@ protected: | ||||||
| 	void probe_joysticks(); | 	void probe_joysticks(); | ||||||
| 	void process_joysticks(); | 	void process_joysticks(); | ||||||
| 	void process_key_events(); | 	void process_key_events(); | ||||||
|  | 	String get_joystick_name( int id, JOYCAPS jcaps); | ||||||
| 	 | 	 | ||||||
| 	struct ProcessInfo { | 	struct ProcessInfo { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -27,7 +27,6 @@ | ||||||
| /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | ||||||
| /*************************************************************************/ | /*************************************************************************/ | ||||||
| #include "drivers/gles2/rasterizer_gles2.h" | #include "drivers/gles2/rasterizer_gles2.h" | ||||||
| #include "drivers/gles1/rasterizer_gles1.h" |  | ||||||
| #include "os_winrt.h" | #include "os_winrt.h" | ||||||
| #include "drivers/nedmalloc/memory_pool_static_nedmalloc.h" | #include "drivers/nedmalloc/memory_pool_static_nedmalloc.h" | ||||||
| #include "drivers/unix/memory_pool_static_malloc.h" | #include "drivers/unix/memory_pool_static_malloc.h" | ||||||
|  | @ -62,11 +61,11 @@ using namespace Microsoft::WRL; | ||||||
| 
 | 
 | ||||||
| int OSWinrt::get_video_driver_count() const { | int OSWinrt::get_video_driver_count() const { | ||||||
| 
 | 
 | ||||||
| 	return 2; | 	return 1; | ||||||
| } | } | ||||||
| const char * OSWinrt::get_video_driver_name(int p_driver) const { | 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 { | OS::VideoMode OSWinrt::get_default_video_mode() const { | ||||||
|  |  | ||||||
|  | @ -70,24 +70,23 @@ def configure(env): | ||||||
| 		else: | 		else: | ||||||
| 			env["bits"]="32" | 			env["bits"]="32" | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	env.Append(CPPPATH=['#platform/x11']) | 	env.Append(CPPPATH=['#platform/x11']) | ||||||
| 	if (env["use_llvm"]=="yes"): | 	if (env["use_llvm"]=="yes"): | ||||||
| 		env["CC"]="clang" | 		if 'clang++' not in env['CXX']: | ||||||
| 		env["CXX"]="clang++" | 			env["CC"]="clang" | ||||||
| 		env["LD"]="clang++" | 			env["CXX"]="clang++" | ||||||
| 		if (env["use_sanitizer"]=="yes"): | 			env["LD"]="clang++" | ||||||
| 			env.Append(CXXFLAGS=['-fsanitize=address','-fno-omit-frame-pointer']) | 		env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) | ||||||
| 			env.Append(LINKFLAGS=['-fsanitize=address']) | 		env.extra_suffix=".llvm" | ||||||
| 			env.extra_suffix=".llvms" | 
 | ||||||
| 		else: |  | ||||||
| 			env.extra_suffix=".llvm" |  | ||||||
| 		if (env["colored"]=="yes"): | 		if (env["colored"]=="yes"): | ||||||
| 			if sys.stdout.isatty(): | 			if sys.stdout.isatty(): | ||||||
| 				env.Append(CXXFLAGS=["-fcolor-diagnostics"]) | 				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"): | 	#if (env["tools"]=="no"): | ||||||
| 	#	#no tools suffix | 	#	#no tools suffix | ||||||
|  | @ -141,11 +140,6 @@ def configure(env): | ||||||
| 		env.Append(LINKFLAGS=['-m64','-L/usr/lib/i686-linux-gnu']) | 		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 | 	import methods | ||||||
| 
 | 
 | ||||||
| 	env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } ) | 	env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } ) | ||||||
|  |  | ||||||
|  | @ -479,8 +479,12 @@ void OS_X11::warp_mouse_pos(const Point2& p_to) { | ||||||
| 		last_mouse_pos=p_to; | 		last_mouse_pos=p_to; | ||||||
| 	} else { | 	} else { | ||||||
| 
 | 
 | ||||||
|  | 		/*XWindowAttributes xwa;
 | ||||||
|  | 		XGetWindowAttributes(x11_display, x11_window, &xwa); | ||||||
|  | 		printf("%d %d\n", xwa.x, xwa.y); needed? */ | ||||||
|  | 
 | ||||||
| 		XWarpPointer(x11_display, None, x11_window, | 		XWarpPointer(x11_display, None, x11_window, | ||||||
| 			      0,0,0,0, (int)p_to.x, (int)p_to.y); | 			      0,0,0,0, (int)p_to.x , (int)p_to.y); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -36,6 +36,192 @@ | ||||||
| #include "scene/resources/texture.h" | #include "scene/resources/texture.h" | ||||||
| #include "scene/resources/style_box.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 { | bool CanvasItem::is_visible() const { | ||||||
| 
 | 
 | ||||||
| 	if (!is_inside_tree()) | 	if (!is_inside_tree()) | ||||||
|  | @ -458,6 +644,16 @@ CanvasItem::BlendMode CanvasItem::get_blend_mode() const { | ||||||
| 	return blend_mode; | 	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() { | 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); | 	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) { | 	if (!drawing) { | ||||||
| 		ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); | 		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()); | 	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) { | 	if (!drawing) { | ||||||
| 		ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); | 		ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); | ||||||
| 		ERR_FAIL(); | 		ERR_FAIL(); | ||||||
| 	} | 	} | ||||||
| 	ERR_FAIL_COND(p_texture.is_null()); | 	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) { | 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; | 	return behind; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CanvasItem::set_shader(const Ref<Shader>& p_shader) { | void CanvasItem::set_material(const Ref<CanvasItemMaterial>& p_material) { | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode()!=Shader::MODE_CANVAS_ITEM); |  | ||||||
| 
 |  | ||||||
| #ifdef TOOLS_ENABLED |  | ||||||
| 
 |  | ||||||
| 	if (shader.is_valid()) { |  | ||||||
| 		shader->disconnect("changed",this,"_shader_changed"); |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
| 	shader=p_shader; |  | ||||||
| 
 |  | ||||||
| #ifdef TOOLS_ENABLED |  | ||||||
| 
 |  | ||||||
| 	if (shader.is_valid()) { |  | ||||||
| 		shader->connect("changed",this,"_shader_changed"); |  | ||||||
| 	} |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
|  | 	material=p_material; | ||||||
| 	RID rid; | 	RID rid; | ||||||
| 	if (shader.is_valid()) | 	if (material.is_valid()) | ||||||
| 		rid=shader->get_rid(); | 		rid=material->get_rid(); | ||||||
| 	VS::get_singleton()->canvas_item_set_shader(canvas_item,rid); | 	VS::get_singleton()->canvas_item_set_material(canvas_item,rid); | ||||||
| 	_change_notify(); //properties for shader exposed
 | 	_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; | 	use_parent_material=p_use_parent_material; | ||||||
| 	VS::get_singleton()->canvas_item_set_use_parent_shader(canvas_item,p_use_parent_shader); | 	VS::get_singleton()->canvas_item_set_use_parent_material(canvas_item,p_use_parent_material); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool CanvasItem::get_use_parent_shader() const{ | bool CanvasItem::get_use_parent_material() const{ | ||||||
| 
 | 
 | ||||||
| 	return use_parent_shader; | 	return use_parent_material; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Ref<Shader> CanvasItem::get_shader() const{ | Ref<CanvasItemMaterial> CanvasItem::get_material() const{ | ||||||
| 
 | 
 | ||||||
| 	return shader; | 	return material; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CanvasItem::set_shader_param(const StringName& p_param,const Variant& p_value) { |  | ||||||
| 
 | 
 | ||||||
| 	VS::get_singleton()->canvas_item_set_shader_param(canvas_item,p_param,p_value); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| Variant CanvasItem::get_shader_param(const StringName& p_param) const { |  | ||||||
| 
 | 
 | ||||||
| 	return VS::get_singleton()->canvas_item_get_shader_param(canvas_item,p_param); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool CanvasItem::_set(const StringName& p_name, const Variant& p_value) { |  | ||||||
| 
 |  | ||||||
| 	if (shader.is_valid()) { |  | ||||||
| 		StringName pr = shader->remap_param(p_name); |  | ||||||
| 		if (pr) { |  | ||||||
| 			set_shader_param(pr,p_value); |  | ||||||
| 			return true; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool CanvasItem::_get(const StringName& p_name,Variant &r_ret) const{ |  | ||||||
| 
 |  | ||||||
| 	if (shader.is_valid()) { |  | ||||||
| 		StringName pr = shader->remap_param(p_name); |  | ||||||
| 		if (pr) { |  | ||||||
| 			r_ret=get_shader_param(pr); |  | ||||||
| 			return true; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return false; |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| void CanvasItem::_get_property_list( List<PropertyInfo> *p_list) const{ |  | ||||||
| 
 |  | ||||||
| 	if (shader.is_valid()) { |  | ||||||
| 		shader->get_param_list(p_list); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #ifdef TOOLS_ENABLED |  | ||||||
| void CanvasItem::_shader_changed() { |  | ||||||
| 
 |  | ||||||
| 	_change_notify(); |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| void CanvasItem::_bind_methods() { | 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("set_blend_mode","blend_mode"),&CanvasItem::set_blend_mode); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_blend_mode"),&CanvasItem::get_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("set_opacity","opacity"),&CanvasItem::set_opacity); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_opacity"),&CanvasItem::get_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("set_self_opacity","self_opacity"),&CanvasItem::set_self_opacity); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_self_opacity"),&CanvasItem::get_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("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("_set_on_top","on_top"),&CanvasItem::_set_on_top); | ||||||
| 	ObjectTypeDB::bind_method(_MD("_is_on_top"),&CanvasItem::_is_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("get_transform"),&CanvasItem::get_transform);
 | ||||||
| 
 | 
 | ||||||
| 	ObjectTypeDB::bind_method(_MD("draw_line","from","to","color","width"),&CanvasItem::draw_line,DEFVAL(1.0)); | 	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("draw_set_transform","pos","rot","scale"),&CanvasItem::draw_set_transform); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_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"),&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_transform"),&CanvasItem::get_viewport_transform); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_viewport_rect"),&CanvasItem::get_viewport_rect); | 	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_canvas"),&CanvasItem::get_canvas); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_world_2d"),&CanvasItem::get_world_2d); | 	ObjectTypeDB::bind_method(_MD("get_world_2d"),&CanvasItem::get_world_2d); | ||||||
| 	//ObjectTypeDB::bind_method(_MD("get_viewport"),&CanvasItem::get_viewport);
 | 	//ObjectTypeDB::bind_method(_MD("get_viewport"),&CanvasItem::get_viewport);
 | ||||||
| 
 | 
 | ||||||
| 	ObjectTypeDB::bind_method(_MD("set_shader","shader"),&CanvasItem::set_shader); | 	ObjectTypeDB::bind_method(_MD("set_material","material:CanvasItemMaterial"),&CanvasItem::set_material); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_shader"),&CanvasItem::get_shader); | 	ObjectTypeDB::bind_method(_MD("get_material:CanvasItemMaterial"),&CanvasItem::get_material); | ||||||
| 	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_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")); | 	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_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::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::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") ); | ||||||
| 	ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"shader/use_parent"), _SCS("set_use_parent_shader"),_SCS("get_use_parent_shader") ); | 	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
 | 	//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/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"));
 | 	//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; | 	block_transform_notify=false; | ||||||
| //	viewport=NULL;
 | //	viewport=NULL;
 | ||||||
| 	canvas_layer=NULL; | 	canvas_layer=NULL; | ||||||
| 	use_parent_shader; | 	use_parent_material=false; | ||||||
| 	global_invalid=true; | 	global_invalid=true; | ||||||
|  | 	light_mask=1; | ||||||
| 
 | 
 | ||||||
| 	C=NULL; | 	C=NULL; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -40,6 +40,41 @@ class Font; | ||||||
| 
 | 
 | ||||||
| class StyleBox; | 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 { | class CanvasItem : public Node { | ||||||
| 
 | 
 | ||||||
| 	OBJ_TYPE( CanvasItem, Node ); | 	OBJ_TYPE( CanvasItem, Node ); | ||||||
|  | @ -71,6 +106,7 @@ private: | ||||||
| 	List<CanvasItem*>::Element *C; | 	List<CanvasItem*>::Element *C; | ||||||
| 
 | 
 | ||||||
| 	BlendMode blend_mode; | 	BlendMode blend_mode; | ||||||
|  | 	int light_mask; | ||||||
| 
 | 
 | ||||||
| 	bool first_draw; | 	bool first_draw; | ||||||
| 	bool hidden; | 	bool hidden; | ||||||
|  | @ -80,9 +116,9 @@ private: | ||||||
| 	bool drawing; | 	bool drawing; | ||||||
| 	bool block_transform_notify; | 	bool block_transform_notify; | ||||||
| 	bool behind; | 	bool behind; | ||||||
|  | 	bool use_parent_material; | ||||||
| 
 | 
 | ||||||
| 	bool use_parent_shader; | 	Ref<CanvasItemMaterial> material; | ||||||
| 	Ref<Shader> shader; |  | ||||||
| 
 | 
 | ||||||
| 	mutable Matrix32 global_transform; | 	mutable Matrix32 global_transform; | ||||||
| 	mutable bool global_invalid; | 	mutable bool global_invalid; | ||||||
|  | @ -103,9 +139,6 @@ private: | ||||||
| 	void _queue_sort_children(); | 	void _queue_sort_children(); | ||||||
| 	void _sort_children(); | 	void _sort_children(); | ||||||
| 
 | 
 | ||||||
| #ifdef TOOLS_ENABLED |  | ||||||
| 	void _shader_changed(); |  | ||||||
| #endif |  | ||||||
| 	void _notify_transform(CanvasItem *p_node); | 	void _notify_transform(CanvasItem *p_node); | ||||||
| 
 | 
 | ||||||
| 	void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); } | 	void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); } | ||||||
|  | @ -113,11 +146,6 @@ private: | ||||||
| 
 | 
 | ||||||
| protected: | 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); } | 	_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(); | 	void item_rect_changed(); | ||||||
|  | @ -158,6 +186,9 @@ public: | ||||||
| 	void set_blend_mode(BlendMode p_blend_mode); | 	void set_blend_mode(BlendMode p_blend_mode); | ||||||
| 	BlendMode get_blend_mode() const; | 	BlendMode get_blend_mode() const; | ||||||
| 
 | 
 | ||||||
|  | 	void set_light_mask(int p_light_mask); | ||||||
|  | 	int get_light_mask() const; | ||||||
|  | 
 | ||||||
| 	void set_opacity(float p_opacity); | 	void set_opacity(float p_opacity); | ||||||
| 	float get_opacity() const; | 	float get_opacity() const; | ||||||
| 
 | 
 | ||||||
|  | @ -170,8 +201,8 @@ public: | ||||||
| 	void draw_rect(const Rect2& p_rect, const Color& p_color); | 	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_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(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(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)); | 	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_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_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>()); | 	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; | 	RID get_canvas() const; | ||||||
| 	Ref<World2D> get_world_2d() const; | 	Ref<World2D> get_world_2d() const; | ||||||
| 
 | 
 | ||||||
| 	void set_shader(const Ref<Shader>& p_shader); | 	void set_material(const Ref<CanvasItemMaterial>& p_material); | ||||||
| 	Ref<Shader> get_shader() const; | 	Ref<CanvasItemMaterial> get_material() const; | ||||||
| 
 | 
 | ||||||
| 	void set_use_parent_shader(bool p_use_parent_shader); | 	void set_use_parent_material(bool p_use_parent_material); | ||||||
| 	bool get_use_parent_shader() const; | 	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(); | ||||||
| 	~CanvasItem(); | 	~CanvasItem(); | ||||||
|  |  | ||||||
							
								
								
									
										46
									
								
								scene/2d/canvas_modulate.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								scene/2d/canvas_modulate.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | ||||||
|  | #include "canvas_modulate.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void CanvasModulate::_notification(int p_what) { | ||||||
|  | 
 | ||||||
|  | 	if (p_what==NOTIFICATION_ENTER_CANVAS) { | ||||||
|  | 
 | ||||||
|  | 		VS::get_singleton()->canvas_set_modulate(get_canvas(),color); | ||||||
|  | 	} else if (p_what==NOTIFICATION_EXIT_CANVAS) { | ||||||
|  | 
 | ||||||
|  | 		VS::get_singleton()->canvas_set_modulate(get_canvas(),Color(1,1,1,1)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void CanvasModulate::_bind_methods(){ | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_color","color"),&CanvasModulate::set_color); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_color"),&CanvasModulate::get_color); | ||||||
|  | 
 | ||||||
|  | 	ADD_PROPERTY(PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void CanvasModulate::set_color(const Color& p_color){ | ||||||
|  | 
 | ||||||
|  | 	color=p_color; | ||||||
|  | 	if (is_inside_tree()) { | ||||||
|  | 		VS::get_singleton()->canvas_set_modulate(get_canvas(),color); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | Color CanvasModulate::get_color() const { | ||||||
|  | 
 | ||||||
|  | 	return color; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | CanvasModulate::CanvasModulate() | ||||||
|  | { | ||||||
|  | 	color=Color(1,1,1,1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | CanvasModulate::~CanvasModulate() | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										23
									
								
								scene/2d/canvas_modulate.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								scene/2d/canvas_modulate.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | ||||||
|  | #ifndef CANVASMODULATE_H | ||||||
|  | #define CANVASMODULATE_H | ||||||
|  | 
 | ||||||
|  | #include "scene/2d/node_2d.h" | ||||||
|  | 
 | ||||||
|  | class CanvasModulate : public Node2D { | ||||||
|  | 
 | ||||||
|  | 	OBJ_TYPE(CanvasModulate,Node2D); | ||||||
|  | 
 | ||||||
|  | 	Color color; | ||||||
|  | protected: | ||||||
|  | 	void _notification(int p_what); | ||||||
|  | 	static void _bind_methods(); | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 	void set_color(const Color& p_color); | ||||||
|  | 	Color get_color() const; | ||||||
|  | 
 | ||||||
|  | 	CanvasModulate(); | ||||||
|  | 	~CanvasModulate(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif // CANVASMODULATE_H
 | ||||||
							
								
								
									
										300
									
								
								scene/2d/light_2d.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								scene/2d/light_2d.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,300 @@ | ||||||
|  | #include "light_2d.h" | ||||||
|  | #include "servers/visual_server.h" | ||||||
|  | 
 | ||||||
|  | void Light2D::edit_set_pivot(const Point2& p_pivot) { | ||||||
|  | 
 | ||||||
|  | 	set_texture_offset(p_pivot); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Point2 Light2D::edit_get_pivot() const { | ||||||
|  | 
 | ||||||
|  | 	return get_texture_offset(); | ||||||
|  | } | ||||||
|  | bool Light2D::edit_has_pivot() const { | ||||||
|  | 
 | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Rect2 Light2D::get_item_rect() const { | ||||||
|  | 
 | ||||||
|  | 	if (texture.is_null()) | ||||||
|  | 		return Rect2(0,0,1,1); | ||||||
|  | 
 | ||||||
|  | 	Size2i s; | ||||||
|  | 
 | ||||||
|  | 	s = texture->get_size(); | ||||||
|  | 	Point2i ofs=texture_offset; | ||||||
|  | 	ofs-=s/2; | ||||||
|  | 
 | ||||||
|  | 	if (s==Size2(0,0)) | ||||||
|  | 		s=Size2(1,1); | ||||||
|  | 
 | ||||||
|  | 	return Rect2(ofs,s); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void Light2D::set_enabled( bool p_enabled) { | ||||||
|  | 
 | ||||||
|  | 	VS::get_singleton()->canvas_light_set_enabled(canvas_light,p_enabled); | ||||||
|  | 	enabled=p_enabled; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Light2D::is_enabled() const { | ||||||
|  | 
 | ||||||
|  | 	return enabled; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_texture( const Ref<Texture>& p_texture) { | ||||||
|  | 
 | ||||||
|  | 	texture=p_texture; | ||||||
|  | 	if (texture.is_valid()) | ||||||
|  | 		VS::get_singleton()->canvas_light_set_texture(canvas_light,texture->get_rid()); | ||||||
|  | 	else | ||||||
|  | 		VS::get_singleton()->canvas_light_set_texture(canvas_light,RID()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Ref<Texture> Light2D::get_texture() const { | ||||||
|  | 
 | ||||||
|  | 	return texture; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_texture_offset( const Vector2& p_offset) { | ||||||
|  | 
 | ||||||
|  | 	texture_offset=p_offset; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_texture_offset(canvas_light,texture_offset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Vector2 Light2D::get_texture_offset() const { | ||||||
|  | 
 | ||||||
|  | 	return texture_offset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_color( const Color& p_color) { | ||||||
|  | 
 | ||||||
|  | 	color=p_color; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_color(canvas_light,color); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | Color Light2D::get_color() const { | ||||||
|  | 
 | ||||||
|  | 	return color; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_height( float p_height) { | ||||||
|  | 
 | ||||||
|  | 	height=p_height; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_height(canvas_light,height); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | float Light2D::get_height() const { | ||||||
|  | 
 | ||||||
|  | 	return height; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_z_range_min( int p_min_z) { | ||||||
|  | 
 | ||||||
|  | 	z_min=p_min_z; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_z_range(canvas_light,z_min,z_max); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | int Light2D::get_z_range_min() const { | ||||||
|  | 
 | ||||||
|  | 	return z_min; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_z_range_max( int p_max_z) { | ||||||
|  | 
 | ||||||
|  | 	z_max=p_max_z; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_z_range(canvas_light,z_min,z_max); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | int Light2D::get_z_range_max() const { | ||||||
|  | 
 | ||||||
|  | 	return z_max; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_layer_range_min( int p_min_layer) { | ||||||
|  | 
 | ||||||
|  | 	layer_min=p_min_layer; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_layer_range(canvas_light,layer_min,layer_max); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | int Light2D::get_layer_range_min() const { | ||||||
|  | 
 | ||||||
|  | 	return layer_min; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_layer_range_max( int p_max_layer) { | ||||||
|  | 
 | ||||||
|  | 	layer_max=p_max_layer; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_layer_range(canvas_light,layer_min,layer_max); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | int Light2D::get_layer_range_max() const { | ||||||
|  | 
 | ||||||
|  | 	return layer_max; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_item_mask( int p_mask) { | ||||||
|  | 
 | ||||||
|  | 	item_mask=p_mask; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_item_mask(canvas_light,item_mask); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int Light2D::get_item_mask() const { | ||||||
|  | 
 | ||||||
|  | 	return item_mask; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_subtract_mode( bool p_enable ) { | ||||||
|  | 
 | ||||||
|  | 	subtract_mode=p_enable; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_subtract_mode(canvas_light,p_enable); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool Light2D::get_subtract_mode() const { | ||||||
|  | 
 | ||||||
|  | 	return subtract_mode; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_shadow_enabled( bool p_enabled) { | ||||||
|  | 
 | ||||||
|  | 	shadow=p_enabled; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_shadow_enabled(canvas_light,shadow); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | bool Light2D::is_shadow_enabled() const { | ||||||
|  | 
 | ||||||
|  | 	return shadow; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_shadow_buffer_size( int p_size ) { | ||||||
|  | 
 | ||||||
|  | 	shadow_buffer_size=p_size; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_shadow_buffer_size(canvas_light,shadow_buffer_size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int Light2D::get_shadow_buffer_size() const { | ||||||
|  | 
 | ||||||
|  | 	return shadow_buffer_size; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::set_shadow_esm_multiplier( float p_multiplier) { | ||||||
|  | 
 | ||||||
|  | 	shadow_esm_multiplier=p_multiplier; | ||||||
|  | 	VS::get_singleton()->canvas_light_set_shadow_esm_multiplier(canvas_light,p_multiplier); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float Light2D::get_shadow_esm_multiplier() const{ | ||||||
|  | 
 | ||||||
|  | 	return shadow_esm_multiplier; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void Light2D::_notification(int p_what) { | ||||||
|  | 
 | ||||||
|  | 	if (p_what==NOTIFICATION_ENTER_TREE) { | ||||||
|  | 
 | ||||||
|  | 		VS::get_singleton()->canvas_light_attach_to_canvas( canvas_light, get_canvas() ); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (p_what==NOTIFICATION_TRANSFORM_CHANGED) { | ||||||
|  | 
 | ||||||
|  | 		VS::get_singleton()->canvas_light_set_transform( canvas_light, get_global_transform()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (p_what==NOTIFICATION_EXIT_TREE) { | ||||||
|  | 
 | ||||||
|  | 		VS::get_singleton()->canvas_light_attach_to_canvas( canvas_light, RID() ); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Light2D::_bind_methods() { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&Light2D::set_enabled); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("is_enabled"),&Light2D::is_enabled); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_texture","texture"),&Light2D::set_texture); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_texture"),&Light2D::get_texture); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_texture_offset","texture_offset"),&Light2D::set_texture_offset); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_texture_offset"),&Light2D::get_texture_offset); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_color","color"),&Light2D::set_color); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_color"),&Light2D::get_color); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_height","height"),&Light2D::set_height); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_height"),&Light2D::get_height); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_z_range_min","z"),&Light2D::set_z_range_min); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_z_range_min"),&Light2D::get_z_range_min); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_z_range_max","z"),&Light2D::set_z_range_max); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_z_range_max"),&Light2D::get_z_range_max); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_layer_range_min","layer"),&Light2D::set_layer_range_min); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_layer_range_min"),&Light2D::get_layer_range_min); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_layer_range_max","layer"),&Light2D::set_layer_range_max); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_layer_range_max"),&Light2D::get_layer_range_max); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_item_mask","item_mask"),&Light2D::set_item_mask); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_item_mask"),&Light2D::get_item_mask); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_subtract_mode","enable"),&Light2D::set_subtract_mode); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_subtract_mode"),&Light2D::get_subtract_mode); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_shadow_enabled","enabled"),&Light2D::set_shadow_enabled); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("is_shadow_enabled"),&Light2D::is_shadow_enabled); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_shadow_buffer_size","size"),&Light2D::set_shadow_buffer_size); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_shadow_buffer_size"),&Light2D::get_shadow_buffer_size); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_shadow_esm_multiplier","multiplier"),&Light2D::set_shadow_esm_multiplier); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_shadow_esm_multiplier"),&Light2D::get_shadow_esm_multiplier); | ||||||
|  | 
 | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"subtract"),_SCS("set_subtract_mode"),_SCS("get_subtract_mode")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"range/height"),_SCS("set_height"),_SCS("get_height")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_min",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_min"),_SCS("get_z_range_min")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_max",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_max"),_SCS("get_z_range_max")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_min",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_min"),_SCS("get_layer_range_min")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_max",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_max"),_SCS("get_layer_range_max")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::INT,"range/item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_mask"),_SCS("get_item_mask")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow/enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/buffer_size",PROPERTY_HINT_RANGE,"32,16384,1"),_SCS("set_shadow_buffer_size"),_SCS("get_shadow_buffer_size")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"shadow/esm_multiplier",PROPERTY_HINT_RANGE,"1,4096,0.1"),_SCS("set_shadow_esm_multiplier"),_SCS("get_shadow_esm_multiplier")); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Light2D::Light2D() { | ||||||
|  | 
 | ||||||
|  | 	canvas_light=VisualServer::get_singleton()->canvas_light_create(); | ||||||
|  | 	enabled=true; | ||||||
|  | 	shadow=false; | ||||||
|  | 	color=Color(1,1,1); | ||||||
|  | 	height=0; | ||||||
|  | 	z_min=-1024; | ||||||
|  | 	z_max=1024; | ||||||
|  | 	layer_min=0; | ||||||
|  | 	layer_max=0; | ||||||
|  | 	item_mask=1; | ||||||
|  | 	subtract_mode=false; | ||||||
|  | 	shadow_buffer_size=2048; | ||||||
|  | 	shadow_esm_multiplier=80; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Light2D::~Light2D() { | ||||||
|  | 
 | ||||||
|  | 	VisualServer::get_singleton()->free(canvas_light); | ||||||
|  | } | ||||||
							
								
								
									
										86
									
								
								scene/2d/light_2d.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								scene/2d/light_2d.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | ||||||
|  | #ifndef LIGHT_2D_H | ||||||
|  | #define LIGHT_2D_H | ||||||
|  | 
 | ||||||
|  | #include "scene/2d/node_2d.h" | ||||||
|  | 
 | ||||||
|  | class Light2D : public Node2D { | ||||||
|  | 
 | ||||||
|  | 	OBJ_TYPE(Light2D,Node2D); | ||||||
|  | private: | ||||||
|  | 	RID canvas_light; | ||||||
|  | 	bool enabled; | ||||||
|  | 	bool shadow; | ||||||
|  | 	Color color; | ||||||
|  | 	float height; | ||||||
|  | 	int z_min; | ||||||
|  | 	int z_max; | ||||||
|  | 	int layer_min; | ||||||
|  | 	int layer_max; | ||||||
|  | 	int item_mask; | ||||||
|  | 	int shadow_buffer_size; | ||||||
|  | 	float shadow_esm_multiplier; | ||||||
|  | 	bool subtract_mode; | ||||||
|  | 	Ref<Texture> texture; | ||||||
|  | 	Vector2 texture_offset; | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  | 
 | ||||||
|  | 	void _notification(int p_what); | ||||||
|  | 	static void _bind_methods(); | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	virtual void edit_set_pivot(const Point2& p_pivot); | ||||||
|  | 	virtual Point2 edit_get_pivot() const; | ||||||
|  | 	virtual bool edit_has_pivot() const; | ||||||
|  | 
 | ||||||
|  | 	void set_enabled( bool p_enabled); | ||||||
|  | 	bool is_enabled() const; | ||||||
|  | 
 | ||||||
|  | 	void set_texture( const Ref<Texture>& p_texture); | ||||||
|  | 	Ref<Texture> get_texture() const; | ||||||
|  | 
 | ||||||
|  | 	void set_texture_offset( const Vector2& p_offset); | ||||||
|  | 	Vector2 get_texture_offset() const; | ||||||
|  | 
 | ||||||
|  | 	void set_color( const Color& p_color); | ||||||
|  | 	Color get_color() const; | ||||||
|  | 
 | ||||||
|  | 	void set_height( float p_height); | ||||||
|  | 	float get_height() const; | ||||||
|  | 
 | ||||||
|  | 	void set_z_range_min( int p_min_z); | ||||||
|  | 	int get_z_range_min() const; | ||||||
|  | 
 | ||||||
|  | 	void set_z_range_max( int p_max_z); | ||||||
|  | 	int get_z_range_max() const; | ||||||
|  | 
 | ||||||
|  | 	void set_layer_range_min( int p_min_layer); | ||||||
|  | 	int get_layer_range_min() const; | ||||||
|  | 
 | ||||||
|  | 	void set_layer_range_max( int p_max_layer); | ||||||
|  | 	int get_layer_range_max() const; | ||||||
|  | 
 | ||||||
|  | 	void set_item_mask( int p_mask); | ||||||
|  | 	int get_item_mask() const; | ||||||
|  | 
 | ||||||
|  | 	void set_subtract_mode( bool p_enable ); | ||||||
|  | 	bool get_subtract_mode() const; | ||||||
|  | 
 | ||||||
|  | 	void set_shadow_enabled( bool p_enabled); | ||||||
|  | 	bool is_shadow_enabled() const; | ||||||
|  | 
 | ||||||
|  | 	void set_shadow_buffer_size( int p_size ); | ||||||
|  | 	int get_shadow_buffer_size() const; | ||||||
|  | 
 | ||||||
|  | 	void set_shadow_esm_multiplier( float p_multiplier); | ||||||
|  | 	float get_shadow_esm_multiplier() const; | ||||||
|  | 
 | ||||||
|  | 	virtual Rect2 get_item_rect() const; | ||||||
|  | 
 | ||||||
|  | 	Light2D(); | ||||||
|  | 	~Light2D(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #endif // LIGHT_2D_H
 | ||||||
							
								
								
									
										201
									
								
								scene/2d/light_occluder_2d.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								scene/2d/light_occluder_2d.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,201 @@ | ||||||
|  | #include "light_occluder_2d.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void OccluderPolygon2D::set_polygon(const DVector<Vector2>& p_polygon) { | ||||||
|  | 
 | ||||||
|  | 	polygon=p_polygon; | ||||||
|  | 	VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,p_polygon,closed); | ||||||
|  | 	emit_changed(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DVector<Vector2> OccluderPolygon2D::get_polygon() const{ | ||||||
|  | 
 | ||||||
|  | 	return polygon; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void OccluderPolygon2D::set_closed(bool p_closed) { | ||||||
|  | 
 | ||||||
|  | 	if (closed==p_closed) | ||||||
|  | 		return; | ||||||
|  | 	closed=p_closed; | ||||||
|  | 	VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon,polygon,closed); | ||||||
|  | 	emit_changed(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool OccluderPolygon2D::is_closed() const{ | ||||||
|  | 
 | ||||||
|  | 	return closed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void OccluderPolygon2D::set_cull_mode(CullMode p_mode){ | ||||||
|  | 
 | ||||||
|  | 	cull=p_mode; | ||||||
|  | 	VS::get_singleton()->canvas_occluder_polygon_set_cull_mode(occ_polygon,VS::CanvasOccluderPolygonCullMode(p_mode)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | OccluderPolygon2D::CullMode OccluderPolygon2D::get_cull_mode() const{ | ||||||
|  | 
 | ||||||
|  | 	return cull; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | RID OccluderPolygon2D::get_rid() const { | ||||||
|  | 
 | ||||||
|  | 	return occ_polygon; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void OccluderPolygon2D::_bind_methods() { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_closed","closed"),&OccluderPolygon2D::set_closed); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("is_closed"),&OccluderPolygon2D::is_closed); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_cull_mode","cull_mode"),&OccluderPolygon2D::set_cull_mode); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_cull_mode"),&OccluderPolygon2D::get_cull_mode); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&OccluderPolygon2D::set_polygon); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_polygon"),&OccluderPolygon2D::get_polygon); | ||||||
|  | 
 | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"closed"),_SCS("set_closed"),_SCS("is_closed")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::INT,"cull_mode",PROPERTY_HINT_ENUM,"Disabled,ClockWise,CounterClockWise"),_SCS("set_cull_mode"),_SCS("get_cull_mode")); | ||||||
|  | 
 | ||||||
|  | 	BIND_CONSTANT(CULL_DISABLED); | ||||||
|  | 	BIND_CONSTANT(CULL_CLOCKWISE); | ||||||
|  | 	BIND_CONSTANT(CULL_COUNTER_CLOCKWISE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | OccluderPolygon2D::OccluderPolygon2D() { | ||||||
|  | 
 | ||||||
|  | 	occ_polygon=VS::get_singleton()->canvas_occluder_polygon_create(); | ||||||
|  | 	closed=true; | ||||||
|  | 	cull=CULL_DISABLED; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | OccluderPolygon2D::~OccluderPolygon2D() { | ||||||
|  | 
 | ||||||
|  | 	VS::get_singleton()->free(occ_polygon); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG_ENABLED | ||||||
|  | void LightOccluder2D::_poly_changed() { | ||||||
|  | 
 | ||||||
|  | 	update(); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void LightOccluder2D::_notification(int p_what) { | ||||||
|  | 
 | ||||||
|  | 	if (p_what==NOTIFICATION_ENTER_CANVAS) { | ||||||
|  | 
 | ||||||
|  | 		VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,get_canvas()); | ||||||
|  | 		VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform()); | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 	if (p_what==NOTIFICATION_TRANSFORM_CHANGED) { | ||||||
|  | 
 | ||||||
|  | 		VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (p_what==NOTIFICATION_DRAW) { | ||||||
|  | 
 | ||||||
|  | 		if (get_tree()->is_editor_hint()) { | ||||||
|  | 
 | ||||||
|  | 			if (occluder_polygon.is_valid()) { | ||||||
|  | 
 | ||||||
|  | 				DVector<Vector2> poly = occluder_polygon->get_polygon(); | ||||||
|  | 
 | ||||||
|  | 				if (poly.size()) { | ||||||
|  | 					if (occluder_polygon->is_closed()) { | ||||||
|  | 						Vector<Color> color; | ||||||
|  | 						color.push_back(Color(0,0,0,0.6)); | ||||||
|  | 						draw_polygon(Variant(poly),color); | ||||||
|  | 					} else { | ||||||
|  | 
 | ||||||
|  | 						int ps=poly.size(); | ||||||
|  | 						DVector<Vector2>::Read r = poly.read(); | ||||||
|  | 						for(int i=0;i<ps-1;i++) { | ||||||
|  | 
 | ||||||
|  | 							draw_line(r[i],r[i+1],Color(0,0,0,0.6),3); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	if (p_what==NOTIFICATION_EXIT_CANVAS) { | ||||||
|  | 
 | ||||||
|  | 		VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,RID()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D>& p_polygon) { | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG_ENABLED | ||||||
|  | 	if (occluder_polygon.is_valid()) | ||||||
|  | 		occluder_polygon->disconnect("changed",this,"_poly_changed"); | ||||||
|  | #endif | ||||||
|  | 	occluder_polygon=p_polygon; | ||||||
|  | 
 | ||||||
|  | 	if (occluder_polygon.is_valid()) | ||||||
|  | 		VS::get_singleton()->canvas_light_occluder_set_polygon(occluder,occluder_polygon->get_rid()); | ||||||
|  | 	else | ||||||
|  | 		VS::get_singleton()->canvas_light_occluder_set_polygon(occluder,RID()); | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG_ENABLED | ||||||
|  | 	if (occluder_polygon.is_valid()) | ||||||
|  | 		occluder_polygon->connect("changed",this,"_poly_changed"); | ||||||
|  | 	update(); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Ref<OccluderPolygon2D> LightOccluder2D::get_occluder_polygon() const { | ||||||
|  | 
 | ||||||
|  | 	return occluder_polygon; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LightOccluder2D::set_occluder_light_mask(int p_mask) { | ||||||
|  | 
 | ||||||
|  | 	mask=p_mask; | ||||||
|  | 	VS::get_singleton()->canvas_light_occluder_set_light_mask(occluder,mask); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int LightOccluder2D::get_occluder_light_mask() const{ | ||||||
|  | 
 | ||||||
|  | 	return mask; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LightOccluder2D::_bind_methods() { | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_occluder_polygon","polygon:OccluderPolygon2D"),&LightOccluder2D::set_occluder_polygon); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_occluder_polygon:OccluderPolygon2D"),&LightOccluder2D::get_occluder_polygon); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_occluder_light_mask","mask"),&LightOccluder2D::set_occluder_light_mask); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_occluder_light_mask"),&LightOccluder2D::get_occluder_light_mask); | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG_ENABLED | ||||||
|  | 	ObjectTypeDB::bind_method("_poly_changed",&LightOccluder2D::_poly_changed); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"occluder",PROPERTY_HINT_RESOURCE_TYPE,"OccluderPolygon2D"),_SCS("set_occluder_polygon"),_SCS("get_occluder_polygon")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::INT,"light_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_occluder_light_mask"),_SCS("get_occluder_light_mask")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LightOccluder2D::LightOccluder2D() { | ||||||
|  | 
 | ||||||
|  | 	occluder=VS::get_singleton()->canvas_light_occluder_create(); | ||||||
|  | 	mask=1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LightOccluder2D::~LightOccluder2D() { | ||||||
|  | 
 | ||||||
|  | 	VS::get_singleton()->free(occluder); | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										73
									
								
								scene/2d/light_occluder_2d.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								scene/2d/light_occluder_2d.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | ||||||
|  | #ifndef LIGHTOCCLUDER2D_H | ||||||
|  | #define LIGHTOCCLUDER2D_H | ||||||
|  | 
 | ||||||
|  | #include "scene/2d/node_2d.h" | ||||||
|  | 
 | ||||||
|  | class OccluderPolygon2D : public Resource { | ||||||
|  | 
 | ||||||
|  | 	OBJ_TYPE(OccluderPolygon2D,Resource); | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 	enum CullMode { | ||||||
|  | 		CULL_DISABLED, | ||||||
|  | 		CULL_CLOCKWISE, | ||||||
|  | 		CULL_COUNTER_CLOCKWISE | ||||||
|  | 	}; | ||||||
|  | private: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	RID occ_polygon; | ||||||
|  | 	DVector<Vector2> polygon; | ||||||
|  | 	bool closed; | ||||||
|  | 	CullMode cull; | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  | 
 | ||||||
|  | 	static void _bind_methods(); | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 	void set_polygon(const DVector<Vector2>& p_polygon); | ||||||
|  | 	DVector<Vector2> get_polygon() const; | ||||||
|  | 
 | ||||||
|  | 	void set_closed(bool p_closed); | ||||||
|  | 	bool is_closed() const; | ||||||
|  | 
 | ||||||
|  | 	void set_cull_mode(CullMode p_mode); | ||||||
|  | 	CullMode get_cull_mode() const; | ||||||
|  | 
 | ||||||
|  | 	virtual RID get_rid() const; | ||||||
|  | 	OccluderPolygon2D(); | ||||||
|  | 	~OccluderPolygon2D(); | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | VARIANT_ENUM_CAST(OccluderPolygon2D::CullMode); | ||||||
|  | 
 | ||||||
|  | class LightOccluder2D : public Node2D { | ||||||
|  | 	OBJ_TYPE(LightOccluder2D,Node2D); | ||||||
|  | 
 | ||||||
|  | 	RID occluder; | ||||||
|  | 	bool enabled; | ||||||
|  | 	int mask; | ||||||
|  | 	Ref<OccluderPolygon2D> occluder_polygon; | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG_ENABLED | ||||||
|  | 	void _poly_changed(); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  | 	void _notification(int p_what); | ||||||
|  | 	static void _bind_methods(); | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 	void set_occluder_polygon(const Ref<OccluderPolygon2D>& p_polygon); | ||||||
|  | 	Ref<OccluderPolygon2D> get_occluder_polygon() const; | ||||||
|  | 
 | ||||||
|  | 	void set_occluder_light_mask(int p_mask); | ||||||
|  | 	int get_occluder_light_mask() const; | ||||||
|  | 
 | ||||||
|  | 	LightOccluder2D(); | ||||||
|  | 	~LightOccluder2D(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif // LIGHTOCCLUDER2D_H
 | ||||||
							
								
								
									
										660
									
								
								scene/2d/navigation2d.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										660
									
								
								scene/2d/navigation2d.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,660 @@ | ||||||
|  | #include "navigation2d.h" | ||||||
|  | 
 | ||||||
|  | #define USE_ENTRY_POINT | ||||||
|  | 
 | ||||||
|  | void Navigation2D::_navpoly_link(int p_id) { | ||||||
|  | 
 | ||||||
|  | 	ERR_FAIL_COND(!navpoly_map.has(p_id)); | ||||||
|  | 	NavMesh &nm=navpoly_map[p_id]; | ||||||
|  | 	ERR_FAIL_COND(nm.linked); | ||||||
|  | 
 | ||||||
|  | 	print_line("LINK"); | ||||||
|  | 
 | ||||||
|  | 	DVector<Vector2> vertices=nm.navpoly->get_vertices(); | ||||||
|  | 	int len = vertices.size(); | ||||||
|  | 	if (len==0) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	DVector<Vector2>::Read r=vertices.read(); | ||||||
|  | 
 | ||||||
|  | 	for(int i=0;i<nm.navpoly->get_polygon_count();i++) { | ||||||
|  | 
 | ||||||
|  | 		//build
 | ||||||
|  | 
 | ||||||
|  | 		List<Polygon>::Element *P=nm.polygons.push_back(Polygon()); | ||||||
|  | 		Polygon &p=P->get(); | ||||||
|  | 		p.owner=&nm; | ||||||
|  | 
 | ||||||
|  | 		Vector<int> poly = nm.navpoly->get_polygon(i); | ||||||
|  | 		int plen=poly.size(); | ||||||
|  | 		const int *indices=poly.ptr(); | ||||||
|  | 		bool valid=true; | ||||||
|  | 		p.edges.resize(plen); | ||||||
|  | 
 | ||||||
|  | 		Vector2 center; | ||||||
|  | 
 | ||||||
|  | 		for(int j=0;j<plen;j++) { | ||||||
|  | 
 | ||||||
|  | 			int idx = indices[j]; | ||||||
|  | 			if (idx<0 || idx>=len) { | ||||||
|  | 				valid=false; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			Polygon::Edge e; | ||||||
|  | 			Vector2 ep=nm.xform.xform(r[idx]); | ||||||
|  | 			center+=ep; | ||||||
|  | 			e.point=_get_point(ep); | ||||||
|  | 			p.edges[j]=e; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (!valid) { | ||||||
|  | 			nm.polygons.pop_back(); | ||||||
|  | 			ERR_CONTINUE(!valid); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		p.center=center/plen; | ||||||
|  | 
 | ||||||
|  | 		//connect
 | ||||||
|  | 
 | ||||||
|  | 		for(int j=0;j<plen;j++) { | ||||||
|  | 
 | ||||||
|  | 			int next = (j+1)%plen; | ||||||
|  | 			EdgeKey ek(p.edges[j].point,p.edges[next].point); | ||||||
|  | 
 | ||||||
|  | 			Map<EdgeKey,Connection>::Element *C=connections.find(ek); | ||||||
|  | 			if (!C) { | ||||||
|  | 
 | ||||||
|  | 				Connection c; | ||||||
|  | 				c.A=&p; | ||||||
|  | 				c.A_edge=j; | ||||||
|  | 				c.B=NULL; | ||||||
|  | 				c.B_edge=-1; | ||||||
|  | 				connections[ek]=c; | ||||||
|  | 			} else { | ||||||
|  | 
 | ||||||
|  | 				if (C->get().B!=NULL) { | ||||||
|  | 					print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b)); | ||||||
|  | 				} | ||||||
|  | 				ERR_CONTINUE(C->get().B!=NULL); //wut
 | ||||||
|  | 
 | ||||||
|  | 				C->get().B=&p; | ||||||
|  | 				C->get().B_edge=j; | ||||||
|  | 				C->get().A->edges[C->get().A_edge].C=&p; | ||||||
|  | 				C->get().A->edges[C->get().A_edge].C_edge=j;; | ||||||
|  | 				p.edges[j].C=C->get().A; | ||||||
|  | 				p.edges[j].C_edge=C->get().A_edge; | ||||||
|  | 				//connection successful.
 | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	nm.linked=true; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void Navigation2D::_navpoly_unlink(int p_id) { | ||||||
|  | 
 | ||||||
|  | 	ERR_FAIL_COND(!navpoly_map.has(p_id)); | ||||||
|  | 	NavMesh &nm=navpoly_map[p_id]; | ||||||
|  | 	ERR_FAIL_COND(!nm.linked); | ||||||
|  | 
 | ||||||
|  | 	print_line("UNLINK"); | ||||||
|  | 
 | ||||||
|  | 	for (List<Polygon>::Element *E=nm.polygons.front();E;E=E->next()) { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 		Polygon &p=E->get(); | ||||||
|  | 
 | ||||||
|  | 		int ec = p.edges.size(); | ||||||
|  | 		Polygon::Edge *edges=p.edges.ptr(); | ||||||
|  | 
 | ||||||
|  | 		for(int i=0;i<ec;i++) { | ||||||
|  | 			int next = (i+1)%ec; | ||||||
|  | 
 | ||||||
|  | 			EdgeKey ek(edges[i].point,edges[next].point); | ||||||
|  | 			Map<EdgeKey,Connection>::Element *C=connections.find(ek); | ||||||
|  | 			ERR_CONTINUE(!C); | ||||||
|  | 			if (C->get().B) { | ||||||
|  | 				//disconnect
 | ||||||
|  | 
 | ||||||
|  | 				C->get().B->edges[C->get().B_edge].C=NULL; | ||||||
|  | 				C->get().B->edges[C->get().B_edge].C_edge=-1; | ||||||
|  | 				C->get().A->edges[C->get().A_edge].C=NULL; | ||||||
|  | 				C->get().A->edges[C->get().A_edge].C_edge=-1; | ||||||
|  | 
 | ||||||
|  | 				if (C->get().A==&E->get()) { | ||||||
|  | 
 | ||||||
|  | 					C->get().A=C->get().B; | ||||||
|  | 					C->get().A_edge=C->get().B_edge; | ||||||
|  | 				} | ||||||
|  | 				C->get().B=NULL; | ||||||
|  | 				C->get().B_edge=-1; | ||||||
|  | 
 | ||||||
|  | 			} else { | ||||||
|  | 				connections.erase(C); | ||||||
|  | 				//erase
 | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	nm.polygons.clear(); | ||||||
|  | 
 | ||||||
|  | 	nm.linked=false; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | int Navigation2D::navpoly_create(const Ref<NavigationPolygon>& p_mesh, const Matrix32& p_xform, Object *p_owner) { | ||||||
|  | 
 | ||||||
|  | 	int id = last_id++; | ||||||
|  | 	NavMesh nm; | ||||||
|  | 	nm.linked=false; | ||||||
|  | 	nm.navpoly=p_mesh; | ||||||
|  | 	nm.xform=p_xform; | ||||||
|  | 	nm.owner=p_owner; | ||||||
|  | 	navpoly_map[id]=nm; | ||||||
|  | 
 | ||||||
|  | 	_navpoly_link(id); | ||||||
|  | 
 | ||||||
|  | 	return id; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Navigation2D::navpoly_set_transform(int p_id, const Matrix32& p_xform){ | ||||||
|  | 
 | ||||||
|  | 	ERR_FAIL_COND(!navpoly_map.has(p_id)); | ||||||
|  | 	NavMesh &nm=navpoly_map[p_id]; | ||||||
|  | 	if (nm.xform==p_xform) | ||||||
|  | 		return; //bleh
 | ||||||
|  | 	_navpoly_unlink(p_id); | ||||||
|  | 	nm.xform=p_xform; | ||||||
|  | 	_navpoly_link(p_id); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | void Navigation2D::navpoly_remove(int p_id){ | ||||||
|  | 
 | ||||||
|  | 	ERR_FAIL_COND(!navpoly_map.has(p_id)); | ||||||
|  | 	_navpoly_unlink(p_id); | ||||||
|  | 	navpoly_map.erase(p_id); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | #if 0 | ||||||
|  | void Navigation2D::_clip_path(Vector<Vector2>& path, Polygon *from_poly, const Vector2& p_to_point, Polygon* p_to_poly) { | ||||||
|  | 
 | ||||||
|  | 	Vector2 from = path[path.size()-1]; | ||||||
|  | 
 | ||||||
|  | 	if (from.distance_to(p_to_point)<CMP_EPSILON) | ||||||
|  | 		return; | ||||||
|  | 	Plane cut_plane; | ||||||
|  | 	cut_plane.normal = (from-p_to_point).cross(up); | ||||||
|  | 	if (cut_plane.normal==Vector2()) | ||||||
|  | 		return; | ||||||
|  | 	cut_plane.normal.normalize(); | ||||||
|  | 	cut_plane.d = cut_plane.normal.dot(from); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	while(from_poly!=p_to_poly) { | ||||||
|  | 
 | ||||||
|  | 		int pe = from_poly->prev_edge; | ||||||
|  | 		Vector2 a = _get_vertex(from_poly->edges[pe].point); | ||||||
|  | 		Vector2 b = _get_vertex(from_poly->edges[(pe+1)%from_poly->edges.size()].point); | ||||||
|  | 
 | ||||||
|  | 		from_poly=from_poly->edges[pe].C; | ||||||
|  | 		ERR_FAIL_COND(!from_poly); | ||||||
|  | 
 | ||||||
|  | 		if (a.distance_to(b)>CMP_EPSILON) { | ||||||
|  | 
 | ||||||
|  | 			Vector2 inters; | ||||||
|  | 			if (cut_plane.intersects_segment(a,b,&inters)) { | ||||||
|  | 				if (inters.distance_to(p_to_point)>CMP_EPSILON && inters.distance_to(path[path.size()-1])>CMP_EPSILON) { | ||||||
|  | 					path.push_back(inters); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vector2& p_end, bool p_optimize) { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	Polygon *begin_poly=NULL; | ||||||
|  | 	Polygon *end_poly=NULL; | ||||||
|  | 	Vector2 begin_point; | ||||||
|  | 	Vector2 end_point; | ||||||
|  | 	float begin_d=1e20; | ||||||
|  | 	float end_d=1e20; | ||||||
|  | 
 | ||||||
|  | 	//look for point inside triangle
 | ||||||
|  | 
 | ||||||
|  | 	for (Map<int,NavMesh>::Element*E=navpoly_map.front();E;E=E->next()) { | ||||||
|  | 
 | ||||||
|  | 		if (!E->get().linked) | ||||||
|  | 			continue; | ||||||
|  | 		for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 			Polygon &p=F->get(); | ||||||
|  | 			if (begin_d || end_d) { | ||||||
|  | 				for(int i=2;i<p.edges.size();i++) { | ||||||
|  | 
 | ||||||
|  | 					if (begin_d>0) { | ||||||
|  | 
 | ||||||
|  | 						if (Geometry::is_point_in_triangle(p_start,_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point))) { | ||||||
|  | 
 | ||||||
|  | 							begin_poly=&p; | ||||||
|  | 							begin_point=p_start; | ||||||
|  | 							begin_d=0; | ||||||
|  | 							if (end_d==0) | ||||||
|  | 								break; | ||||||
|  | 
 | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (end_d>0) { | ||||||
|  | 
 | ||||||
|  | 						if (Geometry::is_point_in_triangle(p_end,_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point))) { | ||||||
|  | 
 | ||||||
|  | 							end_poly=&p; | ||||||
|  | 							end_point=p_end; | ||||||
|  | 							end_d=0; | ||||||
|  | 							if (begin_d==0) | ||||||
|  | 								break; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			p.prev_edge=-1; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	//start or end not inside triangle.. look for closest segment :|
 | ||||||
|  | 	if (begin_d || end_d) { | ||||||
|  | 		for (Map<int,NavMesh>::Element*E=navpoly_map.front();E;E=E->next()) { | ||||||
|  | 
 | ||||||
|  | 			if (!E->get().linked) | ||||||
|  | 				continue; | ||||||
|  | 			for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) { | ||||||
|  | 
 | ||||||
|  | 				Polygon &p=F->get(); | ||||||
|  | 				int es = p.edges.size(); | ||||||
|  | 				for(int i=0;i<es;i++) { | ||||||
|  | 
 | ||||||
|  | 					Vector2 edge[2]={ | ||||||
|  | 						_get_vertex(p.edges[i].point), | ||||||
|  | 						_get_vertex(p.edges[(i+1)%es].point) | ||||||
|  | 					}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 					if (begin_d>0) { | ||||||
|  | 						Vector2 spoint=Geometry::get_closest_point_to_segment_2d(p_start,edge); | ||||||
|  | 						float d = spoint.distance_to(p_start); | ||||||
|  | 						if (d<begin_d) { | ||||||
|  | 							begin_poly=&p; | ||||||
|  | 							begin_point=spoint; | ||||||
|  | 							begin_d=d; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (end_d>0) { | ||||||
|  | 						Vector2 spoint=Geometry::get_closest_point_to_segment_2d(p_end,edge); | ||||||
|  | 						float d = spoint.distance_to(p_end); | ||||||
|  | 						if (d<end_d) { | ||||||
|  | 							end_poly=&p; | ||||||
|  | 							end_point=spoint; | ||||||
|  | 							end_d=d; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!begin_poly || !end_poly) { | ||||||
|  | 
 | ||||||
|  | 		//print_line("No Path Path");
 | ||||||
|  | 		return Vector<Vector2>(); //no path
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (begin_poly==end_poly) { | ||||||
|  | 
 | ||||||
|  | 		Vector<Vector2> path; | ||||||
|  | 		path.resize(2); | ||||||
|  | 		path[0]=begin_point; | ||||||
|  | 		path[1]=end_point; | ||||||
|  | 		//print_line("Direct Path");
 | ||||||
|  | 		return path; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	bool found_route=false; | ||||||
|  | 
 | ||||||
|  | 	List<Polygon*> open_list; | ||||||
|  | 
 | ||||||
|  | 	begin_poly->entry=p_start; | ||||||
|  | 
 | ||||||
|  | 	for(int i=0;i<begin_poly->edges.size();i++) { | ||||||
|  | 
 | ||||||
|  | 		if (begin_poly->edges[i].C) { | ||||||
|  | 
 | ||||||
|  | 			begin_poly->edges[i].C->prev_edge=begin_poly->edges[i].C_edge; | ||||||
|  | #ifdef USE_ENTRY_POINT | ||||||
|  | 			Vector2 edge[2]={ | ||||||
|  | 				_get_vertex(begin_poly->edges[i].point), | ||||||
|  | 				_get_vertex(begin_poly->edges[(i+1)%begin_poly->edges.size()].point) | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			Vector2 entry = Geometry::get_closest_point_to_segment_2d(begin_poly->entry,edge); | ||||||
|  | 			begin_poly->edges[i].C->distance = begin_poly->entry.distance_to(entry); | ||||||
|  | 			begin_poly->edges[i].C->entry=entry; | ||||||
|  | #else | ||||||
|  | 			begin_poly->edges[i].C->distance=begin_poly->center.distance_to(begin_poly->edges[i].C->center); | ||||||
|  | #endif | ||||||
|  | 			open_list.push_back(begin_poly->edges[i].C); | ||||||
|  | 
 | ||||||
|  | 			if (begin_poly->edges[i].C==end_poly) { | ||||||
|  | 				found_route=true; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	while(!found_route) { | ||||||
|  | 
 | ||||||
|  | 		if (open_list.size()==0) { | ||||||
|  | 		//	print_line("NOU OPEN LIST");
 | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		//check open list
 | ||||||
|  | 
 | ||||||
|  | 		List<Polygon*>::Element *least_cost_poly=NULL; | ||||||
|  | 		float least_cost=1e30; | ||||||
|  | 
 | ||||||
|  | 		//this could be faster (cache previous results)
 | ||||||
|  | 		for (List<Polygon*>::Element *E=open_list.front();E;E=E->next()) { | ||||||
|  | 
 | ||||||
|  | 			Polygon *p=E->get(); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 			float cost=p->distance; | ||||||
|  | 			cost+=p->center.distance_to(end_point); | ||||||
|  | 
 | ||||||
|  | 			if (cost<least_cost) { | ||||||
|  | 
 | ||||||
|  | 				least_cost_poly=E; | ||||||
|  | 				least_cost=cost; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 		Polygon *p=least_cost_poly->get(); | ||||||
|  | 		//open the neighbours for search
 | ||||||
|  | 		int es = p->edges.size(); | ||||||
|  | 
 | ||||||
|  | 		for(int i=0;i<es;i++) { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 			Polygon::Edge &e=p->edges[i]; | ||||||
|  | 
 | ||||||
|  | 			if (!e.C) | ||||||
|  | 				continue; | ||||||
|  | 
 | ||||||
|  | #ifdef USE_ENTRY_POINT | ||||||
|  | 			Vector2 edge[2]={ | ||||||
|  | 				_get_vertex(p->edges[i].point), | ||||||
|  | 				_get_vertex(p->edges[(i+1)%es].point) | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			Vector2 edge_entry = Geometry::get_closest_point_to_segment_2d(p->entry,edge); | ||||||
|  | 			float distance = p->entry.distance_to(edge_entry) + p->distance; | ||||||
|  | 
 | ||||||
|  | #else | ||||||
|  | 
 | ||||||
|  | 			float distance = p->center.distance_to(e.C->center) + p->distance; | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 			if (e.C->prev_edge!=-1) { | ||||||
|  | 				//oh this was visited already, can we win the cost?
 | ||||||
|  | 
 | ||||||
|  | 				if (e.C->distance>distance) { | ||||||
|  | 
 | ||||||
|  | 					e.C->prev_edge=e.C_edge; | ||||||
|  | 					e.C->distance=distance; | ||||||
|  | #ifdef USE_ENTRY_POINT | ||||||
|  | 					e.C->entry=edge_entry; | ||||||
|  | #endif | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				//add to open neighbours
 | ||||||
|  | 
 | ||||||
|  | 				e.C->prev_edge=e.C_edge; | ||||||
|  | 				e.C->distance=distance; | ||||||
|  | #ifdef USE_ENTRY_POINT | ||||||
|  | 				e.C->entry=edge_entry; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 				open_list.push_back(e.C); | ||||||
|  | 
 | ||||||
|  | 				if (e.C==end_poly) { | ||||||
|  | 					//oh my reached end! stop algorithm
 | ||||||
|  | 					found_route=true; | ||||||
|  | 					break; | ||||||
|  | 
 | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (found_route) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		open_list.erase(least_cost_poly); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (found_route) { | ||||||
|  | 
 | ||||||
|  | 		Vector<Vector2> path; | ||||||
|  | 
 | ||||||
|  | 		if (p_optimize) { | ||||||
|  | 			//string pulling
 | ||||||
|  | 
 | ||||||
|  | 			Polygon *apex_poly=end_poly; | ||||||
|  | 			Vector2 apex_point=end_point; | ||||||
|  | 			Vector2 portal_left=apex_point; | ||||||
|  | 			Vector2 portal_right=apex_point; | ||||||
|  | 			Polygon *left_poly=end_poly; | ||||||
|  | 			Polygon *right_poly=end_poly; | ||||||
|  | 			Polygon *p=end_poly; | ||||||
|  | 			path.push_back(end_point); | ||||||
|  | 
 | ||||||
|  | 			while(p) { | ||||||
|  | 
 | ||||||
|  | 				Vector2 left; | ||||||
|  | 				Vector2 right; | ||||||
|  | 
 | ||||||
|  | //#define CLOCK_TANGENT(m_a,m_b,m_c) ( ((m_a)-(m_c)).cross((m_a)-(m_b)) )
 | ||||||
|  | #define CLOCK_TANGENT(m_a,m_b,m_c) ((((m_a).x - (m_c).x) * ((m_b).y - (m_c).y) - ((m_b).x - (m_c).x) * ((m_a).y - (m_c).y))) | ||||||
|  | 
 | ||||||
|  | 				if (p==begin_poly) { | ||||||
|  | 					left=begin_point; | ||||||
|  | 					right=begin_point; | ||||||
|  | 				} else { | ||||||
|  | 					int prev = p->prev_edge; | ||||||
|  | 					int prev_n = (p->prev_edge+1)%p->edges.size(); | ||||||
|  | 					left = _get_vertex(p->edges[prev].point); | ||||||
|  | 					right = _get_vertex(p->edges[prev_n].point); | ||||||
|  | 
 | ||||||
|  | 					if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5) < 0){ | ||||||
|  | 						SWAP(left,right); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				bool skip=false; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 				if (CLOCK_TANGENT(apex_point,portal_left,left) >= 0){ | ||||||
|  | 					//process
 | ||||||
|  | 					if (portal_left==apex_point || CLOCK_TANGENT(apex_point,left,portal_right) > 0) { | ||||||
|  | 						left_poly=p; | ||||||
|  | 						portal_left=left; | ||||||
|  | 					} else { | ||||||
|  | 
 | ||||||
|  | 						//_clip_path(path,apex_poly,portal_right,right_poly);
 | ||||||
|  | 
 | ||||||
|  | 						apex_point=portal_right; | ||||||
|  | 						p=right_poly; | ||||||
|  | 						left_poly=p; | ||||||
|  | 						apex_poly=p; | ||||||
|  | 						portal_left=apex_point; | ||||||
|  | 						portal_right=apex_point; | ||||||
|  | 						path.push_back(apex_point); | ||||||
|  | 						skip=true; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (!skip && CLOCK_TANGENT(apex_point,portal_right,right) <= 0){ | ||||||
|  | 					//process
 | ||||||
|  | 					if (portal_right==apex_point || CLOCK_TANGENT(apex_point,right,portal_left) < 0) { | ||||||
|  | 						right_poly=p; | ||||||
|  | 						portal_right=right; | ||||||
|  | 					} else { | ||||||
|  | 
 | ||||||
|  | 						//_clip_path(path,apex_poly,portal_left,left_poly);
 | ||||||
|  | 
 | ||||||
|  | 						apex_point=portal_left; | ||||||
|  | 						p=left_poly; | ||||||
|  | 						right_poly=p; | ||||||
|  | 						apex_poly=p; | ||||||
|  | 						portal_right=apex_point; | ||||||
|  | 						portal_left=apex_point; | ||||||
|  | 						path.push_back(apex_point); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (p!=begin_poly) | ||||||
|  | 					p=p->edges[p->prev_edge].C; | ||||||
|  | 				else | ||||||
|  | 					p=NULL; | ||||||
|  | 
 | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (path[path.size()-1]!=begin_point) | ||||||
|  | 				path.push_back(begin_point); | ||||||
|  | 
 | ||||||
|  | 			path.invert(); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 		} else { | ||||||
|  | 			//midpoints
 | ||||||
|  | 			Polygon *p=end_poly; | ||||||
|  | 
 | ||||||
|  | 			path.push_back(end_point); | ||||||
|  | 			while(true) { | ||||||
|  | 				int prev = p->prev_edge; | ||||||
|  | 				int prev_n = (p->prev_edge+1)%p->edges.size(); | ||||||
|  | 				Vector2 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point))*0.5; | ||||||
|  | 				path.push_back(point); | ||||||
|  | 				p = p->edges[prev].C; | ||||||
|  | 				if (p==begin_poly) | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			path.push_back(begin_point); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 			path.invert();; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return path; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	return Vector<Vector2>(); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Vector2 Navigation2D::get_closest_point(const Vector2& p_point) { | ||||||
|  | 
 | ||||||
|  | 	Vector2 closest_point=Vector2(); | ||||||
|  | 	float closest_point_d=1e20; | ||||||
|  | 
 | ||||||
|  | 	for (Map<int,NavMesh>::Element*E=navpoly_map.front();E;E=E->next()) { | ||||||
|  | 
 | ||||||
|  | 		if (!E->get().linked) | ||||||
|  | 			continue; | ||||||
|  | 		for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) { | ||||||
|  | 
 | ||||||
|  | 			Polygon &p=F->get(); | ||||||
|  | 			for(int i=2;i<p.edges.size();i++) { | ||||||
|  | 
 | ||||||
|  | 				if (Geometry::is_point_in_triangle(p_point,_get_vertex(p.edges[0].point),_get_vertex(p.edges[i-1].point),_get_vertex(p.edges[i].point))) { | ||||||
|  | 
 | ||||||
|  | 					return p_point; //inside triangle, nothing else to discuss
 | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for (Map<int,NavMesh>::Element*E=navpoly_map.front();E;E=E->next()) { | ||||||
|  | 
 | ||||||
|  | 		if (!E->get().linked) | ||||||
|  | 			continue; | ||||||
|  | 		for(List<Polygon>::Element *F=E->get().polygons.front();F;F=F->next()) { | ||||||
|  | 
 | ||||||
|  | 			Polygon &p=F->get(); | ||||||
|  | 			int es = p.edges.size(); | ||||||
|  | 			for(int i=0;i<es;i++) { | ||||||
|  | 
 | ||||||
|  | 				Vector2 edge[2]={ | ||||||
|  | 					_get_vertex(p.edges[i].point), | ||||||
|  | 					_get_vertex(p.edges[(i+1)%es].point) | ||||||
|  | 				}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 				Vector2 spoint=Geometry::get_closest_point_to_segment_2d(p_point,edge); | ||||||
|  | 				float d = spoint.distance_squared_to(p_point); | ||||||
|  | 				if (d<closest_point_d) { | ||||||
|  | 
 | ||||||
|  | 					closest_point=spoint; | ||||||
|  | 					closest_point_d=d; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return closest_point; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void Navigation2D::_bind_methods() { | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("navpoly_create","mesh:NavigationPolygon","xform","owner"),&Navigation2D::navpoly_create,DEFVAL(Variant())); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("navpoly_set_transform","id","xform"),&Navigation2D::navpoly_set_transform); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("navpoly_remove","id"),&Navigation2D::navpoly_remove); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_simple_path","start","end","optimize"),&Navigation2D::get_simple_path,DEFVAL(true)); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_closest_point","to_point"),&Navigation2D::get_closest_point); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Navigation2D::Navigation2D() { | ||||||
|  | 
 | ||||||
|  | 	ERR_FAIL_COND( sizeof(Point)!=8 ); | ||||||
|  | 	cell_size=1; // one pixel
 | ||||||
|  | 	last_id=1; | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										138
									
								
								scene/2d/navigation2d.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								scene/2d/navigation2d.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,138 @@ | ||||||
|  | #ifndef NAVIGATION_2D_H | ||||||
|  | #define NAVIGATION_2D_H | ||||||
|  | 
 | ||||||
|  | #include "scene/2d/node_2d.h" | ||||||
|  | #include "scene/2d/navigation_polygon.h" | ||||||
|  | 
 | ||||||
|  | class Navigation2D : public Node2D { | ||||||
|  | 
 | ||||||
|  | 	OBJ_TYPE( Navigation2D, Node2D); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	union Point { | ||||||
|  | 
 | ||||||
|  | 		struct { | ||||||
|  | 			int64_t x:32; | ||||||
|  | 			int64_t y:32; | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 		uint64_t key; | ||||||
|  | 		bool operator<(const Point& p_key) const { return key < p_key.key; } | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	struct EdgeKey { | ||||||
|  | 
 | ||||||
|  | 		Point a; | ||||||
|  | 		Point b; | ||||||
|  | 
 | ||||||
|  | 		bool operator<(const EdgeKey& p_key) const { | ||||||
|  | 			return (a.key==p_key.a.key)?(b.key<p_key.b.key):(a.key<p_key.a.key); | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 		EdgeKey(const Point& p_a=Point(),const Point& p_b=Point()) { | ||||||
|  | 			a=p_a; | ||||||
|  | 			b=p_b; | ||||||
|  | 			if (a.key > b.key) { | ||||||
|  | 				SWAP(a,b); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	struct NavMesh; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	struct Polygon { | ||||||
|  | 
 | ||||||
|  | 		struct Edge { | ||||||
|  | 			Point point; | ||||||
|  | 			Polygon *C; //connection
 | ||||||
|  | 			int C_edge; | ||||||
|  | 			Edge() { C=NULL; C_edge=-1; } | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 		Vector<Edge> edges; | ||||||
|  | 
 | ||||||
|  | 		Vector2 center; | ||||||
|  | 		Vector2 entry; | ||||||
|  | 
 | ||||||
|  | 		float distance; | ||||||
|  | 		int prev_edge; | ||||||
|  | 
 | ||||||
|  | 		NavMesh *owner; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	struct Connection { | ||||||
|  | 
 | ||||||
|  | 		Polygon *A; | ||||||
|  | 		int A_edge; | ||||||
|  | 		Polygon *B; | ||||||
|  | 		int B_edge; | ||||||
|  | 		Connection() { A=NULL; B=NULL; A_edge=-1; B_edge=-1;} | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	Map<EdgeKey,Connection> connections; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	struct NavMesh { | ||||||
|  | 
 | ||||||
|  | 		Object *owner; | ||||||
|  | 		Matrix32 xform; | ||||||
|  | 		bool linked; | ||||||
|  | 		Ref<NavigationPolygon> navpoly; | ||||||
|  | 		List<Polygon> polygons; | ||||||
|  | 
 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	_FORCE_INLINE_ Point _get_point(const Vector2& p_pos) const { | ||||||
|  | 
 | ||||||
|  | 		int x = int(Math::floor(p_pos.x/cell_size)); | ||||||
|  | 		int y = int(Math::floor(p_pos.y/cell_size)); | ||||||
|  | 
 | ||||||
|  | 		Point p; | ||||||
|  | 		p.key=0; | ||||||
|  | 		p.x=x; | ||||||
|  | 		p.y=y; | ||||||
|  | 		return p; | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	_FORCE_INLINE_ Vector2 _get_vertex(const Point& p_point) const { | ||||||
|  | 
 | ||||||
|  | 		return Vector2(p_point.x,p_point.y)*cell_size; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	void _navpoly_link(int p_id); | ||||||
|  | 	void _navpoly_unlink(int p_id); | ||||||
|  | 
 | ||||||
|  | 	float cell_size; | ||||||
|  | 	Map<int,NavMesh> navpoly_map; | ||||||
|  | 	int last_id; | ||||||
|  | #if 0 | ||||||
|  | 	void _clip_path(Vector<Vector2>& path,Polygon *from_poly, const Vector2& p_to_point, Polygon* p_to_poly); | ||||||
|  | #endif | ||||||
|  | protected: | ||||||
|  | 
 | ||||||
|  | 	static void _bind_methods(); | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 	//API should be as dynamic as possible
 | ||||||
|  | 	int navpoly_create(const Ref<NavigationPolygon>& p_mesh,const Matrix32& p_xform,Object* p_owner=NULL); | ||||||
|  | 	void navpoly_set_transform(int p_id, const Matrix32& p_xform); | ||||||
|  | 	void navpoly_remove(int p_id); | ||||||
|  | 
 | ||||||
|  | 	Vector<Vector2> get_simple_path(const Vector2& p_start, const Vector2& p_end,bool p_optimize=true); | ||||||
|  | 	Vector2 get_closest_point(const Vector2& p_point); | ||||||
|  | 
 | ||||||
|  | 	Navigation2D(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #endif // Navigation2D2D_H
 | ||||||
							
								
								
									
										450
									
								
								scene/2d/navigation_polygon.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										450
									
								
								scene/2d/navigation_polygon.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,450 @@ | ||||||
|  | #include "navigation_polygon.h" | ||||||
|  | #include "navigation2d.h" | ||||||
|  | #include "triangulator.h" | ||||||
|  | #include "core_string_names.h" | ||||||
|  | 
 | ||||||
|  | void NavigationPolygon::set_vertices(const DVector<Vector2>& p_vertices) { | ||||||
|  | 
 | ||||||
|  | 	vertices=p_vertices; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DVector<Vector2> NavigationPolygon::get_vertices() const{ | ||||||
|  | 
 | ||||||
|  | 	return vertices; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void NavigationPolygon::_set_polygons(const Array& p_array) { | ||||||
|  | 
 | ||||||
|  | 	polygons.resize(p_array.size()); | ||||||
|  | 	for(int i=0;i<p_array.size();i++) { | ||||||
|  | 		polygons[i].indices=p_array[i]; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Array NavigationPolygon::_get_polygons() const { | ||||||
|  | 
 | ||||||
|  | 	Array ret; | ||||||
|  | 	ret.resize(polygons.size()); | ||||||
|  | 	for(int i=0;i<ret.size();i++) { | ||||||
|  | 		ret[i]=polygons[i].indices; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NavigationPolygon::_set_outlines(const Array& p_array) { | ||||||
|  | 
 | ||||||
|  | 	outlines.resize(p_array.size()); | ||||||
|  | 	for(int i=0;i<p_array.size();i++) { | ||||||
|  | 		outlines[i]=p_array[i]; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Array NavigationPolygon::_get_outlines() const { | ||||||
|  | 
 | ||||||
|  | 	Array ret; | ||||||
|  | 	ret.resize(outlines.size()); | ||||||
|  | 	for(int i=0;i<ret.size();i++) { | ||||||
|  | 		ret[i]=outlines[i]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void NavigationPolygon::add_polygon(const Vector<int>& p_polygon){ | ||||||
|  | 
 | ||||||
|  | 	Polygon polygon; | ||||||
|  | 	polygon.indices=p_polygon; | ||||||
|  | 	polygons.push_back(polygon); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NavigationPolygon::add_outline_at_index(const DVector<Vector2>& p_outline,int p_index) { | ||||||
|  | 
 | ||||||
|  | 	outlines.insert(p_index,p_outline); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int NavigationPolygon::get_polygon_count() const{ | ||||||
|  | 
 | ||||||
|  | 	return polygons.size(); | ||||||
|  | } | ||||||
|  | Vector<int> NavigationPolygon::get_polygon(int p_idx){ | ||||||
|  | 
 | ||||||
|  | 	ERR_FAIL_INDEX_V(p_idx,polygons.size(),Vector<int>()); | ||||||
|  | 	return polygons[p_idx].indices; | ||||||
|  | } | ||||||
|  | void NavigationPolygon::clear_polygons(){ | ||||||
|  | 
 | ||||||
|  | 	polygons.clear(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NavigationPolygon::add_outline(const DVector<Vector2>& p_outline) { | ||||||
|  | 
 | ||||||
|  | 	outlines.push_back(p_outline); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int NavigationPolygon::get_outline_count() const{ | ||||||
|  | 
 | ||||||
|  | 	return outlines.size(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NavigationPolygon::set_outline(int p_idx,const DVector<Vector2>& p_outline) { | ||||||
|  | 	ERR_FAIL_INDEX(p_idx,outlines.size()); | ||||||
|  | 	outlines[p_idx]=p_outline; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NavigationPolygon::remove_outline(int p_idx) { | ||||||
|  | 
 | ||||||
|  | 	ERR_FAIL_INDEX(p_idx,outlines.size()); | ||||||
|  | 	outlines.remove(p_idx); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DVector<Vector2> NavigationPolygon::get_outline(int p_idx) const { | ||||||
|  | 	ERR_FAIL_INDEX_V(p_idx,outlines.size(),DVector<Vector2>()); | ||||||
|  | 	return outlines[p_idx]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NavigationPolygon::clear_outlines(){ | ||||||
|  | 
 | ||||||
|  | 	outlines.clear();; | ||||||
|  | } | ||||||
|  | void NavigationPolygon::make_polygons_from_outlines(){ | ||||||
|  | 
 | ||||||
|  | 	List<TriangulatorPoly> in_poly,out_poly; | ||||||
|  | 
 | ||||||
|  | 	Vector2 outside_point(-1e10,-1e10); | ||||||
|  | 
 | ||||||
|  | 	for(int i=0;i<outlines.size();i++) { | ||||||
|  | 
 | ||||||
|  | 		DVector<Vector2> ol = outlines[i]; | ||||||
|  | 		int olsize = ol.size(); | ||||||
|  | 		if (olsize<3) | ||||||
|  | 			continue; | ||||||
|  | 		DVector<Vector2>::Read r=ol.read(); | ||||||
|  | 		for(int j=0;j<olsize;j++) { | ||||||
|  | 			outside_point.x = MAX( r[j].x, outside_point.x ); | ||||||
|  | 			outside_point.y = MAX( r[j].y, outside_point.y ); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	outside_point+=Vector2(0.7239784,0.819238); //avoid precision issues
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	for(int i=0;i<outlines.size();i++) { | ||||||
|  | 
 | ||||||
|  | 		DVector<Vector2> ol = outlines[i]; | ||||||
|  | 		int olsize = ol.size(); | ||||||
|  | 		if (olsize<3) | ||||||
|  | 			continue; | ||||||
|  | 		DVector<Vector2>::Read r=ol.read(); | ||||||
|  | 
 | ||||||
|  | 		int interscount=0; | ||||||
|  | 		//test if this is an outer outline
 | ||||||
|  | 		for(int k=0;k<outlines.size();k++) { | ||||||
|  | 
 | ||||||
|  | 			if (i==k) | ||||||
|  | 				continue; //no self intersect
 | ||||||
|  | 
 | ||||||
|  | 			DVector<Vector2> ol2 = outlines[k]; | ||||||
|  | 			int olsize2 = ol2.size(); | ||||||
|  | 			if (olsize2<3) | ||||||
|  | 				continue; | ||||||
|  | 			DVector<Vector2>::Read r2=ol2.read(); | ||||||
|  | 
 | ||||||
|  | 			for(int l=0;l<olsize2;l++) { | ||||||
|  | 
 | ||||||
|  | 				if (Geometry::segment_intersects_segment_2d(r[0],outside_point,r2[l],r2[(l+1)%olsize2],NULL)) { | ||||||
|  | 					interscount++; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		bool outer = (interscount%2)==0; | ||||||
|  | 
 | ||||||
|  | 		TriangulatorPoly tp; | ||||||
|  | 		tp.Init(olsize); | ||||||
|  | 		for(int j=0;j<olsize;j++) { | ||||||
|  | 			tp[j]=r[j]; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (outer) | ||||||
|  | 			tp.SetOrientation(TRIANGULATOR_CCW); | ||||||
|  | 		else { | ||||||
|  | 			tp.SetOrientation(TRIANGULATOR_CW); | ||||||
|  | 			tp.SetHole(true); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		in_poly.push_back(tp); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	TriangulatorPartition tpart; | ||||||
|  | 	if (tpart.ConvexPartition_HM(&in_poly,&out_poly)==0) { //failed!
 | ||||||
|  | 		print_line("convex partition failed!"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	polygons.clear(); | ||||||
|  | 	vertices.resize(0); | ||||||
|  | 
 | ||||||
|  | 	Map<Vector2,int> points; | ||||||
|  | 	for(List<TriangulatorPoly>::Element*I = out_poly.front();I;I=I->next()) { | ||||||
|  | 
 | ||||||
|  | 		TriangulatorPoly& tp = I->get(); | ||||||
|  | 
 | ||||||
|  | 		struct Polygon p; | ||||||
|  | 
 | ||||||
|  | 		for(int i=0;i<tp.GetNumPoints();i++) { | ||||||
|  | 
 | ||||||
|  | 			Map<Vector2,int>::Element *E=points.find(tp[i]); | ||||||
|  | 			if (!E) { | ||||||
|  | 				E=points.insert(tp[i],vertices.size()); | ||||||
|  | 				vertices.push_back(tp[i]); | ||||||
|  | 			} | ||||||
|  | 			p.indices.push_back(E->get()); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		polygons.push_back(p); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	emit_signal(CoreStringNames::get_singleton()->changed); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void NavigationPolygon::_bind_methods() { | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_vertices","vertices"),&NavigationPolygon::set_vertices); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_vertices"),&NavigationPolygon::get_vertices); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("add_polygon","polygon"),&NavigationPolygon::add_polygon); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_polygon_count"),&NavigationPolygon::get_polygon_count); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_polygon","idx"),&NavigationPolygon::get_polygon); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("clear_polygons"),&NavigationPolygon::clear_polygons); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("add_outline","outline"),&NavigationPolygon::add_outline); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("add_outline_at_index","outline","index"),&NavigationPolygon::add_outline_at_index); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_outline_count"),&NavigationPolygon::get_outline_count); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_outline","idx","outline"),&NavigationPolygon::set_outline); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_outline","idx"),&NavigationPolygon::get_outline); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("remove_outline","idx"),&NavigationPolygon::remove_outline); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("clear_outlines"),&NavigationPolygon::clear_outlines); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("make_polygons_from_outlines"),&NavigationPolygon::make_polygons_from_outlines); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("_set_polygons","polygons"),&NavigationPolygon::_set_polygons); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("_get_polygons"),&NavigationPolygon::_get_polygons); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("_set_outlines","outlines"),&NavigationPolygon::_set_outlines); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("_get_outlines"),&NavigationPolygon::_get_outlines); | ||||||
|  | 
 | ||||||
|  | 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3_ARRAY,"vertices",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_vertices"),_SCS("get_vertices")); | ||||||
|  | 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"polygons",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_polygons"),_SCS("_get_polygons")); | ||||||
|  | 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"outlines",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_outlines"),_SCS("_get_outlines")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | NavigationPolygon::NavigationPolygon() { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NavigationPolygonInstance::set_enabled(bool p_enabled) { | ||||||
|  | 
 | ||||||
|  | 	if (enabled==p_enabled) | ||||||
|  | 		return; | ||||||
|  | 	enabled=p_enabled; | ||||||
|  | 
 | ||||||
|  | 	if (!is_inside_tree()) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (!enabled) { | ||||||
|  | 
 | ||||||
|  | 		if (nav_id!=-1) { | ||||||
|  | 			navigation->navpoly_remove(nav_id); | ||||||
|  | 			nav_id=-1; | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 
 | ||||||
|  | 		if (navigation) { | ||||||
|  | 
 | ||||||
|  | 			if (navpoly.is_valid()) { | ||||||
|  | 
 | ||||||
|  | 				nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (get_tree()->is_editor_hint()) | ||||||
|  | 		update(); | ||||||
|  | 
 | ||||||
|  | //	update_gizmo();
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool NavigationPolygonInstance::is_enabled() const { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	return enabled; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /////////////////////////////
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void NavigationPolygonInstance::_notification(int p_what) { | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	switch(p_what) { | ||||||
|  | 		case NOTIFICATION_ENTER_TREE: { | ||||||
|  | 
 | ||||||
|  | 			Node2D *c=this; | ||||||
|  | 			while(c) { | ||||||
|  | 
 | ||||||
|  | 				navigation=c->cast_to<Navigation2D>(); | ||||||
|  | 				if (navigation) { | ||||||
|  | 
 | ||||||
|  | 					if (enabled && navpoly.is_valid()) { | ||||||
|  | 
 | ||||||
|  | 						nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				c=c->get_parent()->cast_to<Node2D>(); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		} break; | ||||||
|  | 		case NOTIFICATION_TRANSFORM_CHANGED: { | ||||||
|  | 
 | ||||||
|  | 			if (navigation && nav_id!=-1) { | ||||||
|  | 				navigation->navpoly_set_transform(nav_id,get_relative_transform(navigation)); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		} break; | ||||||
|  | 		case NOTIFICATION_EXIT_TREE: { | ||||||
|  | 
 | ||||||
|  | 			if (navigation) { | ||||||
|  | 
 | ||||||
|  | 				if (nav_id!=-1) { | ||||||
|  | 					navigation->navpoly_remove(nav_id); | ||||||
|  | 					nav_id=-1; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			navigation=NULL; | ||||||
|  | 		} break; | ||||||
|  | 		case NOTIFICATION_DRAW: { | ||||||
|  | 
 | ||||||
|  | 			if (is_inside_tree() && get_tree()->is_editor_hint() && navpoly.is_valid()) { | ||||||
|  | 
 | ||||||
|  | 				DVector<Vector2> verts=navpoly->get_vertices(); | ||||||
|  | 				int vsize = verts.size(); | ||||||
|  | 				if (vsize<3) | ||||||
|  | 					return; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 				Color color; | ||||||
|  | 				if (enabled) { | ||||||
|  | 					color=Color(0.1,0.8,1.0,0.4); | ||||||
|  | 				} else { | ||||||
|  | 					color=Color(1.0,0.8,0.1,0.4); | ||||||
|  | 				} | ||||||
|  | 				Vector<Color> colors; | ||||||
|  | 				Vector<Vector2> vertices; | ||||||
|  | 				vertices.resize(vsize); | ||||||
|  | 				colors.resize(vsize); | ||||||
|  | 				{ | ||||||
|  | 					DVector<Vector2>::Read vr = verts.read(); | ||||||
|  | 					for(int i=0;i<vsize;i++) { | ||||||
|  | 						vertices[i]=vr[i]; | ||||||
|  | 						colors[i]=color; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				Vector<int> indices; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 				for(int i=0;i<navpoly->get_polygon_count();i++) { | ||||||
|  | 					Vector<int> polygon = navpoly->get_polygon(i); | ||||||
|  | 
 | ||||||
|  | 					for(int j=2;j<polygon.size();j++) { | ||||||
|  | 
 | ||||||
|  | 						int kofs[3]={0,j-1,j}; | ||||||
|  | 						for(int k=0;k<3;k++) { | ||||||
|  | 
 | ||||||
|  | 							int idx = polygon[ kofs[k] ]; | ||||||
|  | 							ERR_FAIL_INDEX(idx,vsize); | ||||||
|  | 							indices.push_back(idx); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(),indices,vertices,colors); | ||||||
|  | 
 | ||||||
|  | 			} | ||||||
|  | 		} break; | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void NavigationPolygonInstance::set_navigation_polygon(const Ref<NavigationPolygon>& p_navpoly) { | ||||||
|  | 
 | ||||||
|  | 	if (p_navpoly==navpoly) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (navigation && nav_id!=-1) { | ||||||
|  | 		navigation->navpoly_remove(nav_id); | ||||||
|  | 		nav_id=-1; | ||||||
|  | 	} | ||||||
|  | 	if (navpoly.is_valid()) { | ||||||
|  | 		navpoly->disconnect(CoreStringNames::get_singleton()->changed,this,"_navpoly_changed"); | ||||||
|  | 	} | ||||||
|  | 	navpoly=p_navpoly; | ||||||
|  | 
 | ||||||
|  | 	if (navpoly.is_valid()) { | ||||||
|  | 		navpoly->connect(CoreStringNames::get_singleton()->changed,this,"_navpoly_changed"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (navigation && navpoly.is_valid() && enabled) { | ||||||
|  | 		nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this); | ||||||
|  | 	} | ||||||
|  | 	//update_gizmo();
 | ||||||
|  | 	_change_notify("navpoly"); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Ref<NavigationPolygon> NavigationPolygonInstance::get_navigation_polygon() const{ | ||||||
|  | 
 | ||||||
|  | 	return navpoly; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NavigationPolygonInstance::_navpoly_changed() { | ||||||
|  | 
 | ||||||
|  | 	if (is_inside_tree() && get_tree()->is_editor_hint()) | ||||||
|  | 		update(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NavigationPolygonInstance::_bind_methods() { | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_navigation_polygon","navpoly"),&NavigationPolygonInstance::set_navigation_polygon); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("get_navigation_polygon"),&NavigationPolygonInstance::get_navigation_polygon); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&NavigationPolygonInstance::set_enabled); | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("is_enabled"),&NavigationPolygonInstance::is_enabled); | ||||||
|  | 
 | ||||||
|  | 	ObjectTypeDB::bind_method(_MD("_navpoly_changed"),&NavigationPolygonInstance::_navpoly_changed); | ||||||
|  | 
 | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"navpoly",PROPERTY_HINT_RESOURCE_TYPE,"NavigationPolygon"),_SCS("set_navigation_polygon"),_SCS("get_navigation_polygon")); | ||||||
|  | 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | NavigationPolygonInstance::NavigationPolygonInstance() { | ||||||
|  | 
 | ||||||
|  | 	navigation=NULL; | ||||||
|  | 	nav_id=-1; | ||||||
|  | 	enabled=true; | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										84
									
								
								scene/2d/navigation_polygon.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								scene/2d/navigation_polygon.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,84 @@ | ||||||
|  | #ifndef NAVIGATION_POLYGON_H | ||||||
|  | #define NAVIGATION_POLYGON_H | ||||||
|  | 
 | ||||||
|  | #include "scene/2d/node_2d.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class NavigationPolygon : public Resource  { | ||||||
|  | 
 | ||||||
|  | 	OBJ_TYPE( NavigationPolygon, Resource ); | ||||||
|  | 
 | ||||||
|  | 	DVector<Vector2> vertices; | ||||||
|  | 	struct Polygon { | ||||||
|  | 		Vector<int> indices; | ||||||
|  | 	}; | ||||||
|  | 	Vector<Polygon> polygons; | ||||||
|  | 	Vector< DVector<Vector2> > outlines; | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  | 
 | ||||||
|  | 	static void _bind_methods(); | ||||||
|  | 
 | ||||||
|  | 	void _set_polygons(const Array& p_array); | ||||||
|  | 	Array _get_polygons() const; | ||||||
|  | 
 | ||||||
|  | 	void _set_outlines(const Array& p_array); | ||||||
|  | 	Array _get_outlines() const; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	void set_vertices(const DVector<Vector2>& p_vertices); | ||||||
|  | 	DVector<Vector2> get_vertices() const; | ||||||
|  | 
 | ||||||
|  | 	void add_polygon(const Vector<int>& p_polygon); | ||||||
|  | 	int get_polygon_count() const; | ||||||
|  | 
 | ||||||
|  | 	void add_outline(const DVector<Vector2>& p_outline); | ||||||
|  | 	void add_outline_at_index(const DVector<Vector2>& p_outline,int p_index); | ||||||
|  | 	void set_outline(int p_idx,const DVector<Vector2>& p_outline); | ||||||
|  | 	DVector<Vector2> get_outline(int p_idx) const; | ||||||
|  | 	void remove_outline(int p_idx); | ||||||
|  | 	int get_outline_count() const; | ||||||
|  | 
 | ||||||
|  | 	void clear_outlines(); | ||||||
|  | 	void make_polygons_from_outlines(); | ||||||
|  | 
 | ||||||
|  | 	Vector<int> get_polygon(int p_idx); | ||||||
|  | 	void clear_polygons(); | ||||||
|  | 
 | ||||||
|  | 	NavigationPolygon(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Navigation2D; | ||||||
|  | 
 | ||||||
|  | class NavigationPolygonInstance : public Node2D { | ||||||
|  | 
 | ||||||
|  | 	OBJ_TYPE(NavigationPolygonInstance,Node2D); | ||||||
|  | 
 | ||||||
|  | 	bool enabled; | ||||||
|  | 	int nav_id; | ||||||
|  | 	Navigation2D *navigation; | ||||||
|  | 	Ref<NavigationPolygon> navpoly; | ||||||
|  | 
 | ||||||
|  | 	void _navpoly_changed(); | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  | 
 | ||||||
|  | 	void _notification(int p_what); | ||||||
|  | 	static void _bind_methods(); | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 	void set_enabled(bool p_enabled); | ||||||
|  | 	bool is_enabled() const; | ||||||
|  | 
 | ||||||
|  | 	void set_navigation_polygon(const Ref<NavigationPolygon>& p_navpoly); | ||||||
|  | 	Ref<NavigationPolygon> get_navigation_polygon() const; | ||||||
|  | 
 | ||||||
|  | 	NavigationPolygonInstance(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #endif // NAVIGATIONPOLYGON_H
 | ||||||
|  | @ -317,6 +317,18 @@ int Node2D::get_z() const{ | ||||||
| 	return z; | 	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() { | 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("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::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::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")); | 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale")); | ||||||
|  |  | ||||||
|  | @ -93,6 +93,9 @@ public: | ||||||
| 	void set_z_as_relative(bool p_enabled); | 	void set_z_as_relative(bool p_enabled); | ||||||
| 	bool is_z_relative() const; | 	bool is_z_relative() const; | ||||||
| 
 | 
 | ||||||
|  | 	Matrix32 get_relative_transform(const Node *p_parent) const; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 	Matrix32 get_transform() const; | 	Matrix32 get_transform() const; | ||||||
| 
 | 
 | ||||||
| 	Node2D(); | 	Node2D(); | ||||||
|  |  | ||||||
|  | @ -29,6 +29,7 @@ | ||||||
| #include "tile_map.h" | #include "tile_map.h" | ||||||
| #include "io/marshalls.h" | #include "io/marshalls.h" | ||||||
| #include "servers/physics_2d_server.h" | #include "servers/physics_2d_server.h" | ||||||
|  | #include "method_bind_ext.inc" | ||||||
| void TileMap::_notification(int p_what) { | void TileMap::_notification(int p_what) { | ||||||
| 
 | 
 | ||||||
| 	switch(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()) { | 	for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) { | ||||||
| 
 | 
 | ||||||
| 		Quadrant &q=E->get(); | 		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; | 		Matrix32 xform; | ||||||
| 		xform.set_origin( q.pos ); | 		xform.set_origin( q.pos ); | ||||||
| 		xform = global_transform * xform; | 		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(); | 		Quadrant &q = *dirty_quadrant_list.first()->self(); | ||||||
| 
 | 
 | ||||||
| 		vs->canvas_item_clear(q.canvas_item); | 		vs->canvas_item_clear(q.canvas_item); | ||||||
| 		ps->body_clear_shapes(q.static_body); | 		ps->body_clear_shapes(q.body); | ||||||
| 		int shape_idx=0; | 		int shape_idx=0; | ||||||
| 
 | 
 | ||||||
| 		for(int i=0;i<q.cells.size();i++) { | 		for(int i=0;i<q.cells.size();i++) { | ||||||
|  | @ -225,11 +226,9 @@ void TileMap::_update_dirty_quadrants() { | ||||||
| 
 | 
 | ||||||
| 			rect.pos+=tile_ofs; | 			rect.pos+=tile_ofs; | ||||||
| 			if (r==Rect2()) { | 			if (r==Rect2()) { | ||||||
| 
 | 				tex->draw_rect(q.canvas_item,rect,false,Color(1,1,1),c.transpose); | ||||||
| 				tex->draw_rect(q.canvas_item,rect); |  | ||||||
| 			} else { | 			} else { | ||||||
| 
 | 				tex->draw_rect_region(q.canvas_item,rect,r,Color(1,1,1),c.transpose); | ||||||
| 				tex->draw_rect_region(q.canvas_item,rect,r); |  | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			Vector< Ref<Shape2D> > shapes = tile_set->tile_get_shapes(c.id); | 			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); | 					Vector2 shape_ofs = tile_set->tile_get_shape_offset(c.id); | ||||||
| 					Matrix32 xform; | 					Matrix32 xform; | ||||||
| 					xform.set_origin(offset.floor()); | 					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) { | 					if (c.flip_h) { | ||||||
| 						xform.elements[0]=-xform.elements[0]; | 						xform.elements[0].x=-xform.elements[0].x; | ||||||
| 						xform.elements[2].x+=s.x-shape_ofs.x; | 						xform.elements[1].x=-xform.elements[1].x; | ||||||
| 					} else { | 						shape_ofs.x=s.x-shape_ofs.x; | ||||||
| 
 |  | ||||||
| 						xform.elements[2].x+=shape_ofs.x; |  | ||||||
| 					} | 					} | ||||||
| 					if (c.flip_v) { | 					if (c.flip_v) { | ||||||
| 						xform.elements[1]=-xform.elements[1]; | 						xform.elements[0].y=-xform.elements[0].y; | ||||||
| 						xform.elements[2].y+=s.y-shape_ofs.y; | 						xform.elements[1].y=-xform.elements[1].y; | ||||||
| 					} else { | 						shape_ofs.y=s.y-shape_ofs.y; | ||||||
| 
 |  | ||||||
| 						xform.elements[2].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(); | 	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_parent( q.canvas_item, get_canvas_item() ); | ||||||
| 	VisualServer::get_singleton()->canvas_item_set_transform( q.canvas_item, xform ); | 	VisualServer::get_singleton()->canvas_item_set_transform( q.canvas_item, xform ); | ||||||
| 	q.static_body=Physics2DServer::get_singleton()->body_create(Physics2DServer::BODY_MODE_STATIC); | 	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.static_body,get_instance_ID()); | 	Physics2DServer::get_singleton()->body_attach_object_instance_ID(q.body,get_instance_ID()); | ||||||
| 	Physics2DServer::get_singleton()->body_set_layer_mask(q.static_body,collision_layer); | 	Physics2DServer::get_singleton()->body_set_layer_mask(q.body,collision_layer); | ||||||
| 	Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_FRICTION,friction); | 	Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_FRICTION,friction); | ||||||
| 	Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_BOUNCE,bounce); | 	Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_BOUNCE,bounce); | ||||||
| 
 | 
 | ||||||
| 	if (is_inside_tree()) { | 	if (is_inside_tree()) { | ||||||
| 		xform = get_global_transform() * xform; | 		xform = get_global_transform() * xform; | ||||||
| 		RID space = get_world_2d()->get_space(); | 		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; | 	rect_cache_dirty=true; | ||||||
| 	quadrant_order_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) { | void TileMap::_erase_quadrant(Map<PosKey,Quadrant>::Element *Q) { | ||||||
| 
 | 
 | ||||||
| 	Quadrant &q=Q->get(); | 	Quadrant &q=Q->get(); | ||||||
| 	Physics2DServer::get_singleton()->free(q.static_body); | 	Physics2DServer::get_singleton()->free(q.body); | ||||||
| 	VisualServer::get_singleton()->free(q.canvas_item); | 	VisualServer::get_singleton()->free(q.canvas_item); | ||||||
| 	if (q.dirty_list.in_list()) | 	if (q.dirty_list.in_list()) | ||||||
| 		dirty_quadrant_list.remove(&q.dirty_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); | 	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 { | 	} else { | ||||||
| 		ERR_FAIL_COND(!Q); // quadrant should exist...
 | 		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
 | 			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.id=p_tile; | ||||||
| 	c.flip_h=p_flip_x; | 	c.flip_h=p_flip_x; | ||||||
| 	c.flip_v=p_flip_y; | 	c.flip_v=p_flip_y; | ||||||
|  | 	c.transpose=p_transpose; | ||||||
| 
 | 
 | ||||||
| 	_make_quadrant_dirty(Q); | 	_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; | 	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() { | 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]); | 		uint32_t v = decode_uint32(&local[4]); | ||||||
| 		bool flip_h = v&(1<<29); | 		bool flip_h = v&(1<<29); | ||||||
| 		bool flip_v = v&(1<<30); | 		bool flip_v = v&(1<<30); | ||||||
|  | 		bool transpose = v&(1<<31); | ||||||
| 		v&=(1<<29)-1; | 		v&=(1<<29)-1; | ||||||
| 
 | 
 | ||||||
| //		if (x<-20 || y <-20 || x>4000 || y>4000)
 | //		if (x<-20 || y <-20 || x>4000 || y>4000)
 | ||||||
| //			continue;
 | //			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); | 			val|=(1<<29); | ||||||
| 		if (E->get().flip_v) | 		if (E->get().flip_v) | ||||||
| 			val|=(1<<30); | 			val|=(1<<30); | ||||||
|  | 		if (E->get().transpose) | ||||||
|  | 			val|=(1<<31); | ||||||
| 
 | 
 | ||||||
| 		encode_uint32(val,&ptr[4]); | 		encode_uint32(val,&ptr[4]); | ||||||
| 		idx+=2; | 		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()) { | 	for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) { | ||||||
| 
 | 
 | ||||||
| 		Quadrant &q=E->get(); | 		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) { | void TileMap::set_collision_friction(float p_friction) { | ||||||
| 
 | 
 | ||||||
| 	friction=p_friction; | 	friction=p_friction; | ||||||
| 	for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) { | 	for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) { | ||||||
| 
 | 
 | ||||||
| 		Quadrant &q=E->get(); | 		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()) { | 	for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) { | ||||||
| 
 | 
 | ||||||
| 		Quadrant &q=E->get(); | 		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("set_center_y","enable"),&TileMap::set_center_y); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_center_y"),&TileMap::get_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("set_collision_layer_mask","mask"),&TileMap::set_collision_layer_mask); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_collision_layer_mask"),&TileMap::get_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("set_collision_bounce","value"),&TileMap::set_collision_bounce); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_collision_bounce"),&TileMap::get_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("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_x_flipped","x","y"),&TileMap::is_cell_x_flipped); | ||||||
| 	ObjectTypeDB::bind_method(_MD("is_cell_y_flipped","x","y"),&TileMap::is_cell_y_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::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::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::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/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::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")); | 	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; | 	bounce=0; | ||||||
| 	mode=MODE_SQUARE; | 	mode=MODE_SQUARE; | ||||||
| 	half_offset=HALF_OFFSET_DISABLED; | 	half_offset=HALF_OFFSET_DISABLED; | ||||||
|  | 	use_kinematic=false; | ||||||
| 
 | 
 | ||||||
| 	fp_adjust=0.01; | 	fp_adjust=0.01; | ||||||
| 	fp_adjust=0.01; | 	fp_adjust=0.01; | ||||||
|  |  | ||||||
|  | @ -60,6 +60,7 @@ private: | ||||||
| 	Mode mode; | 	Mode mode; | ||||||
| 	Matrix32 custom_transform; | 	Matrix32 custom_transform; | ||||||
| 	HalfOffset half_offset; | 	HalfOffset half_offset; | ||||||
|  | 	bool use_kinematic; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	union PosKey { | 	union PosKey { | ||||||
|  | @ -85,6 +86,7 @@ private: | ||||||
| 			int32_t id:24; | 			int32_t id:24; | ||||||
| 			bool flip_h:1; | 			bool flip_h:1; | ||||||
| 			bool flip_v:1; | 			bool flip_v:1; | ||||||
|  | 			bool transpose:1; | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		uint32_t _u32t; | 		uint32_t _u32t; | ||||||
|  | @ -97,14 +99,14 @@ private: | ||||||
| 
 | 
 | ||||||
| 		Vector2 pos; | 		Vector2 pos; | ||||||
| 		RID canvas_item; | 		RID canvas_item; | ||||||
| 		RID static_body; | 		RID body; | ||||||
| 
 | 
 | ||||||
| 		SelfList<Quadrant> dirty_list; | 		SelfList<Quadrant> dirty_list; | ||||||
| 
 | 
 | ||||||
| 		VSet<PosKey> cells; | 		VSet<PosKey> cells; | ||||||
| 
 | 
 | ||||||
| 		void operator=(const Quadrant& q) { 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; static_body=q.static_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) {} | 		Quadrant() : dirty_list(this) {} | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  | @ -167,16 +169,20 @@ public: | ||||||
| 	void set_center_y(bool p_enable); | 	void set_center_y(bool p_enable); | ||||||
| 	bool get_center_y() const; | 	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; | 	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_x_flipped(int p_x,int p_y) const; | ||||||
| 	bool is_cell_y_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; | 	Rect2 get_item_rect() const; | ||||||
| 
 | 
 | ||||||
| 	void set_collision_layer_mask(uint32_t p_layer); | 	void set_collision_layer_mask(uint32_t p_layer); | ||||||
| 	uint32_t get_collision_layer_mask() const; | 	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); | 	void set_collision_friction(float p_friction); | ||||||
| 	float get_collision_friction() const; | 	float get_collision_friction() const; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -152,11 +152,11 @@ void Camera::_get_property_list( List<PropertyInfo> *p_list) const { | ||||||
| 	 | 	 | ||||||
| 		case PROJECTION_PERSPECTIVE: { | 		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) | 			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 | 			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; | 		} break; | ||||||
|  | @ -604,7 +604,7 @@ Vector3 Camera::project_position(const Point2& p_point) const { | ||||||
| 
 | 
 | ||||||
| 	Vector2 point; | 	Vector2 point; | ||||||
| 	point.x = (p_point.x/viewport_size.x) * 2.0 - 1.0; | 	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; | 	point*=vp_size; | ||||||
| 
 | 
 | ||||||
| 	Vector3 p(point.x,point.y,-near); | 	Vector3 p(point.x,point.y,-near); | ||||||
|  |  | ||||||
|  | @ -310,6 +310,17 @@ int GeometryInstance::get_baked_light_texture_id() const{ | ||||||
| 	return baked_light_texture_id; | 	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() { | 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("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("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); | 	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); | 	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_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_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::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"), _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/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); | 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE); | ||||||
|  |  | ||||||
|  | @ -108,6 +108,7 @@ private: | ||||||
| 	void _find_baked_light(); | 	void _find_baked_light(); | ||||||
| 	BakedLightInstance *baked_light_instance; | 	BakedLightInstance *baked_light_instance; | ||||||
| 	int baked_light_texture_id; | 	int baked_light_texture_id; | ||||||
|  | 	float extra_cull_margin; | ||||||
| 
 | 
 | ||||||
| 	void _baked_light_changed(); | 	void _baked_light_changed(); | ||||||
| 	void _update_visibility(); | 	void _update_visibility(); | ||||||
|  | @ -132,6 +133,9 @@ public: | ||||||
| 	void set_baked_light_texture_id(int p_id); | 	void set_baked_light_texture_id(int p_id); | ||||||
| 	int get_baked_light_texture_id() const; | 	int get_baked_light_texture_id() const; | ||||||
| 
 | 
 | ||||||
|  | 	void set_extra_cull_margin(float p_margin); | ||||||
|  | 	float get_extra_cull_margin() const; | ||||||
|  | 
 | ||||||
| 	GeometryInstance(); | 	GeometryInstance(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2267,8 +2267,10 @@ void Control::_window_sort_subwindows() { | ||||||
| 	if (!window->subwindow_order_dirty) | 	if (!window->subwindow_order_dirty) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	window->modal_stack.sort_custom<CComparator>(); | 	window->modal_stack.sort_custom<CComparator>(); | ||||||
| 	window->subwindows.sort_custom<CComparator>(); | 	window->subwindows.sort_custom<CComparator>(); | ||||||
|  | 
 | ||||||
| 	window->subwindow_order_dirty=false; | 	window->subwindow_order_dirty=false; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | @ -2688,6 +2690,12 @@ Control *Control::get_focus_owner() const { | ||||||
| 	return data.window->window->key_focus; | 	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() { | void Control::_bind_methods() { | ||||||
| 
 | 
 | ||||||
| 	ObjectTypeDB::bind_method(_MD("_window_input_event"),&Control::_window_input_event); | 	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("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("_input_event",PropertyInfo(Variant::INPUT_EVENT,"event"))); | ||||||
| 	BIND_VMETHOD(MethodInfo(Variant::VECTOR2,"get_minimum_size")); | 	BIND_VMETHOD(MethodInfo(Variant::VECTOR2,"get_minimum_size")); | ||||||
| 	BIND_VMETHOD(MethodInfo(Variant::OBJECT,"get_drag_data",PropertyInfo(Variant::VECTOR2,"pos"))); | 	BIND_VMETHOD(MethodInfo(Variant::OBJECT,"get_drag_data",PropertyInfo(Variant::VECTOR2,"pos"))); | ||||||
|  |  | ||||||
|  | @ -380,7 +380,7 @@ public: | ||||||
| 
 | 
 | ||||||
| 	void grab_click_focus(); | 	void grab_click_focus(); | ||||||
| 
 | 
 | ||||||
| 
 | 	void warp_mouse(const Point2& p_to_pos); | ||||||
| 
 | 
 | ||||||
| 	Control();	 | 	Control();	 | ||||||
| 	~Control(); | 	~Control(); | ||||||
|  |  | ||||||
|  | @ -328,8 +328,8 @@ AcceptDialog::AcceptDialog() { | ||||||
| 	label->set_anchor(MARGIN_RIGHT,ANCHOR_END); | 	label->set_anchor(MARGIN_RIGHT,ANCHOR_END); | ||||||
| 	label->set_anchor(MARGIN_BOTTOM,ANCHOR_END); | 	label->set_anchor(MARGIN_BOTTOM,ANCHOR_END); | ||||||
| 	label->set_begin( Point2( margin, margin) ); | 	label->set_begin( Point2( margin, margin) ); | ||||||
| 	label->set_end( Point2( margin, button_margin) ); | 	label->set_end( Point2( margin, button_margin+10) ); | ||||||
| 	label->set_autowrap(true); | 	//label->set_autowrap(true);
 | ||||||
| 	add_child(label); | 	add_child(label); | ||||||
| 
 | 
 | ||||||
| 	hbc = memnew( HBoxContainer ); | 	hbc = memnew( HBoxContainer ); | ||||||
|  |  | ||||||
|  | @ -94,6 +94,8 @@ void Popup::popup_centered_minsize(const Size2& p_minsize) { | ||||||
| 		Control *c=get_child(i)->cast_to<Control>(); | 		Control *c=get_child(i)->cast_to<Control>(); | ||||||
| 		if (!c) | 		if (!c) | ||||||
| 			continue; | 			continue; | ||||||
|  | 		if (c->is_hidden()) | ||||||
|  | 			continue; | ||||||
| 
 | 
 | ||||||
| 		Size2 minsize = c->get_combined_minimum_size(); | 		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.width = MAX( total_minsize.width, minsize.width ); | ||||||
| 		total_minsize.height = MAX( total_minsize.height, minsize.height ); | 		total_minsize.height = MAX( total_minsize.height, minsize.height ); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -2472,6 +2472,10 @@ void Tree::_notification(int p_what) { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (p_what==NOTIFICATION_THEME_CHANGED) { | ||||||
|  | 		update_cache(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -29,6 +29,8 @@ | ||||||
| #include "viewport.h" | #include "viewport.h" | ||||||
| #include "os/os.h" | #include "os/os.h" | ||||||
| #include "scene/3d/spatial.h" | #include "scene/3d/spatial.h" | ||||||
|  | #include "os/input.h" | ||||||
|  | 
 | ||||||
| //#include "scene/3d/camera.h"
 | //#include "scene/3d/camera.h"
 | ||||||
| 
 | 
 | ||||||
| #include "servers/spatial_sound_server.h" | #include "servers/spatial_sound_server.h" | ||||||
|  | @ -970,6 +972,22 @@ bool Viewport::get_render_target_vflip() const{ | ||||||
| 	return render_target_vflip; | 	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) { | 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) { | void Viewport::input(const InputEvent& p_event) { | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_COND(!is_inside_tree()); | 	ERR_FAIL_COND(!is_inside_tree()); | ||||||
|  | @ -1257,6 +1281,11 @@ void Viewport::_bind_methods() { | ||||||
| 	ObjectTypeDB::bind_method(_MD("set_render_target_vflip","enable"), &Viewport::set_render_target_vflip); | 	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("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("set_render_target_filter","enable"), &Viewport::set_render_target_filter); | ||||||
| 	ObjectTypeDB::bind_method(_MD("get_render_target_filter"), &Viewport::get_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("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("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::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") ); | 	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,"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/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/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/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::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") ); | 	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_gen_mipmaps=false; | ||||||
| 	render_target=false; | 	render_target=false; | ||||||
| 	render_target_vflip=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_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE; | ||||||
| 	render_target_texture = Ref<RenderTargetTexture>( memnew( RenderTargetTexture(this) ) ); | 	render_target_texture = Ref<RenderTargetTexture>( memnew( RenderTargetTexture(this) ) ); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -114,6 +114,7 @@ friend class RenderTargetTexture; | ||||||
| 
 | 
 | ||||||
| 	bool transparent_bg; | 	bool transparent_bg; | ||||||
| 	bool render_target_vflip; | 	bool render_target_vflip; | ||||||
|  | 	bool render_target_clear_on_new_frame; | ||||||
| 	bool render_target_filter; | 	bool render_target_filter; | ||||||
| 	bool render_target_gen_mipmaps; | 	bool render_target_gen_mipmaps; | ||||||
| 
 | 
 | ||||||
|  | @ -220,6 +221,10 @@ public: | ||||||
| 	void set_render_target_vflip(bool p_enable); | 	void set_render_target_vflip(bool p_enable); | ||||||
| 	bool get_render_target_vflip() const; | 	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); | 	void set_render_target_filter(bool p_enable); | ||||||
| 	bool get_render_target_filter() const; | 	bool get_render_target_filter() const; | ||||||
| 
 | 
 | ||||||
|  | @ -246,6 +251,8 @@ public: | ||||||
| 	void set_render_target_to_screen_rect(const Rect2& p_rect); | 	void set_render_target_to_screen_rect(const Rect2& p_rect); | ||||||
| 	Rect2 get_render_target_to_screen_rect() const; | 	Rect2 get_render_target_to_screen_rect() const; | ||||||
| 
 | 
 | ||||||
|  | 	void warp_mouse(const Vector2& p_pos); | ||||||
|  | 
 | ||||||
| 	void set_physics_object_picking(bool p_enable); | 	void set_physics_object_picking(bool p_enable); | ||||||
| 	bool get_physics_object_picking(); | 	bool get_physics_object_picking(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -79,6 +79,8 @@ | ||||||
| #include "scene/resources/video_stream.h" | #include "scene/resources/video_stream.h" | ||||||
| #include "scene/2d/particles_2d.h" | #include "scene/2d/particles_2d.h" | ||||||
| #include "scene/2d/path_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/canvas_item.h" | ||||||
| #include "scene/2d/sprite.h" | #include "scene/2d/sprite.h" | ||||||
|  | @ -102,6 +104,8 @@ | ||||||
| #include "scene/2d/screen_button.h" | #include "scene/2d/screen_button.h" | ||||||
| #include "scene/2d/remote_transform_2d.h" | #include "scene/2d/remote_transform_2d.h" | ||||||
| #include "scene/2d/y_sort.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/position_2d.h" | ||||||
| #include "scene/2d/tile_map.h" | #include "scene/2d/tile_map.h" | ||||||
|  | @ -262,6 +266,7 @@ void register_scene_types() { | ||||||
| 	ObjectTypeDB::register_virtual_type<RenderTargetTexture>(); | 	ObjectTypeDB::register_virtual_type<RenderTargetTexture>(); | ||||||
| 	ObjectTypeDB::register_type<Timer>(); | 	ObjectTypeDB::register_type<Timer>(); | ||||||
| 	ObjectTypeDB::register_type<CanvasLayer>(); | 	ObjectTypeDB::register_type<CanvasLayer>(); | ||||||
|  | 	ObjectTypeDB::register_type<CanvasModulate>(); | ||||||
| 	ObjectTypeDB::register_type<ResourcePreloader>(); | 	ObjectTypeDB::register_type<ResourcePreloader>(); | ||||||
| 
 | 
 | ||||||
| 	/* REGISTER GUI */ | 	/* REGISTER GUI */ | ||||||
|  | @ -450,6 +455,7 @@ void register_scene_types() { | ||||||
| 	//ObjectTypeDB::set_type_enabled("BodyVolumeCylinder",false);
 | 	//ObjectTypeDB::set_type_enabled("BodyVolumeCylinder",false);
 | ||||||
| 	//ObjectTypeDB::set_type_enabled("BodyVolumeConvexPolygon",false);
 | 	//ObjectTypeDB::set_type_enabled("BodyVolumeConvexPolygon",false);
 | ||||||
| 
 | 
 | ||||||
|  | 	ObjectTypeDB::register_type<CanvasItemMaterial>(); | ||||||
| 	ObjectTypeDB::register_virtual_type<CanvasItem>(); | 	ObjectTypeDB::register_virtual_type<CanvasItem>(); | ||||||
| 	ObjectTypeDB::register_type<Node2D>(); | 	ObjectTypeDB::register_type<Node2D>(); | ||||||
| 	ObjectTypeDB::register_type<Particles2D>(); | 	ObjectTypeDB::register_type<Particles2D>(); | ||||||
|  | @ -471,6 +477,9 @@ void register_scene_types() { | ||||||
| 	ObjectTypeDB::register_type<VisibilityNotifier2D>(); | 	ObjectTypeDB::register_type<VisibilityNotifier2D>(); | ||||||
| 	ObjectTypeDB::register_type<VisibilityEnabler2D>(); | 	ObjectTypeDB::register_type<VisibilityEnabler2D>(); | ||||||
| 	ObjectTypeDB::register_type<Polygon2D>(); | 	ObjectTypeDB::register_type<Polygon2D>(); | ||||||
|  | 	ObjectTypeDB::register_type<Light2D>(); | ||||||
|  | 	ObjectTypeDB::register_type<LightOccluder2D>(); | ||||||
|  | 	ObjectTypeDB::register_type<OccluderPolygon2D>(); | ||||||
| 	ObjectTypeDB::register_type<YSort>(); | 	ObjectTypeDB::register_type<YSort>(); | ||||||
| 
 | 
 | ||||||
| 	ObjectTypeDB::set_type_enabled("CollisionShape2D",false); | 	ObjectTypeDB::set_type_enabled("CollisionShape2D",false); | ||||||
|  | @ -499,6 +508,7 @@ void register_scene_types() { | ||||||
| 	ObjectTypeDB::register_virtual_type<Shader>(); | 	ObjectTypeDB::register_virtual_type<Shader>(); | ||||||
| 	ObjectTypeDB::register_virtual_type<ShaderGraph>(); | 	ObjectTypeDB::register_virtual_type<ShaderGraph>(); | ||||||
| 	ObjectTypeDB::register_type<CanvasItemShader>(); | 	ObjectTypeDB::register_type<CanvasItemShader>(); | ||||||
|  | 	ObjectTypeDB::register_type<CanvasItemShaderGraph>(); | ||||||
| 
 | 
 | ||||||
| #ifndef _3D_DISABLED | #ifndef _3D_DISABLED | ||||||
| 	ObjectTypeDB::register_type<Mesh>(); | 	ObjectTypeDB::register_type<Mesh>(); | ||||||
|  | @ -574,6 +584,10 @@ void register_scene_types() { | ||||||
| 	ObjectTypeDB::register_type<Path2D>(); | 	ObjectTypeDB::register_type<Path2D>(); | ||||||
| 	ObjectTypeDB::register_type<PathFollow2D>(); | 	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
 | 	OS::get_singleton()->yield(); //may take time to init
 | ||||||
| 
 | 
 | ||||||
| 	ObjectTypeDB::register_type<PackedScene>(); | 	ObjectTypeDB::register_type<PackedScene>(); | ||||||
|  |  | ||||||
|  | @ -582,7 +582,7 @@ void ShaderMaterial::get_argument_options(const StringName& p_function,int p_idx | ||||||
| 			List<PropertyInfo> pl; | 			List<PropertyInfo> pl; | ||||||
| 			shader->get_param_list(&pl); | 			shader->get_param_list(&pl); | ||||||
| 			for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) { | 			for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) { | ||||||
| 				r_options->push_back("\""+E->get().name.replace("shader_param/","")+"\""); | 				r_options->push_back("\""+E->get().name.replace_first("shader_param/","")+"\""); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -525,24 +525,32 @@ bool PolygonPathFinder::is_point_inside(const Vector2& p_point) const { | ||||||
| 
 | 
 | ||||||
| Vector2 PolygonPathFinder::get_closest_point(const Vector2& p_point) const { | Vector2 PolygonPathFinder::get_closest_point(const Vector2& p_point) const { | ||||||
| 
 | 
 | ||||||
| 	int closest_idx=-1; |  | ||||||
| 	float closest_dist=1e20; | 	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) { | 		if (d<closest_dist) { | ||||||
| 			closest_dist=d; | 			closest_dist=d; | ||||||
| 			closest_idx=i; | 			closest_point=closest; | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	ERR_FAIL_COND_V(closest_idx==-1,Vector2()); | 	ERR_FAIL_COND_V(closest_dist==1e20,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> PolygonPathFinder::get_intersections(const Vector2& p_from, const Vector2& p_to) const { | ||||||
| 
 | 
 | ||||||
| 	Vector<Vector2> inters; | 	Vector<Vector2> inters; | ||||||
|  |  | ||||||
|  | @ -221,6 +221,13 @@ void ShaderGraph::_bind_methods() { | ||||||
| 	ObjectTypeDB::bind_method(_MD("comment_node_set_text","shader_type","id","text"),&ShaderGraph::comment_node_set_text); | 	ObjectTypeDB::bind_method(_MD("comment_node_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("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("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("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); | 	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_XFORM_TO_VEC ); // 3 vec input ); 1 xform output
 | ||||||
| 	BIND_CONSTANT( NODE_SCALAR_INTERP ); // scalar interpolation (with optional curve)
 | 	BIND_CONSTANT( NODE_SCALAR_INTERP ); // scalar interpolation (with optional curve)
 | ||||||
| 	BIND_CONSTANT( NODE_VEC_INTERP ); // vec3 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_SCALAR_INPUT ); // scalar uniform (assignable in material)
 | ||||||
| 	BIND_CONSTANT( NODE_VEC_INPUT ); // vec3 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_RGB_INPUT ); // color uniform (assignable in material)
 | ||||||
| 	BIND_CONSTANT( NODE_XFORM_INPUT ); // mat4 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_TEXTURE_INPUT ); // texture input (assignable in material)
 | ||||||
| 	BIND_CONSTANT( NODE_CUBEMAP_INPUT ); // cubemap 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_OUTPUT ); // output (shader type dependent)
 | ||||||
| 	BIND_CONSTANT( NODE_COMMENT ); // comment
 | 	BIND_CONSTANT( NODE_COMMENT ); // comment
 | ||||||
| 	BIND_CONSTANT( NODE_TYPE_MAX ); | 	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_XFORM_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
 | ||||||
| 		case NODE_SCALAR_INTERP: {} break; // scalar interpolation (with optional curve)
 | 		case NODE_SCALAR_INTERP: {} break; // scalar interpolation (with optional curve)
 | ||||||
| 		case NODE_VEC_INTERP: {} break; // vec3 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_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_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_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_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_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_OUTPUT: {} break; // output (shader type dependent)
 | ||||||
| 		case NODE_COMMENT: {} break; // comment
 | 		case NODE_COMMENT: {} break; // comment
 | ||||||
| 		case NODE_TYPE_MAX: {}; | 		case NODE_TYPE_MAX: {}; | ||||||
|  | @ -964,6 +977,59 @@ ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type, | ||||||
| 	return VecFunc(func); | 	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){ | void ShaderGraph::input_node_set_name(ShaderType p_type,int p_id,const String& p_name){ | ||||||
| 
 | 
 | ||||||
| 	ERR_FAIL_INDEX(p_type,3); | 	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,"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,"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,"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,"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,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN}, | ||||||
| 	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,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}, | 	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_IN}, | ||||||
| 	//light out
 | 	//light out
 | ||||||
| 	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"Light","LIGHT","",SLOT_TYPE_VEC,SLOT_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
 | 	//end
 | ||||||
| 	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT}, | 	{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_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_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_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_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_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_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_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_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_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_COMMENT,{SLOT_MAX},{SLOT_MAX}}, // comment
 | ||||||
| 		{NODE_TYPE_MAX,{SLOT_MAX},{SLOT_MAX}} | 		{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) { | 			} else if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) { | ||||||
| 				if (name==("IN_NORMAL")) | 				if (name==("IN_NORMAL")) | ||||||
| 					code[i]="vec3 IN_NORMAL=NORMAL;\n"+code[i]; | 					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; | 			all_ok=false; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/*print_line("VERTEX: \n"+code[0]);
 | ||||||
|  | 	print_line("FRAGMENT: \n"+code[1]); | ||||||
|  | 	print_line("LIGHT: \n"+code[2]);*/ | ||||||
|  | 
 | ||||||
| 	if (all_ok) { | 	if (all_ok) { | ||||||
| 		set_code(code[0],code[1],code[2]); | 		set_code(code[0],code[1],code[2]); | ||||||
| 	} | 	} | ||||||
|  | @ -1688,6 +1803,134 @@ void ShaderGraph::_update_shader() { | ||||||
| 	emit_signal(SceneStringNames::get_singleton()->updated); | 	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) { | 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"; | 			code+=OUTNAME(p_node->id,0)+"=TIME;\n"; | ||||||
| 		}break; | 		}break; | ||||||
| 		case NODE_SCREEN_TEX: { | 		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; | 		}break; | ||||||
| 		case NODE_SCALAR_OP: { | 		case NODE_SCALAR_OP: { | ||||||
| 			int op = p_node->param1; | 			int op = p_node->param1; | ||||||
|  | @ -1987,6 +2230,129 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str | ||||||
| 		case NODE_VEC_INTERP: { | 		case NODE_VEC_INTERP: { | ||||||
| 			code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n"; | 			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; | 		}break; | ||||||
| 		case NODE_SCALAR_INPUT: { | 		case NODE_SCALAR_INPUT: { | ||||||
| 			String name = p_node->param1; | 			String name = p_node->param1; | ||||||
|  | @ -2043,6 +2409,22 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str | ||||||
| 			code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n"; | 			code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n"; | ||||||
| 			code += OUTNAME(p_node->id,1)+"="+rname+".a;\n"; | 			code += OUTNAME(p_node->id,1)+"="+rname+".a;\n"; | ||||||
| 		}break; | 		}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: { | 		case NODE_OUTPUT: { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -66,14 +66,15 @@ public: | ||||||
| 		NODE_VEC_TO_XFORM, // 3 vec input, 1 xform output
 | 		NODE_VEC_TO_XFORM, // 3 vec input, 1 xform output
 | ||||||
| 		NODE_SCALAR_INTERP, // scalar interpolation (with optional curve)
 | 		NODE_SCALAR_INTERP, // scalar interpolation (with optional curve)
 | ||||||
| 		NODE_VEC_INTERP, // vec3 interpolation  (with optional curve)
 | 		NODE_VEC_INTERP, // vec3 interpolation  (with optional curve)
 | ||||||
| 		/*NODE_SCALAR_CURVE_REMAP,
 | 		NODE_COLOR_RAMP, //take scalar, output vec3
 | ||||||
| 		NODE_VEC_CURVE_REMAP,*/ | 		NODE_CURVE_MAP, //take scalar, otput scalar
 | ||||||
| 		NODE_SCALAR_INPUT, // scalar uniform (assignable in material)		
 | 		NODE_SCALAR_INPUT, // scalar uniform (assignable in material)		
 | ||||||
| 		NODE_VEC_INPUT, // vec3 uniform (assignable in material)
 | 		NODE_VEC_INPUT, // vec3 uniform (assignable in material)
 | ||||||
| 		NODE_RGB_INPUT, // color uniform (assignable in material)
 | 		NODE_RGB_INPUT, // color uniform (assignable in material)
 | ||||||
| 		NODE_XFORM_INPUT, // mat4 uniform (assignable in material)
 | 		NODE_XFORM_INPUT, // mat4 uniform (assignable in material)
 | ||||||
| 		NODE_TEXTURE_INPUT, // texture input (assignable in material)
 | 		NODE_TEXTURE_INPUT, // texture input (assignable in material)
 | ||||||
| 		NODE_CUBEMAP_INPUT, // cubemap input (assignable in material)
 | 		NODE_CUBEMAP_INPUT, // cubemap input (assignable in material)
 | ||||||
|  | 		NODE_DEFAULT_TEXTURE, | ||||||
| 		NODE_OUTPUT, // output (shader type dependent)
 | 		NODE_OUTPUT, // output (shader type dependent)
 | ||||||
| 		NODE_COMMENT, // comment
 | 		NODE_COMMENT, // comment
 | ||||||
| 		NODE_TYPE_MAX | 		NODE_TYPE_MAX | ||||||
|  | @ -174,6 +175,7 @@ private: | ||||||
| 	void _update_shader(); | 	void _update_shader(); | ||||||
| 	void _request_update(); | 	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); | 	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; | 	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); | 	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; | 	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); | 	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); | 	String input_node_get_name(ShaderType p_which,int p_id); | ||||||
| 
 | 
 | ||||||
|  | @ -397,7 +406,6 @@ VARIANT_ENUM_CAST( ShaderGraph::GraphError ); | ||||||
| class MaterialShaderGraph : public ShaderGraph { | class MaterialShaderGraph : public ShaderGraph { | ||||||
| 
 | 
 | ||||||
| 	OBJ_TYPE( MaterialShaderGraph, ShaderGraph ); | 	OBJ_TYPE( MaterialShaderGraph, ShaderGraph ); | ||||||
| 	RES_BASE_EXTENSION("sgp"); |  | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
| 
 | 
 | ||||||
|  | @ -407,4 +415,17 @@ public: | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | class CanvasItemShaderGraph : public ShaderGraph { | ||||||
|  | 
 | ||||||
|  | 	OBJ_TYPE( CanvasItemShaderGraph, ShaderGraph ); | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	CanvasItemShaderGraph() : ShaderGraph(MODE_CANVAS_ITEM) { | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| #endif // SHADER_GRAPH_H
 | #endif // SHADER_GRAPH_H
 | ||||||
|  |  | ||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Juan Linietsky
						Juan Linietsky