diff options
73 files changed, 1944 insertions, 3429 deletions
diff --git a/.gitignore b/.gitignore index e1941b18df..f3a4e9714c 100644 --- a/.gitignore +++ b/.gitignore @@ -37,17 +37,10 @@ platform/android/java/.gradle  platform/android/java/.gradletasknamecache  platform/android/java/local.properties  platform/android/java/project.properties +platform/android/java/build.gradle  platform/android/java/AndroidManifest.xml -platform/android/java/bin/*  platform/android/java/libs/* -platform/android/java/gen/*  platform/android/java/assets -platform/android/libs/apk_expansion/bin/* -platform/android/libs/apk_expansion/gen/* -platform/android/libs/google_play_services/bin/* -platform/android/libs/google_play_services/gen/* -platform/android/libs/play_licensing/bin/* -platform/android/libs/play_licensing/gen/*  # General c++ generated files  *.lib diff --git a/SConstruct b/SConstruct index 01b1f2ce8e..d168820f66 100644 --- a/SConstruct +++ b/SConstruct @@ -73,6 +73,7 @@ env_base.android_java_dirs=[]  env_base.android_res_dirs=[]  env_base.android_aidl_dirs=[]  env_base.android_jni_dirs=[] +env_base.android_default_config=[]  env_base.android_manifest_chunk=""  env_base.android_permission_chunk=""  env_base.android_appattributes_chunk="" @@ -88,6 +89,7 @@ env_base.__class__.android_add_java_dir=methods.android_add_java_dir  env_base.__class__.android_add_res_dir=methods.android_add_res_dir  env_base.__class__.android_add_aidl_dir=methods.android_add_aidl_dir  env_base.__class__.android_add_jni_dir=methods.android_add_jni_dir +env_base.__class__.android_add_default_config=methods.android_add_default_config  env_base.__class__.android_add_to_manifest = methods.android_add_to_manifest  env_base.__class__.android_add_to_permissions = methods.android_add_to_permissions  env_base.__class__.android_add_to_attributes = methods.android_add_to_attributes diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index ace7e7c7b7..6edc292b62 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -435,6 +435,18 @@ String _OS::get_locale() const {  	return OS::get_singleton()->get_locale();  } +String _OS::get_latin_keyboard_variant() const { +	switch( OS::get_singleton()->get_latin_keyboard_variant() ) { +		case OS::LATIN_KEYBOARD_QWERTY: return "QWERTY"; +		case OS::LATIN_KEYBOARD_QWERTZ: return "QWERTZ"; +		case OS::LATIN_KEYBOARD_AZERTY: return "AZERTY"; +		case OS::LATIN_KEYBOARD_QZERTY: return "QZERTY"; +		case OS::LATIN_KEYBOARD_DVORAK: return "DVORAK"; +		case OS::LATIN_KEYBOARD_NEO   : return "NEO"; +		default: return "ERROR"; +	} +} +  String _OS::get_model_name() const {      return OS::get_singleton()->get_model_name(); @@ -1097,6 +1109,7 @@ void _OS::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("get_ticks_msec"),&_OS::get_ticks_msec);  	ObjectTypeDB::bind_method(_MD("get_splash_tick_msec"),&_OS::get_splash_tick_msec);  	ObjectTypeDB::bind_method(_MD("get_locale"),&_OS::get_locale); +	ObjectTypeDB::bind_method(_MD("get_latin_keyboard_variant"),&_OS::get_latin_keyboard_variant);  	ObjectTypeDB::bind_method(_MD("get_model_name"),&_OS::get_model_name);  	ObjectTypeDB::bind_method(_MD("get_custom_level"),&_OS::get_custom_level); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 856d942d02..5bd427578a 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -192,6 +192,8 @@ public:  	Vector<String> get_cmdline_args();  	String get_locale() const; +	String get_latin_keyboard_variant() const; +  	String get_model_name() const;  	MainLoop *get_main_loop() const; diff --git a/core/os/input.cpp b/core/os/input.cpp index dacddc0928..efbae57950 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -59,6 +59,7 @@ void Input::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("get_joy_axis","device","axis"),&Input::get_joy_axis);  	ObjectTypeDB::bind_method(_MD("get_joy_name","device"),&Input::get_joy_name);  	ObjectTypeDB::bind_method(_MD("get_joy_guid","device"),&Input::get_joy_guid); +	ObjectTypeDB::bind_method(_MD("get_connected_joysticks"),&Input::get_connected_joysticks);  	ObjectTypeDB::bind_method(_MD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);  	ObjectTypeDB::bind_method(_MD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);  	ObjectTypeDB::bind_method(_MD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0)); diff --git a/core/os/input.h b/core/os/input.h index fa2cef5467..d11703470b 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -62,6 +62,7 @@ public:  	virtual float get_joy_axis(int p_device,int p_axis)=0;  	virtual String get_joy_name(int p_idx)=0; +	virtual Array get_connected_joysticks()=0;  	virtual void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid)=0;  	virtual void add_joy_mapping(String p_mapping, bool p_update_existing=false)=0;  	virtual void remove_joy_mapping(String p_guid)=0; diff --git a/core/variant_op.cpp b/core/variant_op.cpp index e549161de9..9182dcde1a 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -2911,6 +2911,14 @@ bool Variant::iter_init(Variant& r_iter,bool &valid) const {  			return ret;  		} break; +		case STRING: { + +			const String *str=reinterpret_cast<const String*>(_data._mem); +			if (str->empty()) +				return false; +			r_iter = 0; +			return true; +		} break;  		case DICTIONARY: {  			const Dictionary *dic=reinterpret_cast<const Dictionary*>(_data._mem); @@ -3028,6 +3036,17 @@ bool Variant::iter_next(Variant& r_iter,bool &valid) const {  			return ret;  		} break; + +		case STRING: { + +			const String *str=reinterpret_cast<const String*>(_data._mem); +			int idx = r_iter; +			idx++; +			if (idx >= str->size()) +				return false; +			r_iter = idx; +			return true; +		} break;  		case DICTIONARY: {  			const Dictionary *dic=reinterpret_cast<const Dictionary*>(_data._mem); @@ -3158,6 +3177,11 @@ Variant Variant::iter_get(const Variant& r_iter,bool &r_valid) const {  			return ret;  		} break; +		case STRING: { + +			const String *str=reinterpret_cast<const String*>(_data._mem); +			return str->substr(r_iter,1); +		} break;  		case DICTIONARY: {  			return r_iter; //iterator is the same as the key diff --git a/doc/base/classes.xml b/doc/base/classes.xml index cffbd68939..ae5438c430 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -6676,6 +6676,17 @@  				Force the camera to update scroll immediately.  			</description>  		</method> +		<method name="reset_smoothing"> +			<description> +			Set the camera's position immediately to its current smoothing destination. +			This has no effect if smoothing is disabled. +			</description> +		</method> +		<method name="align"> +			<description> +			Align the camera to the tracked node +			</description> +		</method>  		<method name="get_anchor_mode" qualifiers="const">  			<return type="int">  			</return> @@ -7328,6 +7339,22 @@  			</description>  		</method>  		<method name="update"> +		<method name="make_screen_coord_local" qualifiers="const"> +			<return type="Vector2"> +			</return> +			<argument index="0" name="screen_point" type="Vector2"> +			</argument> +			<description> +				Take a 2d screen point and convert to 2D local coords relative to this Canvas +				 item.  If this CanvasItem is the root of a Scene, its essentially the  +				 world coords for that scene. +			</description> +		</method> +		<method name="make_input_local" qualifiers="const"> +			<return type="InputEvent"> +			</return> +			<argument index="0" name="event" type="InputEvent"> +			</argument>  			<description>  				Queue the CanvasItem for update. [code]NOTIFICATION_DRAW[/code] will be called on idle time to request redraw.  			</description> @@ -15748,6 +15775,13 @@  				If the device has an accelerometer, this will return the movement.  			</description>  		</method> +		<method name="get_connected_joysticks"> +			<return type="Array"> +			</return> +			<description> +			Returns an [Array] containing the device IDs of all currently connected joysticks. +			</description> +		</method>  		<method name="get_joy_axis">  			<return type="float">  			</return> @@ -21677,6 +21711,12 @@  			<description>  			</description>  		</method> +		<method name="is_displayed_folded" qualifiers="const"> +			<return type="bool"> +			</return> +			<description> +			</description> +		</method>  		<method name="is_fixed_processing" qualifiers="const">  			<return type="bool">  			</return> @@ -21802,6 +21842,12 @@  			<description>  			</description>  		</method> +		<method name="set_display_folded"> +			<argument index="0" name="fold" type="bool"> +			</argument> +			<description> +			</description> +		</method>  		<method name="set_filename">  			<argument index="0" name="filename" type="String">  			</argument> @@ -31551,6 +31597,13 @@  			<description>  			</description>  		</method> +		<method name="get_text"> +			<return type="String"> +			</return> +			<description> +			Returns the raw text, stripping out the formatting information. +			</description> +		</method>  		<method name="get_total_character_count" qualifiers="const">  			<return type="int">  			</return> @@ -39355,6 +39408,34 @@  				Set the color for symbols.  			</description>  		</method> +		<method name="set_show_line_numbers"> +			<argument index="0" name="enable" type="bool"> +			</argument> +			<description> +				Set to enable showing line numbers. +			</description> +		</method> +		<method name="is_show_line_numbers_enabled" qualifiers="const"> +			<return type="bool"> +			</return> +			<description> +				Returns true if line numbers are enabled. +			</description> +		</method> +		<method name="set_highlight_all_occurrences"> +			<argument index="0" name="enable" type="bool"> +			</argument> +			<description> +				Set to enable highlighting all occurrences of the current selection. +			</description> +		</method> +		<method name="is_highlight_all_occurrences_enabled" qualifiers="const"> +			<return type="bool"> +			</return> +			<description> +				Returns true if highlight all occurrences is enabled. +			</description> +		</method>  		<method name="set_syntax_coloring">  			<argument index="0" name="enable" type="bool">  			</argument> @@ -39436,6 +39517,8 @@  		</theme_item>  		<theme_item name="completion_existing_color" type="Color">  		</theme_item> +		<theme_item name="completion_font_color" type="Color"> +		</theme_item>  		<theme_item name="completion_lines" type="int">  		</theme_item>  		<theme_item name="completion_max_width" type="int"> @@ -39456,18 +39539,28 @@  		</theme_item>  		<theme_item name="font_color_selected" type="Color">  		</theme_item> +		<theme_item name="function_color" type="Color"> +		</theme_item> +		<theme_item name="line_number_color" type="Color"> +		</theme_item>  		<theme_item name="line_spacing" type="int">  		</theme_item>  		<theme_item name="mark_color" type="Color">  		</theme_item> +		<theme_item name="member_variable_color" type="Color"> +		</theme_item>  		<theme_item name="normal" type="StyleBox">  		</theme_item> +		<theme_item name="number_color" type="Color"> +		</theme_item>  		<theme_item name="selection_color" type="Color">  		</theme_item>  		<theme_item name="symbol_color" type="Color">  		</theme_item>  		<theme_item name="tab" type="Texture">  		</theme_item> +		<theme_item name="word_highlighted_color" type="Color"> +		</theme_item>  	</theme_items>  </class>  <class name="Texture" inherits="Resource" category="Core"> diff --git a/drivers/builtin_openssl2/openssl/opensslconf.h b/drivers/builtin_openssl2/openssl/opensslconf.h index 25429e94d6..c86bb60b94 100644 --- a/drivers/builtin_openssl2/openssl/opensslconf.h +++ b/drivers/builtin_openssl2/openssl/opensslconf.h @@ -213,8 +213,13 @@ extern "C" {  #ifdef OPENSSL_USE_64_BITS -#define SIXTY_FOUR_BIT_LONG -#undef SIXTY_FOUR_BIT +# ifdef _WIN32 +#  undef SIXTY_FOUR_BIT_LONG +#  define SIXTY_FOUR_BIT +# else +#  define SIXTY_FOUR_BIT_LONG +#  undef SIXTY_FOUR_BIT +# endif  #undef THIRTY_TWO_BIT  #else diff --git a/main/input_default.cpp b/main/input_default.cpp index 4fcb450bce..945898f1f3 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -30,6 +30,7 @@  #include "servers/visual_server.h"  #include "os/os.h"  #include "input_map.h" +#include "scene/resources/texture.h"  void InputDefault::SpeedTrack::update(const Vector2& p_delta_p) { @@ -101,7 +102,7 @@ bool InputDefault::is_action_pressed(const StringName& p_action) {  	const List<InputEvent> *alist = InputMap::get_singleton()->get_action_list(p_action);  	if (!alist) -		return NULL; +		return false;  	for (const List<InputEvent>::Element *E=alist->front();E;E=E->next()) { @@ -220,18 +221,18 @@ void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_  			};  		};  		js.uid = uidname; -		//printf("looking for mappings for guid %ls\n", uidname.c_str()); +		js.connected = true;  		int mapping = fallback_mapping;  		for (int i=0; i < map_db.size(); i++) {  			if (js.uid == map_db[i].uid) {  				mapping = i;  				js.name = map_db[i].name; -				//printf("found mapping\n");  			};  		};  		js.mapping = mapping;  	}  	else { +		js.connected = false;  		for (int i = 0; i < JOY_BUTTON_MAX; i++) {  			if (i < JOY_AXIS_MAX) @@ -463,9 +464,11 @@ void InputDefault::set_custom_mouse_cursor(const RES& p_cursor,const Vector2& p_  		set_mouse_mode(MOUSE_MODE_VISIBLE);  		VisualServer::get_singleton()->cursor_set_visible(false);  	} else { +		Ref<AtlasTexture> atex = custom_cursor; +		Rect2 region = atex.is_valid() ? atex->get_region() : Rect2();  		set_mouse_mode(MOUSE_MODE_HIDDEN);  		VisualServer::get_singleton()->cursor_set_visible(true); -		VisualServer::get_singleton()->cursor_set_texture(custom_cursor->get_rid(),p_hotspot); +		VisualServer::get_singleton()->cursor_set_texture(custom_cursor->get_rid(),p_hotspot, 0, region);  		VisualServer::get_singleton()->cursor_set_pos(get_mouse_pos());  	}  } @@ -1039,3 +1042,15 @@ bool InputDefault::is_joy_mapped(int p_device) {  String InputDefault::get_joy_guid_remapped(int p_device) const {  	return joy_names[p_device].uid;  } + +Array InputDefault::get_connected_joysticks() { +	Array ret; +	Map<int, Joystick>::Element *elem = joy_names.front(); +	while (elem) { +		if (elem->get().connected) { +			ret.push_back(elem->key()); +		} +		elem = elem->next(); +	} +	return ret; +} diff --git a/main/input_default.h b/main/input_default.h index c7fef8374c..644af15e3b 100644 --- a/main/input_default.h +++ b/main/input_default.h @@ -75,6 +75,7 @@ class InputDefault : public Input {  	struct Joystick {  		StringName name;  		StringName uid; +		bool connected;  		bool last_buttons[JOY_BUTTON_MAX + 19]; //apparently SDL specifies 35 possible buttons on android  		float last_axis[JOY_AXIS_MAX];  		float filter; @@ -93,6 +94,7 @@ class InputDefault : public Input {  				last_buttons[i] = false;  			} +			connected = false;  			last_hat = HAT_MASK_CENTER;  			filter = 0.01f;  			mapping = -1; @@ -168,6 +170,7 @@ public:  	virtual float get_joy_axis(int p_device,int p_axis);  	String get_joy_name(int p_idx); +	virtual Array get_connected_joysticks();  	virtual Vector2 get_joy_vibration_strength(int p_device);  	virtual float get_joy_vibration_duration(int p_device);  	virtual uint64_t get_joy_vibration_timestamp(int p_device); diff --git a/main/main.cpp b/main/main.cpp index adaebab1d4..aa8540632f 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1504,6 +1504,8 @@ bool Main::start() {  		if (project_manager_request || (script=="" && test=="" && game_path=="" && !editor)) {  			ProjectManager *pmanager = memnew( ProjectManager ); +			ProgressDialog *progress_dialog = memnew( ProgressDialog ); +			pmanager->add_child(progress_dialog);  			sml->get_root()->add_child(pmanager);  			OS::get_singleton()->set_context(OS::CONTEXT_PROJECTMAN);  		} diff --git a/methods.py b/methods.py index 7128b334ec..74c282b8cf 100755 --- a/methods.py +++ b/methods.py @@ -1326,7 +1326,9 @@ def android_add_aidl_dir(self,subpath):  def android_add_jni_dir(self,subpath):  	base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+subpath  	self.android_jni_dirs.append(base_path) - +def android_add_default_config(self,config): +	self.android_default_config.append(config) +	  def android_add_to_manifest(self,file):  	base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+file  	f = open(base_path,"rb") diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index e87bd99e4f..6a7cd5eb8c 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -1536,6 +1536,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {  					return;  				}  				tokenizer->advance(); +				if(tokenizer->get_token()==GDTokenizer::TK_SEMICOLON) { +					// Ignore semicolon after 'pass' +					tokenizer->advance(); +				}  			} break;  			case GDTokenizer::TK_PR_VAR: {  				//variale declaration and (eventual) initialization diff --git a/platform/android/SCsub b/platform/android/SCsub index c8feac8690..60bb4bd613 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -79,6 +79,11 @@ for x in env.android_jni_dirs:  gradle_asset_dirs_text="" +gradle_default_config_text="" + +for x in env.android_default_config: +	gradle_default_config_text+=x+"\n\t\t" +  gradle_text = gradle_text.replace("$$GRADLE_REPOSITORY_URLS$$",gradle_maven_repos_text)  gradle_text = gradle_text.replace("$$GRADLE_DEPENDENCIES$$",gradle_maven_dependencies_text)  gradle_text = gradle_text.replace("$$GRADLE_JAVA_DIRS$$",gradle_java_dirs_text) @@ -86,6 +91,7 @@ gradle_text = gradle_text.replace("$$GRADLE_RES_DIRS$$",gradle_res_dirs_text)  gradle_text = gradle_text.replace("$$GRADLE_ASSET_DIRS$$",gradle_asset_dirs_text)  gradle_text = gradle_text.replace("$$GRADLE_AIDL_DIRS$$",gradle_aidl_dirs_text)  gradle_text = gradle_text.replace("$$GRADLE_JNI_DIRS$$",gradle_jni_dirs_text) +gradle_text = gradle_text.replace("$$GRADLE_DEFAULT_CONFIG$$",gradle_default_config_text)  gradle_baseout.write( gradle_text ) @@ -103,4 +109,22 @@ pp_baseout.write( manifest )  env_android.SharedLibrary("#bin/libgodot",[android_objects],SHLIBSUFFIX=env["SHLIBSUFFIX"]) -#env.Command('#bin/libgodot_android.so', '#platform/android/libgodot_android.so', Copy('bin/libgodot_android.so', 'platform/android/libgodot_android.so')) + +lib_arch_dir = '' +if env['android_arch'] == 'armv6': +	lib_arch_dir = 'armeabi' +elif env['android_arch'] == 'armv7': +	lib_arch_dir = 'armeabi-v7a' +elif env['android_arch'] == 'x86': +	lib_arch_dir = 'x86' +else: +	print 'WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin' + +if lib_arch_dir != '': +	if env['target'] == 'release': +		lib_type_dir = 'release' +	else: # release_debug, debug +		lib_type_dir = 'debug' +		 +	out_dir = '#platform/android/java/libs/'+lib_type_dir+'/'+lib_arch_dir +	env_android.Command(out_dir+'/libgodot_android.so', '#bin/libgodot'+env['SHLIBSUFFIX'], Move("$TARGET", "$SOURCE")) diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template index 1e1461ef29..24951b921b 100644 --- a/platform/android/build.gradle.template +++ b/platform/android/build.gradle.template @@ -3,7 +3,7 @@ buildscript {  		jcenter()  	}  	dependencies { -		classpath 'com.android.tools.build:gradle:1.3.1' +		classpath 'com.android.tools.build:gradle:2.1.0'  	}  } @@ -39,6 +39,12 @@ android {  	defaultConfig {  		minSdkVersion 14  		targetSdkVersion 23 +		$$GRADLE_DEFAULT_CONFIG$$ +	} +	// Both signing and zip-aligning will be done at export time +	buildTypes.all { buildType -> +		buildType.zipAlignEnabled false +		buildType.signingConfig null  	}  	sourceSets {  		main { @@ -65,8 +71,17 @@ android {  				$$GRADLE_JNI_DIRS$$  			]  		} - +		debug.jniLibs.srcDirs = [ +			'libs/debug' +			$$GRADLE_JNI_DIRS$$ +		] +		release.jniLibs.srcDirs = [ +			'libs/release' +			$$GRADLE_JNI_DIRS$$ +		] +	} +	applicationVariants.all { variant -> +		// ApplicationVariant is undocumented, but this method is widely used; may break with another version of the Android Gradle plugin +		variant.outputs.get(0).setOutputFile(new File("${projectDir}/../../../bin", "android_${variant.name}.apk"))  	} - -  } diff --git a/platform/android/detect.py b/platform/android/detect.py index ba6b73a89f..6fd0b81d91 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -23,7 +23,7 @@ def get_opts():  			('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),  			('NDK_TARGET', 'toolchain to use for the NDK',os.environ.get("NDK_TARGET", "arm-linux-androideabi-4.9")),  			('NDK_TARGET_X86', 'toolchain to use for the NDK x86',os.environ.get("NDK_TARGET_X86", "x86-4.9")), -			('ndk_platform', 'compile for platform: (android-<api> , example: android-15)',"android-15"), +			('ndk_platform', 'compile for platform: (android-<api> , example: android-14)',"android-14"),  			('android_arch', 'select compiler architecture: (armv7/armv6/x86)',"armv7"),  			('android_neon','enable neon (armv7 only)',"yes"),  			('android_stl','enable STL support in android port (for modules)',"no") diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 872f047c95..83f7292716 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1166,7 +1166,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d  			skip=true;  		} -		if (file=="lib/armeabi/libgodot_android.so" && !export_arm) { +		if (file.match("lib/armeabi*/libgodot_android.so") && !export_arm) {  			skip=true;  		} diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp index da8ceaff14..ea33e9a67b 100644 --- a/platform/android/file_access_jandroid.cpp +++ b/platform/android/file_access_jandroid.cpp @@ -182,8 +182,10 @@ bool FileAccessJAndroid::file_exists(const String& p_path) {  	jstring js = env->NewStringUTF(path.utf8().get_data());  	int res = env->CallIntMethod(io,_file_open,js,false); -	if (res<=0) +	if (res<=0) { +		env->DeleteLocalRef(js);  		return false; +	}  	env->CallVoidMethod(io,_file_close,res);  	env->DeleteLocalRef(js);  	return true; diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.properties b/platform/android/java/gradle/wrapper/gradle-wrapper.properties index 0c71e760dc..d57051703e 100644 --- a/platform/android/java/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/java/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME  distributionPath=wrapper/dists  zipStoreBase=GRADLE_USER_HOME  zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 89de969cff..b0a50ca4b8 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -2178,6 +2178,68 @@ String OS_Windows::get_locale() const {  	return "en";  } + +OS::LatinKeyboardVariant OS_Windows::get_latin_keyboard_variant() const { +	 +	unsigned long azerty[] = {  +		0x00020401, // Arabic (102) AZERTY +		0x0001080c, // Belgian (Comma) +		0x0000080c, // Belgian French +		0x0000040c, // French +		0 // <--- STOP MARK +	}; +	unsigned long qwertz[] = { +		0x0000041a, // Croation +		0x00000405, // Czech +		0x00000407, // German +		0x00010407, // German (IBM) +		0x0000040e, // Hungarian +		0x0000046e, // Luxembourgish +		0x00010415, // Polish (214) +		0x00000418, // Romanian (Legacy) +		0x0000081a, // Serbian (Latin) +		0x0000041b, // Slovak +		0x00000424, // Slovenian +		0x0001042e, // Sorbian Extended +		0x0002042e, // Sorbian Standard +		0x0000042e, // Sorbian Standard (Legacy) +		0x0000100c, // Swiss French +		0x00000807, // Swiss German +		0 // <--- STOP MARK +	}; +	unsigned long dvorak[] = { +		0x00010409, // US-Dvorak +		0x00030409, // US-Dvorak for left hand +		0x00040409, // US-Dvorak for right hand +		0 // <--- STOP MARK +	}; + +	char name[ KL_NAMELENGTH + 1 ]; name[0] = 0; +	GetKeyboardLayoutNameA( name ); + +	unsigned long hex = strtoul(name, NULL, 16); + +	int i=0; +	while( azerty[i] != 0 ) { +		if (azerty[i] == hex) return LATIN_KEYBOARD_AZERTY; +		i++; +	} + +	i = 0; +	while( qwertz[i] != 0 ) { +		if (qwertz[i] == hex) return LATIN_KEYBOARD_QWERTZ; +		i++; +	} +	 +	i = 0; +	while( dvorak[i] != 0 ) { +		if (dvorak[i] == hex) return LATIN_KEYBOARD_DVORAK; +		i++;  +	} + +	return LATIN_KEYBOARD_QWERTY; +} +  void OS_Windows::release_rendering_thread() {  	gl_context->release_current(); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index d2249bf352..5acb300c0f 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -266,6 +266,7 @@ public:  	virtual String get_executable_path() const;  	virtual String get_locale() const; +	virtual LatinKeyboardVariant get_latin_keyboard_variant() const;   	virtual void move_window_to_foreground();  	virtual String get_data_dir() const; diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 27e07a35be..f98a50e3e0 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -408,6 +408,35 @@ void Camera2D::force_update_scroll() {  	_update_scroll();  } +void Camera2D::reset_smoothing() { + +	smoothed_camera_pos = camera_pos; +	_update_scroll(); +} + +void Camera2D::align() { + +	Size2 screen_size = get_viewport_rect().size; +	screen_size=get_viewport_rect().size; +	Point2 current_camera_pos = get_global_transform().get_origin(); +	if (anchor_mode==ANCHOR_MODE_DRAG_CENTER) { +		if (h_ofs<0) { +			camera_pos.x = current_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs; +		} else { +			camera_pos.x = current_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs; +		} +		if (v_ofs<0) { +			camera_pos.y = current_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs; +		} else { +			camera_pos.y = current_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs; +		} +	} else if (anchor_mode==ANCHOR_MODE_FIXED_TOP_LEFT){ + +		camera_pos=current_camera_pos; +	} + +	_update_scroll(); +}  void Camera2D::set_follow_smoothing(float p_speed) { @@ -543,6 +572,8 @@ void Camera2D::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("is_follow_smoothing_enabled"),&Camera2D::is_follow_smoothing_enabled);  	ObjectTypeDB::bind_method(_MD("force_update_scroll"),&Camera2D::force_update_scroll); +	ObjectTypeDB::bind_method(_MD("reset_smoothing"),&Camera2D::reset_smoothing); +	ObjectTypeDB::bind_method(_MD("align"),&Camera2D::align);  	ObjectTypeDB::bind_method(_MD("_set_old_smoothing","follow_smoothing"),&Camera2D::_set_old_smoothing); diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 22e5bc382a..b3f55d798d 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -128,6 +128,8 @@ public:  	Vector2 get_camera_pos() const;  	void force_update_scroll(); +	void reset_smoothing(); +	void align();  	Camera2D();  }; diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index bc5bff3b8e..eb4f457975 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -948,6 +948,15 @@ Ref<CanvasItemMaterial> CanvasItem::get_material() const{  	return material;  } +Vector2 CanvasItem::make_canvas_pos_local(const Vector2& screen_point) const { + +	ERR_FAIL_COND_V(!is_inside_tree(),screen_point); + +	Matrix32 local_matrix = (get_canvas_transform() *  +			get_global_transform()).affine_inverse(); + +	return local_matrix.xform(screen_point); +}  InputEvent CanvasItem::make_input_local(const InputEvent& p_event) const { @@ -1052,6 +1061,8 @@ void CanvasItem::_bind_methods() {  	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); +	ObjectTypeDB::bind_method(_MD("make_canvas_pos_local","screen_point"), +			&CanvasItem::make_canvas_pos_local);  	ObjectTypeDB::bind_method(_MD("make_input_local","event"),&CanvasItem::make_input_local);  	BIND_VMETHOD(MethodInfo("_draw")); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 8a61b449fd..b894310ce2 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -263,6 +263,7 @@ public:  	bool get_use_parent_material() const;  	InputEvent make_input_local(const InputEvent& pevent) const; +	Vector2 make_canvas_pos_local(const Vector2& screen_point) const;  	Vector2 get_global_mouse_pos() const;  	Vector2 get_local_mouse_pos() const; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 1f16b36466..1a4f88c30e 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -222,6 +222,10 @@ void TileMap::_fix_cell_transform(Matrix32& xform,const Cell& p_cell, const Vect  	Size2 s=p_sc;  	Vector2 offset = p_offset; +	 +	if (tile_origin==TILE_ORIGIN_BOTTOM_LEFT) +		offset.y+=cell_size.y; +  	if (s.y > s.x) {  		if ((p_cell.flip_h && (p_cell.flip_v || p_cell.transpose)) || (p_cell.flip_v && !p_cell.transpose)) @@ -240,7 +244,7 @@ void TileMap::_fix_cell_transform(Matrix32& xform,const Cell& p_cell, const Vect  	if (p_cell.flip_h) {  		xform.elements[0].x=-xform.elements[0].x;  		xform.elements[1].x=-xform.elements[1].x; -		if (tile_origin==TILE_ORIGIN_TOP_LEFT) +		if (tile_origin==TILE_ORIGIN_TOP_LEFT || tile_origin==TILE_ORIGIN_BOTTOM_LEFT)  			offset.x=s.x-offset.x;  	}  	if (p_cell.flip_v) { @@ -248,6 +252,12 @@ void TileMap::_fix_cell_transform(Matrix32& xform,const Cell& p_cell, const Vect  		xform.elements[1].y=-xform.elements[1].y;  		if (tile_origin==TILE_ORIGIN_TOP_LEFT)  			offset.y=s.y-offset.y; +		else if (tile_origin==TILE_ORIGIN_BOTTOM_LEFT) { +			if(p_cell.transpose) +				offset.y+=s.y; +			else +				offset.y-=s.y; +		}  	}  	xform.elements[2].x+=offset.x;  	xform.elements[2].y+=offset.y; @@ -411,6 +421,24 @@ void TileMap::_update_dirty_quadrants() {  			if (tile_origin==TILE_ORIGIN_TOP_LEFT) {  				rect.pos+=tile_ofs; +				 +			} else if (tile_origin==TILE_ORIGIN_BOTTOM_LEFT) { +								 +				rect.pos+=tile_ofs; +				 +				if(c.transpose) +				{ +					if(c.flip_h) +						rect.pos.x-=cell_size.x; +					else +						rect.pos.x+=cell_size.x; +				} else { +					if(c.flip_v) +						rect.pos.y-=cell_size.y; +					else +						rect.pos.y+=cell_size.y; +				} +				  			} else if (tile_origin==TILE_ORIGIN_CENTER) {  				rect.pos+=tcenter; @@ -584,6 +612,9 @@ Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const  	q.pos+=get_cell_draw_offset();  	if (tile_origin==TILE_ORIGIN_CENTER)  		q.pos+=cell_size/2; +	else if (tile_origin==TILE_ORIGIN_BOTTOM_LEFT) +		q.pos.y+=cell_size.y; +	  	xform.set_origin( q.pos );  //	q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); @@ -1242,7 +1273,7 @@ void TileMap::_bind_methods() {  	ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/quadrant_size",PROPERTY_HINT_RANGE,"1,128,1"),_SCS("set_quadrant_size"),_SCS("get_quadrant_size"));  	ADD_PROPERTY( PropertyInfo(Variant::MATRIX32,"cell/custom_transform"),_SCS("set_custom_transform"),_SCS("get_custom_transform"));  	ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/half_offset",PROPERTY_HINT_ENUM,"Offset X,Offset Y,Disabled"),_SCS("set_half_offset"),_SCS("get_half_offset")); -	ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/tile_origin",PROPERTY_HINT_ENUM,"Top Left,Center"),_SCS("set_tile_origin"),_SCS("get_tile_origin")); +	ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/tile_origin",PROPERTY_HINT_ENUM,"Top Left,Center,Bottom Left"),_SCS("set_tile_origin"),_SCS("get_tile_origin"));  	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"cell/y_sort"),_SCS("set_y_sort_mode"),_SCS("is_y_sort_mode_enabled"));  	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")); @@ -1264,6 +1295,7 @@ void TileMap::_bind_methods() {  	BIND_CONSTANT( HALF_OFFSET_DISABLED );  	BIND_CONSTANT( TILE_ORIGIN_TOP_LEFT );  	BIND_CONSTANT( TILE_ORIGIN_CENTER ); +	BIND_CONSTANT( TILE_ORIGIN_BOTTOM_LEFT );  } diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index cec5ac0a1b..b48fdde43f 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -54,7 +54,8 @@ public:  	enum TileOrigin {  		TILE_ORIGIN_TOP_LEFT, -		TILE_ORIGIN_CENTER +		TILE_ORIGIN_CENTER, +		TILE_ORIGIN_BOTTOM_LEFT  	}; diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 628edf09de..9488ae37a8 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -445,8 +445,44 @@ void AnimationTreePlayer::_notification(int p_what) {  } +void AnimationTreePlayer::_compute_weights(float *p_fallback_weight, HashMap<NodePath,float> *p_weights, float p_coeff, const HashMap<NodePath,bool> *p_filter, float p_filtered_coeff) { -float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode **r_prev_anim,float p_weight, float p_time, bool p_seek,const HashMap<NodePath,bool> *p_filter, float p_reverse_weight) { +	if (p_filter != NULL) { + +		List<NodePath> key_list; +		p_filter->get_key_list(&key_list); + +		for (List<NodePath>::Element *E = key_list.front();E; E=E->next()) { + +			if ((*p_filter)[E->get()]) { + +				if (p_weights->has(E->get())) { +					(*p_weights)[E->get()] *= p_filtered_coeff; +				} else { +					p_weights->set(E->get(), *p_fallback_weight * p_filtered_coeff); +				} + +			} else if (p_weights->has(E->get())) { +					(*p_weights)[E->get()] *= p_coeff; +			} +		} +	} + +	List<NodePath> key_list; +	p_weights->get_key_list(&key_list); +	 +	for (List<NodePath>::Element *E = key_list.front();E;E=E->next()) { +		if (p_filter == NULL || !p_filter->has(E->get())) { +			(*p_weights)[E->get()] *= p_coeff; +		} +	} + +	*p_fallback_weight *= p_coeff; + +} + + +float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode **r_prev_anim, float p_time, bool p_seek, float p_fallback_weight, HashMap<NodePath,float>* p_weights) {  	ERR_FAIL_COND_V(!node_map.has(p_node), 0);  	NodeBase *nb=node_map[p_node]; @@ -458,7 +494,16 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode  		case NODE_OUTPUT: {  			NodeOut *on = static_cast<NodeOut*>(nb); -			return _process_node(on->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek); + +			for(TrackMap::Element *E=track_map.front();E;E=E->next()) { +				E->get().total_weight = 0; +			} + +			HashMap<NodePath, float> weights; + + + +			return _process_node(on->inputs[0].node,r_prev_anim,p_time,p_seek, p_fallback_weight, &weights);  		} break;  		case NODE_ANIMATION: { @@ -494,15 +539,21 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode  				}  				an->skip=true; +  				for (List<AnimationNode::TrackRef>::Element *E=an->tref.front();E;E=E->next()) {  					NodePath track_path = an->animation->track_get_path(E->get().local_track); -					if (p_filter && p_filter->has(track_path)) { -						E->get().weight = MAX(0, p_reverse_weight); -					} else if(an->filter.has(track_path)) { +					if (an->filter.has(track_path) && an->filter[track_path]) {  						E->get().weight = 0; -						E->get().track->skip = true; +						E->get().track->total_weight += p_fallback_weight;  					} else { -						E->get().weight=p_weight; +						if (p_weights->has(track_path)) { +							float weight = (*p_weights)[track_path]; +							E->get().weight = weight; +							E->get().track->total_weight += weight; +						} else { +							E->get().weight = p_fallback_weight; +							E->get().track->total_weight += p_fallback_weight; +						}  					}  					if (E->get().weight>CMP_EPSILON)  						an->skip=false; @@ -531,7 +582,7 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode  			if (!osn->active) {  				//make it as if this node doesn't exist, pass input 0 by. -				return _process_node(osn->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek,p_filter,p_reverse_weight); +				return _process_node(osn->inputs[0].node,r_prev_anim,p_time,p_seek, p_fallback_weight, p_weights);  			}  			float os_seek = p_seek; @@ -563,16 +614,14 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode  			float main_rem;  			float os_rem; -			float os_reverse_weight = p_reverse_weight; -			if (!osn->filter.empty()) { -				p_filter = &osn->filter; -				p_reverse_weight = p_weight; -				os_reverse_weight = -1; -			} +			HashMap<NodePath, float> os_weights(*p_weights); +			float os_fallback_weight = p_fallback_weight; +			_compute_weights(&p_fallback_weight, p_weights, osn->mix?1.0 : 1.0 - blend, &osn->filter, 1.0); +			_compute_weights(&os_fallback_weight, &os_weights, blend, &osn->filter, 0.0); -			main_rem = _process_node(osn->inputs[0].node,r_prev_anim,(osn->mix?p_weight:p_weight*(1.0-blend)),p_time,p_seek,p_filter,p_reverse_weight); -			os_rem = _process_node(osn->inputs[1].node,r_prev_anim,p_weight*blend,p_time,os_seek,p_filter,os_reverse_weight); +			main_rem = _process_node(osn->inputs[0].node,r_prev_anim,p_time,p_seek, p_fallback_weight, p_weights); +			os_rem = _process_node(osn->inputs[1].node,r_prev_anim,p_time,os_seek, os_fallback_weight, &os_weights);  			if (osn->start) {  				osn->remaining=os_rem; @@ -591,9 +640,11 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode  		case NODE_MIX: {  			MixNode *mn = static_cast<MixNode*>(nb); - -			float rem = _process_node(mn->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek,p_filter,p_reverse_weight); -			_process_node(mn->inputs[1].node,r_prev_anim,p_weight*mn->amount,p_time,p_seek,p_filter,p_reverse_weight); +			HashMap<NodePath, float> mn_weights(*p_weights); +			float mn_fallback_weight = p_fallback_weight; +			_compute_weights(&mn_fallback_weight, &mn_weights, mn->amount); +			float rem = _process_node(mn->inputs[0].node,r_prev_anim, p_time,p_seek,p_fallback_weight,p_weights); +			_process_node(mn->inputs[1].node,r_prev_anim,p_time,p_seek,mn_fallback_weight,&mn_weights);  			return rem;  		} break; @@ -601,16 +652,12 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode  			Blend2Node *bn = static_cast<Blend2Node*>(nb); -			float rem; -			if (!bn->filter.empty()) { - -				rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value),p_time,p_seek,&bn->filter,p_weight); -				_process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value,p_time,p_seek,&bn->filter,-1); - -			} else { -				rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value),p_time,p_seek,p_filter,p_reverse_weight*(1.0-bn->value)); -				_process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value,p_time,p_seek,p_filter,p_reverse_weight*bn->value); -			} +			HashMap<NodePath, float> bn_weights(*p_weights); +			float bn_fallback_weight = p_fallback_weight; +			_compute_weights(&p_fallback_weight,p_weights, 1.0 - bn->value, &bn->filter, 1.0); +			_compute_weights(&bn_fallback_weight,&bn_weights, bn->value, &bn->filter, 0.0); +			float rem = _process_node(bn->inputs[0].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights); +			_process_node(bn->inputs[1].node,r_prev_anim,p_time,p_seek,bn_fallback_weight,&bn_weights);  			return rem;  		} break; @@ -629,19 +676,39 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode  				upper_blend = bn->value;  			} -			rem = _process_node(bn->inputs[1].node,r_prev_anim,p_weight*blend,p_time,p_seek,p_filter,p_reverse_weight*blend); -			_process_node(bn->inputs[2].node,r_prev_anim,p_weight*upper_blend,p_time,p_seek,p_filter,p_reverse_weight*upper_blend); -			_process_node(bn->inputs[0].node,r_prev_anim,p_weight*lower_blend,p_time,p_seek,p_filter,p_reverse_weight*lower_blend); +			HashMap<NodePath, float> upper_weights(*p_weights); +			float upper_fallback_weight = p_fallback_weight; +			HashMap<NodePath, float> lower_weights(*p_weights); +			float lower_fallback_weight = p_fallback_weight; +			_compute_weights(&upper_fallback_weight,&upper_weights, upper_blend); +			_compute_weights(&p_fallback_weight,p_weights, blend); +			_compute_weights(&lower_fallback_weight,&lower_weights, lower_blend); + +			rem = _process_node(bn->inputs[1].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights); +			_process_node(bn->inputs[0].node,r_prev_anim,p_time,p_seek,lower_fallback_weight,&lower_weights); +			_process_node(bn->inputs[2].node,r_prev_anim,p_time,p_seek,upper_fallback_weight,&upper_weights);  			return rem;  		} break;  		case NODE_BLEND4: {  			Blend4Node *bn = static_cast<Blend4Node*>(nb); -			float rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value.x),p_time,p_seek,p_filter,p_reverse_weight*(1.0-bn->value.x)); -			_process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value.x,p_time,p_seek,p_filter,p_reverse_weight*bn->value.x); -			float rem2 = _process_node(bn->inputs[2].node,r_prev_anim,p_weight*(1.0-bn->value.y),p_time,p_seek,p_filter,p_reverse_weight*(1.0-bn->value.y)); -			_process_node(bn->inputs[3].node,r_prev_anim,p_weight*bn->value.y,p_time,p_seek,p_filter,p_reverse_weight*bn->value.y); +			HashMap<NodePath, float> weights1(*p_weights); +			float fallback_weight1 = p_fallback_weight; +			HashMap<NodePath, float> weights2(*p_weights); +			float fallback_weight2 = p_fallback_weight; +			HashMap<NodePath, float> weights3(*p_weights); +			float fallback_weight3 = p_fallback_weight; + +			_compute_weights(&p_fallback_weight,p_weights, 1.0-bn->value.x); +			_compute_weights(&fallback_weight1,&weights1, bn->value.x); +			_compute_weights(&fallback_weight2,&weights2, 1.0-bn->value.y); +			_compute_weights(&fallback_weight3,&weights3, bn->value.y); + +			float rem = _process_node(bn->inputs[0].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights); +			_process_node(bn->inputs[1].node,r_prev_anim,p_time,p_seek,fallback_weight1,&weights1); +			float rem2 = _process_node(bn->inputs[2].node,r_prev_anim,p_time,p_seek,fallback_weight2,&weights2); +			_process_node(bn->inputs[3].node,r_prev_anim,p_time,p_seek,fallback_weight3,&weights3);  			return MAX(rem,rem2); @@ -650,9 +717,9 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode  			TimeScaleNode *tsn = static_cast<TimeScaleNode*>(nb);  			float rem;  			if (p_seek) -				rem = _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time,true,p_filter,p_reverse_weight); +				rem = _process_node(tsn->inputs[0].node,r_prev_anim,p_time,true,p_fallback_weight,p_weights);  			else -				rem = _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time*tsn->scale,false,p_filter,p_reverse_weight); +				rem = _process_node(tsn->inputs[0].node,r_prev_anim,p_time*tsn->scale,false,p_fallback_weight,p_weights);  			if (tsn->scale == 0)  				return INFINITY;  			else @@ -669,16 +736,18 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode  			}  			tsn->seek_pos=-1; -			return _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek, p_filter, p_reverse_weight); +			return _process_node(tsn->inputs[0].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights);  		}   break;  		case NODE_TRANSITION: {  			TransitionNode *tn = static_cast<TransitionNode*>(nb); +			HashMap<NodePath, float> prev_weights(*p_weights); +			float prev_fallback_weight = p_fallback_weight;  			if (tn->prev<0) {  // process current animation, check for transition -				float rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight,p_time,p_seek,p_filter,p_reverse_weight); +				float rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights);  				if (p_seek)  					tn->time=p_time;  				else @@ -698,22 +767,25 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode  				float rem; +				_compute_weights(&p_fallback_weight,p_weights, 1.0-blend); +				_compute_weights(&prev_fallback_weight,&prev_weights, blend); +  				if (!p_seek && tn->switched) { //just switched, seek to start of current -					rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight*(1.0-blend),0,true,p_filter,p_reverse_weight*(1.0-blend)); +					rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,0,true,p_fallback_weight,p_weights);  				} else { -					rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight*(1.0-blend),p_time,p_seek,p_filter,p_reverse_weight*(1.0-blend)); +					rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights);  				}  				tn->switched=false;  				if (p_seek) {  // don't seek prev animation -					_process_node(tn->inputs[tn->prev].node,r_prev_anim,p_weight*blend,0,false,p_filter,p_reverse_weight*blend); +					_process_node(tn->inputs[tn->prev].node,r_prev_anim,0,false,prev_fallback_weight,&prev_weights);  					tn->time=p_time;  				} else { -					_process_node(tn->inputs[tn->prev].node,r_prev_anim,p_weight*blend,p_time,false,p_filter,p_reverse_weight*blend); +					_process_node(tn->inputs[tn->prev].node,r_prev_anim,p_time,false,prev_fallback_weight,&prev_weights);  					tn->time+=p_time;  					tn->prev_xfading-=p_time;  					if (tn->prev_xfading<0) { @@ -750,10 +822,11 @@ void AnimationTreePlayer::_process_animation(float p_delta) {  	AnimationNode *prev=NULL;  	if (reset_request) { -		_process_node(out_name,&prev, 1.0, 0, true); + +		_process_node(out_name,&prev, 0, true);  		reset_request=false;  	} else -		_process_node(out_name,&prev, 1.0, p_delta); +		_process_node(out_name,&prev, p_delta);  	if (dirty_caches) {  		//some animation changed.. ignore this pass @@ -802,7 +875,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) {  				if (tr.track==NULL || tr.local_track<0 || tr.weight < CMP_EPSILON)  					continue; -				float blend=tr.weight; +				float blend=tr.weight / tr.track->total_weight;  				switch(a->track_get_type(tr.local_track)) {  					case Animation::TYPE_TRANSFORM: { ///< Transform a node or a bone. @@ -1904,6 +1977,3 @@ AnimationTreePlayer::~AnimationTreePlayer() {  		node_map.erase( node_map.front() );  	}  } - - - diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h index dae891b5ce..6b5350e9ee 100644 --- a/scene/animation/animation_tree_player.h +++ b/scene/animation/animation_tree_player.h @@ -111,6 +111,7 @@ private:  		Variant value;  		bool skip; +		float total_weight;  	}; @@ -273,7 +274,7 @@ private:  	Map<StringName,NodeBase*> node_map;  	// return time left to finish animation -	float _process_node(const StringName& p_node,AnimationNode **r_prev_anim, float p_weight,float p_step, bool p_seek=false,const HashMap<NodePath,bool> *p_filter=NULL, float p_reverse_weight=0); +	float _process_node(const StringName& p_node,AnimationNode **r_prev_anim,float p_step, bool p_seek=false, float p_fallback_weight = 1.0, HashMap<NodePath,float>* p_weights = NULL);  	void _process_animation(float p_delta);  	bool reset_request; @@ -283,6 +284,8 @@ private:  	void _recompute_caches();  	void _recompute_caches(const StringName& p_node);  	DVector<String> _get_node_list(); +	 +	void _compute_weights(float *p_fallback_weight, HashMap<NodePath,float> *p_weights, float p_coeff, const HashMap<NodePath,bool> *p_filter = NULL, float p_filtered_coeff = 0);  protected: diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index d6c018ae8e..6c47072b33 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -31,6 +31,7 @@  #include "os/os.h"  #include "print_string.h"  #include "label.h" +#include "translation.h"  #ifdef TOOLS_ENABLED  #include "tools/editor/editor_settings.h"  #endif @@ -947,7 +948,7 @@ String LineEdit::get_text() const {  void LineEdit::set_placeholder(String p_text) { -	placeholder = p_text; +	placeholder = XL_MESSAGE(p_text);  	update();  } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 31cef85aa0..b4fa463cde 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -662,8 +662,7 @@ void RichTextLabel::_notification(int p_what) {  		} break;  		case NOTIFICATION_ENTER_TREE: { -			if (use_bbcode) -				parse_bbcode(bbcode); +			set_bbcode(bbcode);  			main->first_invalid_line=0; //invalidate ALL  			update(); @@ -1440,7 +1439,6 @@ bool RichTextLabel::is_scroll_following() const {  Error RichTextLabel::parse_bbcode(const String& p_bbcode) { -  	clear();  	return append_bbcode(p_bbcode);  } @@ -1858,6 +1856,10 @@ void RichTextLabel::set_bbcode(const String& p_bbcode) {  	bbcode=p_bbcode;  	if (is_inside_tree() && use_bbcode)  		parse_bbcode(p_bbcode); +	else { // raw text +		clear(); +		add_text(p_bbcode); +	}  }  String RichTextLabel::get_bbcode() const { @@ -1869,19 +1871,37 @@ void RichTextLabel::set_use_bbcode(bool p_enable) {  	if (use_bbcode==p_enable)  		return;  	use_bbcode=p_enable; -	if (is_inside_tree() && use_bbcode) -		parse_bbcode(bbcode); +	set_bbcode(bbcode);  }  bool RichTextLabel::is_using_bbcode() const {  	return use_bbcode;  } + +String RichTextLabel::get_text() { +	String text = ""; +	Item *it = main; +	while (it) { +		if (it->type == ITEM_TEXT) { +			ItemText *t = static_cast<ItemText*>(it); +			text += t->text; +		} else if (it->type == ITEM_NEWLINE) { +			text += "\n"; +		} else if (it->type == ITEM_INDENT) { +			text += "\t"; +		} +		it=_get_next_item(it,true); +	} +	return text; +} +  void RichTextLabel::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("_input_event"),&RichTextLabel::_input_event);  	ObjectTypeDB::bind_method(_MD("_scroll_changed"),&RichTextLabel::_scroll_changed); +	ObjectTypeDB::bind_method(_MD("get_text"),&RichTextLabel::get_text);  	ObjectTypeDB::bind_method(_MD("add_text","text"),&RichTextLabel::add_text);  	ObjectTypeDB::bind_method(_MD("add_image","image:Texture"),&RichTextLabel::add_image);  	ObjectTypeDB::bind_method(_MD("newline"),&RichTextLabel::add_newline); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 635fe87ad4..5147905a0e 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -280,6 +280,7 @@ protected:  public: +	String get_text();  	void add_text(const String& p_text);  	void add_image(const Ref<Texture>& p_image);  	void add_newline(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 55e1a2cc52..a680d5d873 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -965,6 +965,12 @@ void TextEdit::_notification(int p_what) {  							}  							bool in_highlighted_word = (j >= highlighted_text_col && j < highlighted_text_col+highlighted_text.length()); + +							/* if this is the original highlighted text we don't want to highlight it again */ +							if (cursor.line==line && (cursor.column >= highlighted_text_col && cursor.column <= highlighted_text_col+highlighted_text.length())) { +								in_highlighted_word = false; +							} +  							if (in_highlighted_word) {  								VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w, get_row_height())),cache.word_highlighted_color);  							} @@ -1105,7 +1111,7 @@ void TextEdit::_notification(int p_what) {  					int l = line_from + i;  					ERR_CONTINUE( l < 0 || l>= completion_options.size()); -					Color text_color = cache.font_color; +					Color text_color = cache.completion_font_color;  					for(int j=0;j<color_regions.size();j++) {  						if (completion_options[l].begins_with(color_regions[j].begin_key)) {  							text_color=color_regions[j].color; @@ -3306,6 +3312,7 @@ void TextEdit::_update_caches() {  	cache.completion_background_color=get_color("completion_background_color");  	cache.completion_selected_color=get_color("completion_selected_color");  	cache.completion_existing_color=get_color("completion_existing_color"); +	cache.completion_font_color=get_color("completion_font_color");  	cache.font=get_font("font");  	cache.caret_color=get_color("caret_color");  	cache.line_number_color=get_color("line_number_color"); @@ -3603,6 +3610,10 @@ void TextEdit::set_highlight_all_occurrences(const bool p_enabled) {  	update();  } +bool TextEdit::is_highlight_all_occurrences_enabled() const { +	return highlight_all_occurrences; +} +  int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_search, uint32_t p_search_flags, int p_from_column) {  	int col = -1; @@ -4312,6 +4323,10 @@ void TextEdit::set_show_line_numbers(bool p_show) {  	update();  } +bool TextEdit::is_show_line_numbers_enabled() const { +	return line_numbers; +} +  void TextEdit::set_draw_breakpoint_gutter(bool p_draw) {  	draw_breakpoint_gutter = p_draw;  	update(); @@ -4426,6 +4441,12 @@ void TextEdit::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("redo"),&TextEdit::redo);  	ObjectTypeDB::bind_method(_MD("clear_undo_history"),&TextEdit::clear_undo_history); +	ObjectTypeDB::bind_method(_MD("set_show_line_numbers", "enable"), &TextEdit::set_show_line_numbers); +	ObjectTypeDB::bind_method(_MD("is_show_line_numbers_enabled"), &TextEdit::is_show_line_numbers_enabled); + +	ObjectTypeDB::bind_method(_MD("set_highlight_all_occurrences", "enable"), &TextEdit::set_highlight_all_occurrences); +	ObjectTypeDB::bind_method(_MD("is_highlight_all_occurrences_enabled"), &TextEdit::is_highlight_all_occurrences_enabled); +  	ObjectTypeDB::bind_method(_MD("set_syntax_coloring","enable"),&TextEdit::set_syntax_coloring);  	ObjectTypeDB::bind_method(_MD("is_syntax_coloring_enabled"),&TextEdit::is_syntax_coloring_enabled); @@ -4438,7 +4459,10 @@ void TextEdit::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("menu_option"),&TextEdit::menu_option);  	ObjectTypeDB::bind_method(_MD("get_menu:PopupMenu"),&TextEdit::get_menu); -	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret/caret_blink"), _SCS("cursor_set_blink_enabled"), _SCS("cursor_get_blink_enabled"));; +	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), _SCS("set_show_line_numbers"), _SCS("is_show_line_numbers_enabled")); +	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), _SCS("set_highlight_all_occurrences"), _SCS("is_highlight_all_occurrences_enabled")); + +	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret/caret_blink"), _SCS("cursor_set_blink_enabled"), _SCS("cursor_get_blink_enabled"));  	ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret/caret_blink_speed",PROPERTY_HINT_RANGE,"0.1,10,0.1"), _SCS("cursor_set_blink_speed"),_SCS("cursor_get_blink_speed") );  	ADD_SIGNAL(MethodInfo("cursor_changed")); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index acac687b59..270a1723b1 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -77,6 +77,7 @@ class TextEdit : public Control  {  		Color completion_background_color;  		Color completion_selected_color;  		Color completion_existing_color; +		Color completion_font_color;  		Color caret_color;  		Color line_number_color;  		Color font_color; @@ -427,6 +428,7 @@ public:  	void set_current_search_result(int line, int col);  	void set_highlight_all_occurrences(const bool p_enabled); +	bool is_highlight_all_occurrences_enabled() const;  	bool is_selection_active() const;  	int get_selection_from_line() const;      int get_selection_from_column() const; @@ -468,6 +470,7 @@ public:  	void menu_option(int p_option);  	void set_show_line_numbers(bool p_show); +	bool is_show_line_numbers_enabled() const;  	void set_draw_breakpoint_gutter(bool p_draw);  	bool is_drawing_breakpoint_gutter() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index a3d6ac9714..305a3920da 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1030,7 +1030,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&  				Point2i o = Point2i( ofs+w-s.width, p_pos.y )-cache.offset+p_draw_ofs; -				if (cache.click_type==Cache::CLICK_BUTTON && cache.click_item==p_item && cache.click_column==i && !p_item->cells[i].buttons[j].disabled) { +				if (cache.click_type==Cache::CLICK_BUTTON && cache.click_item==p_item && cache.click_column==i && cache.click_index==j && !p_item->cells[i].buttons[j].disabled) {  					//being pressed  					cache.button_pressed->draw(get_canvas_item(),Rect2(o,s));  				} diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 7ed83f50f8..182bc5dabc 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -473,6 +473,7 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F  	t->set_color("completion_selected_color", "TextEdit",Color::html("434244"));  	t->set_color("completion_existing_color", "TextEdit",Color::html("21dfdfdf"));  	t->set_color("completion_scroll_color","TextEdit", control_font_color_pressed ); +	t->set_color("completion_font_color","TextEdit", Color::html("aaaaaa"));  	t->set_color("font_color","TextEdit", control_font_color );  	t->set_color("font_color_selected","TextEdit", Color(0,0,0) );  	t->set_color("selection_color","TextEdit", font_color_selection ); @@ -482,6 +483,11 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F  	t->set_color("caret_color","TextEdit", control_font_color );  	t->set_color("symbol_color","TextEdit", control_font_color_hover );  	t->set_color("brace_mismatch_color","TextEdit", Color(1,0.2,0.2) ); +	t->set_color("line_number_color","TextEdit",Color::html("66aaaaaa")); +	t->set_color("function_color","TextEdit",Color::html("66a2ce")); +	t->set_color("member_variable_color","TextEdit",Color::html("e64e59")); +	t->set_color("number_color","TextEdit",Color::html("EB9532")); +	t->set_color("word_highlighted_color","TextEdit",Color(0.8,0.9,0.9,0.15));  	t->set_constant("completion_lines","TextEdit", 7 );  	t->set_constant("completion_max_width","TextEdit", 50 ); diff --git a/scene/resources/sample_library.cpp b/scene/resources/sample_library.cpp index 73517b180e..67481f267d 100644 --- a/scene/resources/sample_library.cpp +++ b/scene/resources/sample_library.cpp @@ -106,9 +106,9 @@ void SampleLibrary::remove_sample(const StringName& p_name) {  	sample_map.erase(p_name);  } -void SampleLibrary::get_sample_list(List<StringName> *p_samples) { +void SampleLibrary::get_sample_list(List<StringName> *p_samples) const { -	for(Map<StringName,SampleData >::Element *E=sample_map.front();E;E=E->next()) { +	for(const Map<StringName,SampleData >::Element *E=sample_map.front();E;E=E->next()) {  		p_samples->push_back(E->key());  	} @@ -177,7 +177,20 @@ float SampleLibrary::sample_get_pitch_scale(const StringName& p_name) const{  	return sample_map[p_name].pitch_scale;  } +Array SampleLibrary::_get_sample_list() const { +	List<StringName> snames; +	get_sample_list(&snames); + +	snames.sort_custom<StringName::AlphCompare>(); + +	Array ret; +	for (List<StringName>::Element *E=snames.front();E;E=E->next()) { +		ret.push_back(E->get()); +	} + +	return ret; +}  void SampleLibrary::_bind_methods() { @@ -186,6 +199,8 @@ void SampleLibrary::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("has_sample","name"),&SampleLibrary::has_sample );  	ObjectTypeDB::bind_method(_MD("remove_sample","name"),&SampleLibrary::remove_sample ); +	ObjectTypeDB::bind_method(_MD("get_sample_list"),&SampleLibrary::_get_sample_list ); +  	ObjectTypeDB::bind_method(_MD("sample_set_volume_db","name","db"),&SampleLibrary::sample_set_volume_db );  	ObjectTypeDB::bind_method(_MD("sample_get_volume_db","name"),&SampleLibrary::sample_get_volume_db ); diff --git a/scene/resources/sample_library.h b/scene/resources/sample_library.h index 8377967106..e572aa215a 100644 --- a/scene/resources/sample_library.h +++ b/scene/resources/sample_library.h @@ -47,6 +47,8 @@ class SampleLibrary : public Resource {  	};  	Map<StringName,SampleData > sample_map; + +	Array _get_sample_list() const;  protected:  	bool _set(const StringName& p_name, const Variant& p_value); @@ -66,7 +68,7 @@ public:  	void sample_set_pitch_scale(const StringName& p_name, float p_pitch);  	float sample_get_pitch_scale(const StringName& p_name) const;  	Ref<Sample> get_sample(const StringName& p_name) const; -	void get_sample_list(List<StringName> *p_samples); +	void get_sample_list(List<StringName> *p_samples) const;  	void remove_sample(const StringName& p_name);  	StringName get_sample_idx(int p_idx) const; diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 526179c41f..d89ea887fa 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -4448,12 +4448,13 @@ void VisualServerRaster::cursor_set_rotation(float p_rotation, int p_cursor) {  	cursors[p_cursor].rot = p_rotation;  }; -void VisualServerRaster::cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor) { +void VisualServerRaster::cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor, const Rect2 &p_region) {  	VS_CHANGED;  	ERR_FAIL_INDEX(p_cursor, MAX_CURSORS);  	cursors[p_cursor].texture = p_texture;  	cursors[p_cursor].center = p_center_offset; +	cursors[p_cursor].region = p_region;  };  void VisualServerRaster::cursor_set_visible(bool p_visible, int p_cursor) { @@ -7530,8 +7531,13 @@ void VisualServerRaster::_draw_cursors_and_margins() {  		RID tex = cursors[i].texture?cursors[i].texture:default_cursor_texture;  		ERR_CONTINUE( !tex ); -		Point2 size(texture_get_width(tex), texture_get_height(tex)); -		rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), 0, Rect2(), tex, Color(1, 1, 1, 1)); +		if (cursors[i].region.has_no_area()) { +			Point2 size(texture_get_width(tex), texture_get_height(tex)); +			rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), 0, Rect2(), tex, Color(1, 1, 1, 1)); +		} else { +			Point2 size = cursors[i].region.size; +			rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), Rasterizer::CANVAS_RECT_REGION, cursors[i].region, tex, Color(1, 1, 1, 1)); +		}  	}; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 0480d9f5cb..228a4a7c44 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -544,10 +544,12 @@ class VisualServerRaster : public VisualServer {  		RID texture;  		Point2 center;  		bool visible; +		Rect2 region;  		Cursor() {  			rot = 0;  			visible = false; +			region = Rect2();  		};  	}; @@ -1240,7 +1242,7 @@ public:  	/* CURSOR */  	virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0); // radians -	virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor=0); +	virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor=0, const Rect2 &p_region=Rect2());  	virtual void cursor_set_visible(bool p_visible, int p_cursor = 0);  	virtual void cursor_set_pos(const Point2& p_pos, int p_cursor = 0); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index a97b232c03..8c39b0bea1 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -680,7 +680,7 @@ public:  	/* CURSOR */  	FUNC2(cursor_set_rotation,float , int ); // radians -	FUNC3(cursor_set_texture,RID , const Point2 &, int ); +	FUNC4(cursor_set_texture,RID , const Point2 &, int, const Rect2 &);  	FUNC2(cursor_set_visible,bool , int );  	FUNC2(cursor_set_pos,const Point2& , int ); diff --git a/servers/visual_server.h b/servers/visual_server.h index f330a6faee..64318dfd72 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -1110,7 +1110,7 @@ public:  	/* CURSOR */  	virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0)=0; // radians -	virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset = Point2(0, 0), int p_cursor=0)=0; +	virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset = Point2(0, 0), int p_cursor=0, const Rect2 &p_region=Rect2())=0;  	virtual void cursor_set_visible(bool p_visible, int p_cursor = 0)=0;  	virtual void cursor_set_pos(const Point2& p_pos, int p_cursor = 0)=0; diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp index c7b78b980f..9eb6b4013f 100644 --- a/tools/editor/animation_editor.cpp +++ b/tools/editor/animation_editor.cpp @@ -693,11 +693,103 @@ void AnimationKeyEditor::_menu_add_track(int p_type) {  	}  } +void AnimationKeyEditor::_anim_duplicate_keys(bool transpose) { +	//duplicait! +	if (selection.size() && animation.is_valid() && selected_track>=0 && selected_track<animation->get_track_count()) { + +		int top_track=0x7FFFFFFF; +		float top_time = 1e10; +		for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { + +			const SelectedKey &sk = E->key(); + +			float t = animation->track_get_key_time(sk.track,sk.key); +			if (t<top_time) +				top_time=t; +			if (sk.track<top_track) +				top_track=sk.track; + +		} +		ERR_FAIL_COND( top_track == 0x7FFFFFFF || top_time==1e10 ); + +		// + +		int start_track = transpose ? selected_track : top_track; + +		undo_redo->create_action(TTR("Anim Duplicate Keys")); + +		List<Pair<int,float> > new_selection_values; + +		for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { + +			const SelectedKey &sk = E->key(); + +			float t = animation->track_get_key_time(sk.track,sk.key); + +			float dst_time = t+(timeline_pos - top_time); +			int dst_track = sk.track + (start_track - top_track); + +			if (dst_track < 0 || dst_track>= animation->get_track_count()) +				continue; + +			if (animation->track_get_type(dst_track) != animation->track_get_type(sk.track)) +				continue; + +			int existing_idx = animation->track_find_key(dst_track,dst_time,true); + +			undo_redo->add_do_method(animation.ptr(),"track_insert_key",dst_track,dst_time,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key)); +			undo_redo->add_undo_method(animation.ptr(),"track_remove_key_at_pos",dst_track,dst_time); + +			Pair<int,float> p; +			p.first=dst_track; +			p.second=dst_time; +			new_selection_values.push_back( p ); + +			if (existing_idx!=-1) { + +				undo_redo->add_undo_method(animation.ptr(),"track_insert_key",dst_track,dst_time,animation->track_get_key_value(dst_track,existing_idx),animation->track_get_key_transition(dst_track,existing_idx)); + +			} + +		} + +		undo_redo->commit_action(); + +		//reselect duplicated + +		Map<SelectedKey,KeyInfo> new_selection; +		for (List<Pair<int,float> >::Element *E=new_selection_values.front();E;E=E->next()) { + +			int track=E->get().first; +			float time = E->get().second; + +			int existing_idx = animation->track_find_key(track,time,true); + +			if (existing_idx==-1) +				continue; +			SelectedKey sk2; +			sk2.track=track; +			sk2.key=existing_idx; + +			KeyInfo ki; +			ki.pos=time; + +			new_selection[sk2]=ki; + +		} + + +		selection=new_selection; +		track_editor->update(); +		_edit_if_single_selection(); + +	} +} +  void AnimationKeyEditor::_menu_track(int p_type) {  	ERR_FAIL_COND(!animation.is_valid()); -  	last_menu_track_opt=p_type;  	switch(p_type) { @@ -765,108 +857,7 @@ void AnimationKeyEditor::_menu_track(int p_type) {  		case TRACK_MENU_DUPLICATE:  		case TRACK_MENU_DUPLICATE_TRANSPOSE: { - -			//duplicait! -			if (selection.size() && animation.is_valid() && selected_track>=0 && selected_track<animation->get_track_count()) { - - -				int top_track=0x7FFFFFFF; -				float top_time = 1e10; -				for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { - -					const SelectedKey &sk = E->key(); - -					float t = animation->track_get_key_time(sk.track,sk.key); -					if (t<top_time) -						top_time=t; -					if (sk.track<top_track) -						top_track=sk.track; - - -				} -				ERR_FAIL_COND( top_track == 0x7FFFFFFF || top_time==1e10 ); - -				// - -				int start_track = p_type==TRACK_MENU_DUPLICATE_TRANSPOSE ? selected_track : top_track; - - -				undo_redo->create_action(TTR("Anim Duplicate Keys")); - -				List<Pair<int,float> > new_selection_values; - -				for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { - -					const SelectedKey &sk = E->key(); - -					float t = animation->track_get_key_time(sk.track,sk.key); - -					float dst_time = t+(timeline_pos - top_time); -					int dst_track = sk.track + (start_track - top_track); - -					if (dst_track < 0 || dst_track>= animation->get_track_count()) -						continue; - -					if (animation->track_get_type(dst_track) != animation->track_get_type(sk.track)) -						continue; - -					int existing_idx = animation->track_find_key(dst_track,dst_time,true); - -					undo_redo->add_do_method(animation.ptr(),"track_insert_key",dst_track,dst_time,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key)); -					undo_redo->add_undo_method(animation.ptr(),"track_remove_key_at_pos",dst_track,dst_time); - -					Pair<int,float> p; -					p.first=dst_track; -					p.second=dst_time; -					new_selection_values.push_back( p ); - -					if (existing_idx!=-1) { - -						undo_redo->add_undo_method(animation.ptr(),"track_insert_key",dst_track,dst_time,animation->track_get_key_value(dst_track,existing_idx),animation->track_get_key_transition(dst_track,existing_idx)); - -					} - - - -				} - -				undo_redo->commit_action(); - -				//reselect duplicated - -				Map<SelectedKey,KeyInfo> new_selection; -				for (List<Pair<int,float> >::Element *E=new_selection_values.front();E;E=E->next()) { - - -					int track=E->get().first; -					float time = E->get().second; - -					int existing_idx = animation->track_find_key(track,time,true); - -					if (existing_idx==-1) -						continue; -					SelectedKey sk2; -					sk2.track=track; -					sk2.key=existing_idx; - -					KeyInfo ki; -					ki.pos=time; - - -					new_selection[sk2]=ki; - - -				} - - -				selection=new_selection; -				track_editor->update(); -				_edit_if_single_selection(); - - -			} - - +			_anim_duplicate_keys(p_type==TRACK_MENU_DUPLICATE_TRANSPOSE);  		} break;  		case TRACK_MENU_SET_ALL_TRANS_LINEAR:  		case TRACK_MENU_SET_ALL_TRANS_CONSTANT: @@ -1618,9 +1609,7 @@ void AnimationKeyEditor::_track_menu_selected(int p_idx) {  		undo_redo->add_do_method(animation.ptr(),"track_set_interpolation_type",interp_editing,p_idx);  		undo_redo->add_undo_method(animation.ptr(),"track_set_interpolation_type",interp_editing,animation->track_get_interpolation_type(interp_editing));  		undo_redo->commit_action(); -	} - -	if (cont_editing!=-1) { +	} else if (cont_editing!=-1) {  		ERR_FAIL_INDEX(cont_editing,animation->get_track_count()); @@ -1628,6 +1617,16 @@ void AnimationKeyEditor::_track_menu_selected(int p_idx) {  		undo_redo->add_do_method(animation.ptr(),"value_track_set_update_mode",cont_editing,p_idx);  		undo_redo->add_undo_method(animation.ptr(),"value_track_set_update_mode",cont_editing,animation->value_track_get_update_mode(cont_editing));  		undo_redo->commit_action(); +	} else { +		switch (p_idx) { + +			case RIGHT_MENU_DUPLICATE: +				_anim_duplicate_keys(); break; +			case RIGHT_MENU_DUPLICATE_TRANSPOSE: +				_anim_duplicate_keys(true); break; +			case RIGHT_MENU_REMOVE: +				_anim_delete_keys(); break; +		}  	}  } @@ -1789,6 +1788,25 @@ bool AnimationKeyEditor::_edit_if_single_selection() {  } +void AnimationKeyEditor::_anim_delete_keys() { +	if (selection.size()) { +		undo_redo->create_action(TTR("Anim Delete Keys")); + +		for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { + +			undo_redo->add_do_method(animation.ptr(),"track_remove_key",E->key().track,E->key().key); +			undo_redo->add_undo_method(animation.ptr(),"track_insert_key",E->key().track,E->get().pos,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key)); + +		} +		undo_redo->add_do_method(this,"_clear_selection_for_anim",animation); +		undo_redo->add_undo_method(this,"_clear_selection_for_anim",animation); +		undo_redo->commit_action(); +		//selection.clear(); +		accept_event(); +		_edit_if_single_selection(); +	} +} +  void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {  	Control *te=track_editor; @@ -1859,22 +1877,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {  			} else if (p_input.key.scancode==KEY_DELETE && p_input.key.pressed && click.click==ClickOver::CLICK_NONE) { -				if (selection.size()) { -					undo_redo->create_action(TTR("Anim Delete Keys")); - -					for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { - -						undo_redo->add_do_method(animation.ptr(),"track_remove_key",E->key().track,E->key().key); -						undo_redo->add_undo_method(animation.ptr(),"track_insert_key",E->key().track,E->get().pos,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key)); - -					} -					undo_redo->add_do_method(this,"_clear_selection_for_anim",animation); -					undo_redo->add_undo_method(this,"_clear_selection_for_anim",animation); -					undo_redo->commit_action(); -					//selection.clear(); -					accept_event(); -					_edit_if_single_selection(); -				} +				_anim_delete_keys();  			} else if (animation.is_valid() && animation->get_track_count()>0) {  				if (p_input.is_pressed() && (p_input.is_action("ui_up") || p_input.is_action("ui_page_up"))) { @@ -1934,6 +1937,116 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {  				v_scroll->set_val( v_scroll->get_val() + v_scroll->get_page() / 8 );  			} +			if (mb.button_index==BUTTON_RIGHT && mb.pressed) { + +				Point2 mpos = Point2(mb.x,mb.y)-ofs; + +				if (selection.size() == 0) { +					// Auto-select on right-click if nothing is selected +					// Note: This code is pretty much duplicated from the left click code, +					// both codes could be moved into a function to avoid the duplicated code. +					Point2 mpos = Point2(mb.x,mb.y)-ofs; + +					if (mpos.y < h ) { +						return; +					} + +					mpos.y -= h; + +					int idx = mpos.y / h; +					idx+=v_scroll->get_val(); +					if (idx <0 || idx>=animation->get_track_count()) +						break; + +					if (mpos.x < name_limit) { +					} else if (mpos.x < settings_limit) { +						float pos = mpos.x - name_limit; +						pos/=_get_zoom_scale(); +						pos+=h_scroll->get_val(); +						float w_time = (type_icon[0]->get_width() / _get_zoom_scale())/2.0; + +						int kidx = animation->track_find_key(idx,pos); +						int kidx_n = kidx+1; +						int key=-1; + +						if (kidx>=0 && kidx<animation->track_get_key_count(idx)) { + +							float kpos = animation->track_get_key_time(idx,kidx); +							if (ABS(pos-kpos)<=w_time) { + +								key=kidx; +							} +						} + +						if (key==-1 && kidx_n>=0 && kidx_n<animation->track_get_key_count(idx)) { + +							float kpos = animation->track_get_key_time(idx,kidx_n); +							if (ABS(pos-kpos)<=w_time) { + +								key=kidx_n; +							} +						} + +						if (key==-1) { + +							click.click=ClickOver::CLICK_SELECT_KEYS; +							click.at=Point2(mb.x,mb.y); +							click.to=click.at; +							click.shift=mb.mod.shift; +							selected_track=idx; +							track_editor->update(); +							//drag select region +							return; + +						} + + + +						SelectedKey sk; +						sk.track=idx; +						sk.key=key; +						KeyInfo ki; +						ki.pos= animation->track_get_key_time(idx,key); +						click.shift=mb.mod.shift; +						click.selk=sk; + + +						if (!mb.mod.shift && !selection.has(sk)) +							_clear_selection(); + +						selection.insert(sk,ki); + +						click.click=ClickOver::CLICK_MOVE_KEYS; +						click.at=Point2(mb.x,mb.y); +						click.to=click.at; +						update(); +						selected_track=idx; +						track_editor->update(); + +						if (_edit_if_single_selection() && mb.mod.command) { +							edit_button->set_pressed(true); +							key_editor_tab->show(); +						} +					} +				} + +				if (selection.size()) { +					// User has right clicked and we have a selection, show a popup menu with options +					track_menu->clear(); +					track_menu->set_size(Point2(1,1)); +					track_menu->add_item(TTR("Duplicate Selection"), RIGHT_MENU_DUPLICATE); +					track_menu->add_item(TTR("Duplicate Transposed"), RIGHT_MENU_DUPLICATE_TRANSPOSE); +					track_menu->add_item(TTR("Remove Selection"), RIGHT_MENU_REMOVE); + +					track_menu->set_pos(te->get_global_pos()+mpos); + +					interp_editing=-1; +					cont_editing=-1; + +					track_menu->popup(); +				} +			} +  			if (mb.button_index==BUTTON_LEFT && !(mb.button_mask&~BUTTON_MASK_LEFT)) { diff --git a/tools/editor/animation_editor.h b/tools/editor/animation_editor.h index 413c73b4b9..131100a205 100644 --- a/tools/editor/animation_editor.h +++ b/tools/editor/animation_editor.h @@ -99,6 +99,12 @@ class AnimationKeyEditor : public VBoxContainer  {  		CURVE_SET_CONSTANT  	}; +	enum { +		RIGHT_MENU_DUPLICATE, +		RIGHT_MENU_DUPLICATE_TRANSPOSE, +		RIGHT_MENU_REMOVE +	}; +  	struct MouseOver {  		enum Over { @@ -313,6 +319,9 @@ class AnimationKeyEditor : public VBoxContainer  {  	void _add_call_track(const NodePath& p_base); +	void _anim_duplicate_keys(bool transpose = false); +	void _anim_delete_keys(); +  	void _root_removed();  protected: diff --git a/tools/editor/asset_library_editor_plugin.cpp b/tools/editor/asset_library_editor_plugin.cpp index ee535310bc..4f685badfb 100644 --- a/tools/editor/asset_library_editor_plugin.cpp +++ b/tools/editor/asset_library_editor_plugin.cpp @@ -444,6 +444,13 @@ void EditorAssetLibraryItemDownload::_close() {  void EditorAssetLibraryItemDownload::_install() {  	String file = download->get_download_file(); + +	if (external_install) { +		emit_signal("install_asset",file,title->get_text()); +		return; +	} + +  	asset_installer->open(file,1);  } @@ -465,6 +472,8 @@ void EditorAssetLibraryItemDownload::_bind_methods() {  	ObjectTypeDB::bind_method("_close",&EditorAssetLibraryItemDownload::_close);  	ObjectTypeDB::bind_method("_make_request",&EditorAssetLibraryItemDownload::_make_request); +	ADD_SIGNAL(MethodInfo("install_asset",PropertyInfo(Variant::STRING,"zip_path"),PropertyInfo(Variant::STRING,"name"))); +  }  EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { @@ -530,6 +539,8 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {  	prev_status=-1; +	external_install=false; +  } @@ -600,7 +611,8 @@ void EditorAssetLibrary::_install_asset() {  		EditorAssetLibraryItemDownload *d  = downloads_hb->get_child(i)->cast_to<EditorAssetLibraryItemDownload>();  		if (d && d->get_asset_id() == description->get_asset_id()) { -			EditorNode::get_singleton()->show_warning("Download for this asset is already in progress!"); +			if (EditorNode::get_singleton() != NULL) +				EditorNode::get_singleton()->show_warning("Download for this asset is already in progress!");  			return;  		}  	} @@ -610,6 +622,11 @@ void EditorAssetLibrary::_install_asset() {  	downloads_hb->add_child(download);  	download->configure(description->get_title(),description->get_asset_id(),description->get_preview_icon(),description->get_download_url(),description->get_sha256()); +	if (templates_only) { +		download->set_external_install(true); +		download->connect("install_asset",this,"_install_external_asset"); +	} +  }  const char* EditorAssetLibrary::sort_key[SORT_MAX]={ @@ -1258,6 +1275,11 @@ void EditorAssetLibrary::_manage_plugins() { +void EditorAssetLibrary::_install_external_asset(String p_zip_path,String p_title) { + +	emit_signal("install_asset",p_zip_path,p_title); +} +  void EditorAssetLibrary::_bind_methods() {  	ObjectTypeDB::bind_method("_http_request_completed",&EditorAssetLibrary::_http_request_completed); @@ -1273,6 +1295,11 @@ void EditorAssetLibrary::_bind_methods() {  	ObjectTypeDB::bind_method("_repository_changed",&EditorAssetLibrary::_repository_changed);  	ObjectTypeDB::bind_method("_support_toggled",&EditorAssetLibrary::_support_toggled);  	ObjectTypeDB::bind_method("_rerun_search",&EditorAssetLibrary::_rerun_search); +	ObjectTypeDB::bind_method("_install_external_asset",&EditorAssetLibrary::_install_external_asset); + + + +	ADD_SIGNAL(MethodInfo("install_asset",PropertyInfo(Variant::STRING,"zip_path"),PropertyInfo(Variant::STRING,"name")));  } diff --git a/tools/editor/asset_library_editor_plugin.h b/tools/editor/asset_library_editor_plugin.h index 89663aa00b..fe40255af9 100644 --- a/tools/editor/asset_library_editor_plugin.h +++ b/tools/editor/asset_library_editor_plugin.h @@ -155,6 +155,8 @@ class EditorAssetLibraryItemDownload : public PanelContainer {  	int asset_id; +	bool external_install; +  	EditorAssetInstaller *asset_installer;  	void _close(); @@ -168,6 +170,7 @@ protected:  	static void _bind_methods();  public: +	void set_external_install(bool p_enable) { external_install=p_enable; }  	int get_asset_id() { return asset_id; }  	void configure(const String& p_title,int p_asset_id,const Ref<Texture>& p_preview, const String& p_download_url, const String& p_sha256_hash);  	EditorAssetLibraryItemDownload(); @@ -301,6 +304,8 @@ class EditorAssetLibrary : public PanelContainer {  	void _repository_changed(int p_repository_id);  	void _support_toggled(int p_support); +	void _install_external_asset(String p_zip_path,String p_title); +  friend class EditorAssetLibraryItemDescription;  friend class EditorAssetLibraryItem;  protected: diff --git a/tools/editor/create_dialog.cpp b/tools/editor/create_dialog.cpp index 5275e1beeb..210b799f3d 100644 --- a/tools/editor/create_dialog.cpp +++ b/tools/editor/create_dialog.cpp @@ -42,12 +42,13 @@  void CreateDialog::popup(bool p_dontclear) { -	popup_centered_ratio(0.6); +	popup_centered_ratio();  	if (p_dontclear)  		search_box->select_all();  	else  		search_box->clear();  	search_box->grab_focus(); +  	_update_search(); @@ -165,9 +166,10 @@ void CreateDialog::_update_search() {  		if (!ObjectTypeDB::can_instance(type))  			continue; // cant create what can't be instanced -		if (search_box->get_text()=="") + +		if (search_box->get_text()=="") {  			add_type(type,types,root,&to_select); -		else { +		} else {  			bool found=false;  			String type=I->get(); @@ -186,7 +188,7 @@ void CreateDialog::_update_search() {  				add_type(I->get(),types,root,&to_select);  		} -		if (EditorNode::get_editor_data().get_custom_types().has(type)) { +		if (EditorNode::get_editor_data().get_custom_types().has(type) && ObjectTypeDB::is_type(type, base_type)) {  			//there are custom types based on this... cool.  			//print_line("there are custom types"); @@ -198,6 +200,7 @@ void CreateDialog::_update_search() {  				if (!show)  					continue; +  				if (!types.has(type))  					add_type(type,types,root,&to_select); @@ -216,7 +219,7 @@ void CreateDialog::_update_search() {  				} -				if (!to_select && (search_box->get_text()=="" || ct[i].name.findn(search_box->get_text())!=-1)) { +				if (!to_select) {  					to_select=item;  				} @@ -246,7 +249,6 @@ void CreateDialog::_notification(int p_what) {  	if (p_what==NOTIFICATION_ENTER_TREE) {  		connect("confirmed",this,"_confirmed"); -		_update_search();  	}  	if (p_what==NOTIFICATION_EXIT_TREE) { diff --git a/tools/editor/editor_asset_installer.cpp b/tools/editor/editor_asset_installer.cpp index ec36773d8d..b6051886c0 100644 --- a/tools/editor/editor_asset_installer.cpp +++ b/tools/editor/editor_asset_installer.cpp @@ -317,9 +317,11 @@ void EditorAssetInstaller::ok_pressed() {  			}  			msg+=failed_files[i];  		} -		EditorNode::get_singleton()->show_warning(msg); +		if (EditorNode::get_singleton() != NULL) +			EditorNode::get_singleton()->show_warning(msg);  	} else { -		EditorNode::get_singleton()->show_warning("Package Installed Successfully!","Success!"); +		if (EditorNode::get_singleton() != NULL) +			EditorNode::get_singleton()->show_warning("Package Installed Successfully!","Success!");  	} diff --git a/tools/editor/editor_autoload_settings.cpp b/tools/editor/editor_autoload_settings.cpp new file mode 100644 index 0000000000..1cf0090e7e --- /dev/null +++ b/tools/editor/editor_autoload_settings.cpp @@ -0,0 +1,618 @@ +/*************************************************************************/ +/*  editor_autoload_settings.cpp                                         */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                    http://www.godotengine.org                         */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.                 */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +#include "editor_autoload_settings.h" + +#include "globals.h" +#include "global_constants.h" + +#include "editor_node.h" + +#define PREVIEW_LIST_MAX_SIZE 10 + +StringName EditorAutoloadSettings::autoload_changed = StringName(); + +void EditorAutoloadSettings::_notification(int p_what) { + +	if (p_what == NOTIFICATION_ENTER_TREE) { + +		List<String> afn; +		ResourceLoader::get_recognized_extensions_for_type("Script", &afn); +		ResourceLoader::get_recognized_extensions_for_type("PackedScene", &afn); + +		EditorFileDialog *file_dialog = autoload_add_path->get_file_dialog(); + +		for (List<String>::Element *E = afn.front(); E; E = E->next()) { + +			file_dialog->add_filter("*." + E->get()); +		} +	} +} + +bool EditorAutoloadSettings::_autoload_name_is_valid(const String& p_name, String* r_error) { + +	if (!p_name.is_valid_identifier()) { +		if (r_error) +			*r_error = TTR("Invalid name.") + "\n" + TTR("Valid characters:")+" a-z, A-Z, 0-9 or _"; + +		return false; +	} + +	if (ObjectTypeDB::type_exists(p_name)) { +		if (r_error) +			*r_error = TTR("Invalid name. Must not collide with an existing engine class name."); + +		return false; +	} + +	for (int i = 0; i < Variant::VARIANT_MAX; i++) { +		if (Variant::get_type_name( Variant::Type(i) ) == p_name) { +			if (r_error) +				*r_error = TTR("Invalid name. Must not collide with an existing buit-in type name."); + +			return false; +		} +	} + +	for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { +		if (GlobalConstants::get_global_constant_name(i) == p_name) { +			if (r_error) +				*r_error = TTR("Invalid name. Must not collide with an existing global constant name."); + +			return false; +		} +	} + +	return true; +} + +void EditorAutoloadSettings::_autoload_add() { + +	String name = autoload_add_name->get_text(); + +	String error; +	if (!_autoload_name_is_valid(name, &error)) { +		EditorNode::get_singleton()->show_warning(error); +		return; +	} + +	String path = autoload_add_path->get_line_edit()->get_text(); +	if (!FileAccess::exists(path)) { +		EditorNode::get_singleton()->show_warning(TTR("Invalid Path.") + "\n" + TTR("File does not exist.")); +		return; +	} + +	if (!path.begins_with("res://")) { +		EditorNode::get_singleton()->show_warning(TTR("Invalid Path.") + "\n"+ TTR("Not in resource path.")); +		return; +	} + +	name = "autoload/" + name; + +	UndoRedo* undo_redo = EditorNode::get_singleton()->get_undo_redo(); + +	undo_redo->create_action(TTR("Add AutoLoad")); +	undo_redo->add_do_property(Globals::get_singleton(), name, "*" + path); +	undo_redo->add_do_method(Globals::get_singleton(), "set_persisting", name, true); + +	if (Globals::get_singleton()->has(name)) { +		undo_redo->add_undo_property(Globals::get_singleton(), name, Globals::get_singleton()->get(name)); +	} else { +		undo_redo->add_undo_property(Globals::get_singleton(), name, Variant()); +	} + +	undo_redo->add_do_method(this, "update_autoload"); +	undo_redo->add_undo_method(this, "update_autoload"); + +	undo_redo->add_do_method(this, "emit_signal", autoload_changed); +	undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + +	undo_redo->commit_action(); + +	autoload_add_path->get_line_edit()->set_text(""); +	autoload_add_name->set_text(""); +} + +void EditorAutoloadSettings::_autoload_selected() { + +	TreeItem *ti = tree->get_selected(); + +	if (!ti) +		return; + +	selected_autoload = "autoload/" + ti->get_text(0); +} + +void EditorAutoloadSettings::_autoload_edited() { + +	if (updating_autoload) +		return; + +	TreeItem *ti = tree->get_edited(); +	int column = tree->get_edited_column(); + +	UndoRedo *undo_redo = EditorNode::get_undo_redo(); + +	if (column == 0) { +		String name = ti->get_text(0); +		String old_name = selected_autoload.get_slice("/", 1); + +		if (name == old_name) +			return; + +		String error; +		if (!_autoload_name_is_valid(name, &error)) { +			ti->set_text(0, old_name); +			EditorNode::get_singleton()->show_warning(error); +			return; +		} + +		if (Globals::get_singleton()->has("autoload/" + name)) { +			ti->set_text(0, old_name); +			EditorNode::get_singleton()->show_warning(vformat(TTR("Autoload '%s' already exists!"), name)); +			return; +		} + +		updating_autoload = true; + +		name = "autoload/" + name; + +		bool persisting = Globals::get_singleton()->get(selected_autoload); +		int order = Globals::get_singleton()->get(selected_autoload); +		String path = Globals::get_singleton()->get(selected_autoload); + +		undo_redo->create_action(TTR("Rename Autoload")); + +		undo_redo->add_do_property(Globals::get_singleton(), name, path); +		undo_redo->add_do_method(Globals::get_singleton(), "set_persisting", name, persisting); +		undo_redo->add_do_method(Globals::get_singleton(), "set_order", name, order); +		undo_redo->add_do_method(Globals::get_singleton(), "clear", selected_autoload); + +		undo_redo->add_undo_property(Globals::get_singleton(), selected_autoload, path); +		undo_redo->add_undo_method(Globals::get_singleton(), "set_persisting", selected_autoload, persisting); +		undo_redo->add_undo_method(Globals::get_singleton(), "set_order", selected_autoload, order); +		undo_redo->add_undo_method(Globals::get_singleton(), "clear", name); + +		undo_redo->add_do_method(this, "update_autoload"); +		undo_redo->add_undo_method(this, "update_autoload"); + +		undo_redo->add_do_method(this, "emit_signal", autoload_changed); +		undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + +		undo_redo->commit_action(); + +		selected_autoload = name; +	} else if (column == 2) { +		updating_autoload = true; + +		bool checked = ti->is_checked(2); +		String base = "autoload/" + ti->get_text(0); + +		int order = Globals::get_singleton()->get_order(base); +		String path = Globals::get_singleton()->get(base); + +		if (path.begins_with("*")) +			path = path.substr(1, path.length()); + +		if (checked) +			path = "*" + path; + +		undo_redo->create_action(TTR("Toggle AutoLoad Globals")); + +		undo_redo->add_do_property(Globals::get_singleton(), base, path); +		undo_redo->add_undo_property(Globals::get_singleton(), base, Globals::get_singleton()->get(base)); + +		undo_redo->add_do_method(Globals::get_singleton(),"set_order", base, order); +		undo_redo->add_undo_method(Globals::get_singleton(),"set_order", base, order); + +		undo_redo->add_do_method(this, "update_autoload"); +		undo_redo->add_undo_method(this, "update_autoload"); + +		undo_redo->add_do_method(this, "emit_signal", autoload_changed); +		undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + +		undo_redo->commit_action(); +	} + +	updating_autoload = false; +} + +void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_column, int p_button) { + +	TreeItem *ti = p_item->cast_to<TreeItem>(); + +	String name = "autoload/" + ti->get_text(0); + +	UndoRedo *undo_redo = EditorNode::get_undo_redo(); + +	switch (p_button) { + +		case BUTTON_MOVE_UP:  +		case BUTTON_MOVE_DOWN: { + +			TreeItem *swap = NULL; + +			if (p_button == BUTTON_MOVE_UP) { +				swap = ti->get_prev(); +			} else { +				swap = ti->get_next(); +			} + +			if (!swap) +				return; + +			String swap_name = "autoload/" + swap->get_text(0); + +			int order = Globals::get_singleton()->get_order(name); +			int swap_order = Globals::get_singleton()->get_order(swap_name); + +			undo_redo->create_action(TTR("Move Autoload")); + +			undo_redo->add_do_method(Globals::get_singleton(), "set_order", name, swap_order); +			undo_redo->add_undo_method(Globals::get_singleton(), "set_order", name, order); + +			undo_redo->add_do_method(Globals::get_singleton(), "set_order", swap_name, order); +			undo_redo->add_undo_method(Globals::get_singleton(), "set_order", swap_name, swap_order); + +			undo_redo->add_do_method(this, "update_autoload"); +			undo_redo->add_undo_method(this, "update_autoload"); + +			undo_redo->add_do_method(this, "emit_signal", autoload_changed); +			undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + +			undo_redo->commit_action(); +		} break; +		case BUTTON_DELETE: { + +			int order = Globals::get_singleton()->get_order(name); + +			undo_redo->create_action(TTR("Remove Autoload")); + +			undo_redo->add_do_property(Globals::get_singleton(), name, Variant()); + +			undo_redo->add_undo_property(Globals::get_singleton(), name, Globals::get_singleton()->get(name)); +			undo_redo->add_undo_method(Globals::get_singleton(), "set_persisting", name, true); +			undo_redo->add_undo_method(Globals::get_singleton(), "set_order", order); + +			undo_redo->add_do_method(this, "update_autoload"); +			undo_redo->add_undo_method(this, "update_autoload"); + +			undo_redo->add_do_method(this, "emit_signal", autoload_changed); +			undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + +			undo_redo->commit_action(); +		} break; +	} +} + +void EditorAutoloadSettings::_autoload_file_callback(const String& p_path) { + +	autoload_add_name->set_text(p_path.get_file().basename()); +} + +void EditorAutoloadSettings::update_autoload() { + +	if (updating_autoload) +		return; + +	updating_autoload = true; + +	autoload_cache.clear(); + +	tree->clear(); +	TreeItem *root = tree->create_item(); + +	List<PropertyInfo> props; +	Globals::get_singleton()->get_property_list(&props); + +	for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + +		const PropertyInfo &pi = E->get(); + +		if (!pi.name.begins_with("autoload/")) +			continue; + +		String name = pi.name.get_slice("/", 1); +		String path = Globals::get_singleton()->get(pi.name); + +		if (name.empty()) +			continue; + +		AutoLoadInfo info; +		info.name = pi.name; +		info.order = Globals::get_singleton()->get_order(pi.name); + +		autoload_cache.push_back(info); + +		bool global = false; + +		if (path.begins_with("*")) { +			global = true; +			path = path.substr(1, path.length()); +		} + +		TreeItem *item = tree->create_item(root); +		item->set_text(0, name); +		item->set_editable(0, true); + +		item->set_text(1, path); +		item->set_selectable(1, false); + +		item->set_cell_mode(2, TreeItem::CELL_MODE_CHECK); +		item->set_editable(2, true); +		item->set_text(2, TTR("Enable")); +		item->set_checked(2, global); + +		item->add_button(3, get_icon("MoveUp","EditorIcons"), BUTTON_MOVE_UP); +		item->add_button(3, get_icon("MoveDown","EditorIcons"), BUTTON_MOVE_DOWN); +		item->add_button(3, get_icon("Del","EditorIcons"), BUTTON_DELETE); +		item->set_selectable(3, false); +	} + +	updating_autoload = false; +} + +Variant EditorAutoloadSettings::get_drag_data_fw(const Point2& p_point, Control *p_control) { + +	if (autoload_cache.size() <= 1) +		return false; + +	StringArray autoloads; + +	TreeItem *next = tree->get_next_selected(NULL); + +	while (next) { +		autoloads.push_back(next->get_text(0)); +		next = tree->get_next_selected(next); +	} + +	if (autoloads.size() == 0 || autoloads.size() == autoload_cache.size()) +		return Variant(); + +	VBoxContainer *preview = memnew( VBoxContainer ); + +	int max_size = MIN(PREVIEW_LIST_MAX_SIZE, autoloads.size()); + +	for (int i = 0; i < max_size; i++) { +		Label *label = memnew( Label(autoloads[i]) ); +		label->set_self_opacity(Math::lerp(1, 0, float(i)/PREVIEW_LIST_MAX_SIZE)); + +		preview->add_child(label); +	} + +	tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN); +	tree->set_drag_preview(preview); + +	Dictionary drop_data; +	drop_data["type"] = "autoload"; +	drop_data["autoloads"] = autoloads; + +	return drop_data; +} + +bool EditorAutoloadSettings::can_drop_data_fw(const Point2& p_point, const Variant& p_data, Control *p_control) const { +	if (updating_autoload) +		return false; + +	Dictionary drop_data = p_data; + +	if (!drop_data.has("type")) +		return false; + +	if (drop_data.has("type")) { +		TreeItem *ti = tree->get_item_at_pos(p_point); + +		if (!ti) +			return false; + +		int section = tree->get_drop_section_at_pos(p_point); + +		if (section < -1) +			return false; + +		return true; +	} + +	return false; +} + +void EditorAutoloadSettings::drop_data_fw(const Point2& p_point, const Variant& p_data, Control *p_control) { + +	TreeItem *ti = tree->get_item_at_pos(p_point); + +	if (!ti) +		return; + +	int section = tree->get_drop_section_at_pos(p_point); + +	if (section < -1) +		return; + +	String name; +	bool move_to_back = false; + +	if (section < 0) { +		name = ti->get_text(0); +	} else if (ti->get_next()) { +		name = ti->get_next()->get_text(0); +	} else { +		name = ti->get_text(0); +		move_to_back = true; +	} + +	int order = Globals::get_singleton()->get_order("autoload/" + name); + +	AutoLoadInfo aux; +	List<AutoLoadInfo>::Element *E = NULL; + +	if (!move_to_back) { +		aux.order = order; +		E = autoload_cache.find(aux); +	} + +	Dictionary drop_data = p_data; +	StringArray autoloads = drop_data["autoloads"]; + +	Vector<int> orders; +	orders.resize(autoload_cache.size()); + +	for (int i = 0; i < autoloads.size(); i++) { +		aux.order = Globals::get_singleton()->get_order("autoload/" + autoloads[i]); + +		List<AutoLoadInfo>::Element *I = autoload_cache.find(aux); + +		if (move_to_back) { +			autoload_cache.move_to_back(I); +		} else if (E != I) { +			autoload_cache.move_before(I, E); +		} else if (E->next()) { +			E = E->next(); +		} else { +			break; +		} +	} + +	int i = 0; + +	for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { +		orders[i++] = E->get().order; +	} + +	orders.sort(); + +	UndoRedo *undo_redo = EditorNode::get_undo_redo(); + +	undo_redo->create_action(TTR("Rearrange Autoloads")); + +	i = 0; + +	for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { +		undo_redo->add_do_method(Globals::get_singleton(), "set_order", E->get().name, orders[i++]); +		undo_redo->add_undo_method(Globals::get_singleton(), "set_order", E->get().name, E->get().order); +	} + +	orders.clear(); + +	undo_redo->add_do_method(this, "update_autoload"); +	undo_redo->add_undo_method(this, "update_autoload"); + +	undo_redo->add_do_method(this, "emit_signal", autoload_changed); +	undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + +	undo_redo->commit_action(); +} + +void EditorAutoloadSettings::_bind_methods() { + +	ObjectTypeDB::bind_method("_autoload_add", &EditorAutoloadSettings::_autoload_add); +	ObjectTypeDB::bind_method("_autoload_selected", &EditorAutoloadSettings::_autoload_selected); +	ObjectTypeDB::bind_method("_autoload_edited", &EditorAutoloadSettings::_autoload_edited); +	ObjectTypeDB::bind_method("_autoload_button_pressed", &EditorAutoloadSettings::_autoload_button_pressed); +	ObjectTypeDB::bind_method("_autoload_file_callback", &EditorAutoloadSettings::_autoload_file_callback); + +	ObjectTypeDB::bind_method("get_drag_data_fw", &EditorAutoloadSettings::get_drag_data_fw); +	ObjectTypeDB::bind_method("can_drop_data_fw", &EditorAutoloadSettings::can_drop_data_fw); +	ObjectTypeDB::bind_method("drop_data_fw", &EditorAutoloadSettings::drop_data_fw); + +	ObjectTypeDB::bind_method("update_autoload", &EditorAutoloadSettings::update_autoload); + +	ADD_SIGNAL(MethodInfo("autoload_changed")); +} + +EditorAutoloadSettings::EditorAutoloadSettings() { + +	autoload_changed = "autoload_changed"; + +	updating_autoload = false; +	selected_autoload = ""; + +	HBoxContainer *hbc = memnew( HBoxContainer ); +	add_child(hbc); + +	VBoxContainer *vbc_path = memnew( VBoxContainer ); +	vbc_path->set_h_size_flags(SIZE_EXPAND_FILL); + +	autoload_add_path = memnew( EditorLineEditFileChooser ); +	autoload_add_path->set_h_size_flags(SIZE_EXPAND_FILL); + +	autoload_add_path->get_file_dialog()->set_mode(EditorFileDialog::MODE_OPEN_FILE); +	autoload_add_path->get_file_dialog()->connect("file_selected", this, "_autoload_file_callback"); + +	vbc_path->add_margin_child(TTR("Path:"), autoload_add_path); +	hbc->add_child(vbc_path); + +	VBoxContainer *vbc_name = memnew( VBoxContainer ); +	vbc_name->set_h_size_flags(SIZE_EXPAND_FILL); + +	HBoxContainer *hbc_name = memnew( HBoxContainer ); + +	autoload_add_name = memnew( LineEdit ); +	autoload_add_name->set_h_size_flags(SIZE_EXPAND_FILL); +	hbc_name->add_child(autoload_add_name); + +	Button *add_autoload = memnew( Button ); +	add_autoload->set_text(TTR("Add")); +	hbc_name->add_child(add_autoload); +	add_autoload->connect("pressed", this, "_autoload_add"); + +	vbc_name->add_margin_child(TTR("Node Name:"), hbc_name); +	hbc->add_child(vbc_name); + +	tree = memnew( Tree ); +	tree->set_hide_root(true); +	tree->set_select_mode(Tree::SELECT_MULTI); +	tree->set_single_select_cell_editing_only_when_already_selected(true); + +	tree->set_drag_forwarding(this); + +	tree->set_columns(4); +	tree->set_column_titles_visible(true); + +	tree->set_column_title(0,TTR("Name")); +	tree->set_column_expand(0,true); +	tree->set_column_min_width(0,100); + +	tree->set_column_title(1,TTR("Path")); +	tree->set_column_expand(1,true); +	tree->set_column_min_width(1,100); + +	tree->set_column_title(2,TTR("Singleton")); +	tree->set_column_expand(2,false); +	tree->set_column_min_width(2,80); + +	tree->set_column_expand(3,false); +	tree->set_column_min_width(3,80); + +	tree->connect("cell_selected", this, "_autoload_selected"); +	tree->connect("item_edited", this, "_autoload_edited"); +	tree->connect("button_pressed", this, "_autoload_button_pressed"); + +	add_margin_child(TTR("List:"), tree, true); +} + diff --git a/tools/editor/editor_autoload_settings.h b/tools/editor/editor_autoload_settings.h new file mode 100644 index 0000000000..b8825f807c --- /dev/null +++ b/tools/editor/editor_autoload_settings.h @@ -0,0 +1,94 @@ +/*************************************************************************/ +/*  editor_autoload_settings.h                                           */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                    http://www.godotengine.org                         */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.                 */ +/*                                                                       */ +/* 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 EDITOR_AUTOLOAD_SETTINGS_H +#define EDITOR_AUTOLOAD_SETTINGS_H + +#include "scene/gui/tree.h" + +#include "editor_file_dialog.h" + +class EditorAutoloadSettings : public VBoxContainer { + +	OBJ_TYPE( EditorAutoloadSettings, VBoxContainer ); + +	enum { +		BUTTON_MOVE_UP, +		BUTTON_MOVE_DOWN, +		BUTTON_DELETE +	}; + +	static StringName autoload_changed; + +	struct AutoLoadInfo { +		String name; +		int order; + +		bool operator==(const AutoLoadInfo& p_info) { +			return order == p_info.order; +		} +	}; + +	List<AutoLoadInfo> autoload_cache; + +	bool updating_autoload; +	int number_of_autoloads; +	String selected_autoload; + +	Tree *tree; +	EditorLineEditFileChooser *autoload_add_path; +	LineEdit *autoload_add_name; + +	bool _autoload_name_is_valid(const String& p_string, String *r_error = NULL); + +	void _autoload_add(); +	void _autoload_selected(); +	void _autoload_edited(); +	void _autoload_button_pressed(Object *p_item, int p_column, int p_button); +	void _autoload_file_callback(const String& p_path); + +	Variant get_drag_data_fw(const Point2& p_point, Control *p_from); +	bool can_drop_data_fw(const Point2& p_point, const Variant& p_data, Control *p_from) const; +	void drop_data_fw(const Point2& p_point, const Variant& p_data, Control *p_from); + +protected: + +	void _notification(int p_what); +	static void _bind_methods(); + +public: + +	void update_autoload(); + +	EditorAutoloadSettings(); + +}; + +#endif + diff --git a/tools/editor/editor_data.cpp b/tools/editor/editor_data.cpp index 0f10041034..8d3fd6c9c2 100644 --- a/tools/editor/editor_data.cpp +++ b/tools/editor/editor_data.cpp @@ -326,6 +326,13 @@ Dictionary EditorData::get_editor_states() const {  } +Dictionary EditorData::get_scene_editor_states(int p_idx) const +{ +	ERR_FAIL_INDEX_V(p_idx,edited_scene.size(),Dictionary()); +	EditedScene es = edited_scene[p_idx]; +	return es.editor_states; +} +  void EditorData::set_editor_states(const Dictionary& p_states) {  	List<Variant> keys; @@ -613,11 +620,14 @@ void EditorData::set_edited_scene(int p_idx){  	current_edited_scene=p_idx;  	//swap  } -Node* EditorData::get_edited_scene_root(){ - -	ERR_FAIL_INDEX_V(current_edited_scene,edited_scene.size(),NULL); - -	return edited_scene[current_edited_scene].root; +Node* EditorData::get_edited_scene_root(int p_idx){ +	if (p_idx < 0) { +		ERR_FAIL_INDEX_V(current_edited_scene,edited_scene.size(),NULL); +		return edited_scene[current_edited_scene].root; +	} else { +		ERR_FAIL_INDEX_V(p_idx,edited_scene.size(),NULL); +		return edited_scene[p_idx].root; +	}  }  void EditorData::set_edited_scene_root(Node* p_root) { @@ -630,9 +640,14 @@ int EditorData::get_edited_scene_count() const {  	return edited_scene.size();  } -void EditorData::set_edited_scene_version(uint64_t version) { +void EditorData::set_edited_scene_version(uint64_t version, int scene_idx) {  	ERR_FAIL_INDEX(current_edited_scene,edited_scene.size()); -	edited_scene[current_edited_scene].version=version; +	if (scene_idx < 0) { +		edited_scene[current_edited_scene].version=version; +	} else { +		ERR_FAIL_INDEX(scene_idx,edited_scene.size()); +		edited_scene[scene_idx].version=version; +	}  } @@ -758,10 +773,15 @@ void EditorData::set_edited_scene_import_metadata(Ref<ResourceImportMetadata> p_  } -Ref<ResourceImportMetadata> EditorData::get_edited_scene_import_metadata() const{ +Ref<ResourceImportMetadata> EditorData::get_edited_scene_import_metadata(int idx) const{  	ERR_FAIL_INDEX_V(current_edited_scene,edited_scene.size(),Ref<ResourceImportMetadata>()); -	return edited_scene[current_edited_scene].medatata; +	if(idx<0) { +		return edited_scene[current_edited_scene].medatata; +	} else { +		ERR_FAIL_INDEX_V(idx,edited_scene.size(),Ref<ResourceImportMetadata>()); +		return edited_scene[idx].medatata; +	}  } diff --git a/tools/editor/editor_data.h b/tools/editor/editor_data.h index 319155655d..a0b716f560 100644 --- a/tools/editor/editor_data.h +++ b/tools/editor/editor_data.h @@ -156,6 +156,7 @@ public:  	void paste_object_params(Object *p_object);  	Dictionary get_editor_states() const; +	Dictionary get_scene_editor_states(int p_idx) const;  	void set_editor_states(const Dictionary& p_states);  	void get_editor_breakpoints(List<String> *p_breakpoints);  	void clear_editor_states(); @@ -184,15 +185,15 @@ public:  	void set_edited_scene(int p_idx);  	void set_edited_scene_root(Node* p_root);  	void set_edited_scene_import_metadata(Ref<ResourceImportMetadata> p_mdata); -	Ref<ResourceImportMetadata> get_edited_scene_import_metadata() const; +	Ref<ResourceImportMetadata> get_edited_scene_import_metadata(int p_idx = -1) const;  	int get_edited_scene() const; -	Node* get_edited_scene_root(); +	Node* get_edited_scene_root(int p_idx = -1);  	int get_edited_scene_count() const;  	String get_scene_title(int p_idx) const;  	String get_scene_path(int p_idx) const;  	String get_scene_type(int p_idx) const;  	Ref<Script> get_scene_root_script(int p_idx) const; -	void set_edited_scene_version(uint64_t version); +	void set_edited_scene_version(uint64_t version, int p_scene_idx = -1);  	uint64_t get_edited_scene_version() const;  	uint64_t get_scene_version(int p_idx) const;  	void clear_edited_scenes(); diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 89d7f8f3ce..81f9927b92 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -725,9 +725,9 @@ void EditorNode::_get_scene_metadata(const String& p_file) {  } -void EditorNode::_set_scene_metadata(const String& p_file) { +void EditorNode::_set_scene_metadata(const String& p_file, int p_idx) { -	Node *scene = editor_data.get_edited_scene_root(); +	Node *scene = editor_data.get_edited_scene_root(p_idx);  	if (!scene)  		return; @@ -740,7 +740,7 @@ void EditorNode::_set_scene_metadata(const String& p_file) {  	Ref<ConfigFile> cf;  	cf.instance(); -	Dictionary md = editor_data.get_editor_states(); +	Dictionary md = editor_data.get_edited_scene()==p_idx?editor_data.get_editor_states():editor_data.get_scene_editor_states(p_idx);  	List<Variant> keys;  	md.get_key_list(&keys); @@ -954,9 +954,9 @@ void EditorNode::_save_scene_with_preview(String p_file) {  } -void EditorNode::_save_scene(String p_file) { +void EditorNode::_save_scene(String p_file, int idx) { -	Node *scene = editor_data.get_edited_scene_root(); +	Node *scene = editor_data.get_edited_scene_root(idx);  	if (!scene) { @@ -970,7 +970,7 @@ void EditorNode::_save_scene(String p_file) {  	editor_data.apply_changes_in_editors(); -	_set_scene_metadata(p_file); +	_set_scene_metadata(p_file,idx);  	Ref<PackedScene> sdata; @@ -1001,7 +1001,7 @@ void EditorNode::_save_scene(String p_file) {  		return;  	} -	sdata->set_import_metadata(editor_data.get_edited_scene_import_metadata()); +	sdata->set_import_metadata(editor_data.get_edited_scene_import_metadata(idx));  	int flg=0;  	if (EditorSettings::get_singleton()->get("on_save/compress_binary_resources"))  		flg|=ResourceSaver::FLAG_COMPRESS; @@ -1017,7 +1017,10 @@ void EditorNode::_save_scene(String p_file) {  	if (err==OK) {  		scene->set_filename( Globals::get_singleton()->localize_path(p_file) );  		//EditorFileSystem::get_singleton()->update_file(p_file,sdata->get_type()); -		set_current_version(editor_data.get_undo_redo().get_version()); +		if (idx < 0 || idx == editor_data.get_edited_scene()) +			set_current_version(editor_data.get_undo_redo().get_version()); +		else +			editor_data.set_edited_scene_version(0,idx);  		_update_title();  		_update_scene_tabs();  	} else { @@ -1810,7 +1813,6 @@ void EditorNode::_run(bool p_current,const String& p_custom) {  	String args; -  	if (p_current || (editor_data.get_edited_scene_root() && p_custom==editor_data.get_edited_scene_root()->get_filename())) {  		Node *scene = editor_data.get_edited_scene_root(); @@ -1833,12 +1835,7 @@ void EditorNode::_run(bool p_current,const String& p_custom) {  		} -		bool autosave = EDITOR_DEF("run/auto_save_before_running",true); -		if (autosave) { - -			_menu_option(FILE_SAVE_SCENE); -		}  		if (run_settings_dialog->get_run_mode()==RunSettingsDialog::RUN_LOCAL_SCENE) { @@ -1911,7 +1908,7 @@ void EditorNode::_run(bool p_current,const String& p_custom) {  				_save_scene_with_preview(scene->get_filename());  			}  		} - +		_menu_option(FILE_SAVE_ALL_SCENES);  		editor_data.save_editor_external_data();  	} @@ -2167,6 +2164,19 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {  		} break; +		case FILE_SAVE_ALL_SCENES: { +			for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { +				Node *scene = editor_data.get_edited_scene_root(i); +				if (scene && scene->get_filename()!="") { +					// save in background if in the script editor +					if (i != editor_data.get_edited_scene() || _get_current_main_editor() == EDITOR_SCRIPT) { +						_save_scene(scene->get_filename(), i); +					} else { +						_save_scene_with_preview(scene->get_filename()); +					} +				}// else: ignore new scenes +			} +		} break;  		case FILE_SAVE_BEFORE_RUN: {  			if (!p_confirmed) {  				accept->get_ok()->set_text(TTR("Yes")); @@ -2494,7 +2504,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {  #endif  		case RESOURCE_NEW: { -			create_dialog->popup_centered_ratio(); +			create_dialog->popup(true);  		} break;  		case RESOURCE_LOAD: { @@ -2665,11 +2675,16 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {  		} break;  		case RUN_PLAY_NATIVE: { -			_menu_option_confirm(RUN_STOP,true); -			emit_signal("play_pressed"); -			editor_run.run_native_notify(); - - +			 +			bool autosave = EDITOR_DEF("run/auto_save_before_running",true); +			if (autosave) { +				_menu_option_confirm(FILE_SAVE_ALL_SCENES, false); +			} +			if (run_native->is_deploy_debug_remote_enabled()){ +				_menu_option_confirm(RUN_STOP,true); +				emit_signal("play_pressed"); +				editor_run.run_native_notify(); +			}  		} break;  		case RUN_SCENE_SETTINGS: { @@ -5648,6 +5663,7 @@ EditorNode::EditorNode() {  	p->add_separator();  	p->add_shortcut(ED_SHORTCUT("editor/save_scene",TTR("Save Scene"),KEY_MASK_CMD+KEY_S),FILE_SAVE_SCENE);  	p->add_shortcut(ED_SHORTCUT("editor/save_scene_as",TTR("Save Scene As.."),KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_S),FILE_SAVE_AS_SCENE); +	p->add_shortcut(ED_SHORTCUT("editor/save_all_scenes",TTR("Save all Scenes"),KEY_MASK_ALT+KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_S),FILE_SAVE_ALL_SCENES);  	p->add_separator();  	p->add_shortcut(ED_SHORTCUT("editor/close_scene",TTR("Close Scene"),KEY_MASK_SHIFT+KEY_MASK_CTRL+KEY_W),FILE_CLOSE);  	p->add_separator(); @@ -5840,7 +5856,8 @@ EditorNode::EditorNode() {  	play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE);  	play_custom_scene_button->set_icon(gui_base->get_icon("PlayCustom","EditorIcons"));  	play_custom_scene_button->connect("pressed", this,"_menu_option",make_binds(RUN_PLAY_CUSTOM_SCENE)); -	play_custom_scene_button->set_tooltip(TTR("Play custom scene")+" ("+keycode_get_string(KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_F5)+")."); +	play_custom_scene_button->set_tooltip(TTR("Play custom scene")); +	play_custom_scene_button->set_shortcut(ED_SHORTCUT("editor/play_custom_scene",TTR("Play Custom Scene"),KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_F5));  	debug_button = memnew( MenuButton );  	debug_button->set_flat(true); diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index c4414d5c36..d18de1c531 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -124,6 +124,7 @@ private:  		FILE_OPEN_SCENE,  		FILE_SAVE_SCENE,  		FILE_SAVE_AS_SCENE, +		FILE_SAVE_ALL_SCENES,  		FILE_SAVE_BEFORE_RUN,  		FILE_SAVE_AND_RUN,  		FILE_IMPORT_SUBSCENE, @@ -438,7 +439,7 @@ private:  	void _node_renamed();  	void _editor_select(int p_which); -	void _set_scene_metadata(const String &p_file); +	void _set_scene_metadata(const String &p_file, int p_idx=-1);  	void _get_scene_metadata(const String& p_file);  	void _update_title();  	void _update_scene_tabs(); @@ -448,7 +449,7 @@ private:  	void _rebuild_import_menu(); -	void _save_scene(String p_file); +	void _save_scene(String p_file, int idx = -1);  	void _instance_request(const String& p_path); diff --git a/tools/editor/editor_run_native.cpp b/tools/editor/editor_run_native.cpp index 234dd03087..edbcc71284 100644 --- a/tools/editor/editor_run_native.cpp +++ b/tools/editor/editor_run_native.cpp @@ -101,10 +101,8 @@ void EditorRunNative::_run_native(int p_idx,const String& p_platform) {  	Ref<EditorExportPlatform> eep = EditorImportExport::get_singleton()->get_export_platform(p_platform);  	ERR_FAIL_COND(eep.is_null()); -	if (deploy_debug_remote) { -		emit_signal("native_run"); +	emit_signal("native_run"); -	}  	int flags=0;  	if (deploy_debug_remote)  		flags|=EditorExportPlatform::EXPORT_REMOTE_DEBUG; diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index 22cc243e88..7f496d0e22 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -682,6 +682,8 @@ void EditorSettings::_load_default_text_editor_theme() {  	set("text_editor/completion_background_color", Color::html("2C2A32"));  	set("text_editor/completion_selected_color", Color::html("434244"));  	set("text_editor/completion_existing_color", Color::html("21dfdfdf")); +	set("text_editor/completion_scroll_color", Color::html("ffffff")); +	set("text_editor/completion_font_color", Color::html("aaaaaa"));  	set("text_editor/caret_color",Color::html("aaaaaa"));  	set("text_editor/line_number_color",Color::html("66aaaaaa"));  	set("text_editor/text_color",Color::html("aaaaaa")); @@ -917,6 +919,8 @@ bool EditorSettings::_save_text_editor_theme(String p_file) {  	cf->set_value(theme_section, "completion_background_color", ((Color)get("text_editor/completion_background_color")).to_html());  	cf->set_value(theme_section, "completion_selected_color", ((Color)get("text_editor/completion_selected_color")).to_html());  	cf->set_value(theme_section, "completion_existing_color", ((Color)get("text_editor/completion_existing_color")).to_html()); +	cf->set_value(theme_section, "completion_scroll_color", ((Color)get("text_editor/completion_scroll_color")).to_html()); +	cf->set_value(theme_section, "completion_font_color", ((Color)get("text_editor/completion_font_color")).to_html());  	cf->set_value(theme_section, "caret_color", ((Color)get("text_editor/caret_color")).to_html());  	cf->set_value(theme_section, "line_number_color", ((Color)get("text_editor/line_number_color")).to_html());  	cf->set_value(theme_section, "text_color", ((Color)get("text_editor/text_color")).to_html()); diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp index 3b095d15f9..fc5f552723 100644 --- a/tools/editor/plugins/script_editor_plugin.cpp +++ b/tools/editor/plugins/script_editor_plugin.cpp @@ -312,6 +312,8 @@ void ScriptTextEditor::_load_theme_settings() {  	get_text_edit()->add_color_override("completion_background_color", EDITOR_DEF("text_editor/completion_background_color", Color(0,0,0,0)));  	get_text_edit()->add_color_override("completion_selected_color", EDITOR_DEF("text_editor/completion_selected_color", Color::html("434244")));  	get_text_edit()->add_color_override("completion_existing_color", EDITOR_DEF("text_editor/completion_existing_color", Color::html("21dfdfdf"))); +	get_text_edit()->add_color_override("completion_scroll_color", EDITOR_DEF("text_editor/completion_scroll_color", Color::html("ffffff"))); +	get_text_edit()->add_color_override("completion_font_color", EDITOR_DEF("text_editor/completion_font_color", Color::html("aaaaaa")));  	get_text_edit()->add_color_override("font_color",EDITOR_DEF("text_editor/text_color",Color(0,0,0)));  	get_text_edit()->add_color_override("line_number_color",EDITOR_DEF("text_editor/line_number_color",Color(0,0,0)));  	get_text_edit()->add_color_override("caret_color",EDITOR_DEF("text_editor/caret_color",Color(0,0,0))); diff --git a/tools/editor/plugins/shader_editor_plugin.cpp b/tools/editor/plugins/shader_editor_plugin.cpp index 864df42b6e..9ef84af260 100644 --- a/tools/editor/plugins/shader_editor_plugin.cpp +++ b/tools/editor/plugins/shader_editor_plugin.cpp @@ -81,6 +81,8 @@ void ShaderTextEditor::_load_theme_settings() {  	get_text_edit()->add_color_override("completion_background_color", EDITOR_DEF("text_editor/completion_background_color", Color(0,0,0,0)));  	get_text_edit()->add_color_override("completion_selected_color", EDITOR_DEF("text_editor/completion_selected_color", Color::html("434244")));  	get_text_edit()->add_color_override("completion_existing_color", EDITOR_DEF("text_editor/completion_existing_color", Color::html("21dfdfdf"))); +	get_text_edit()->add_color_override("completion_scroll_color", EDITOR_DEF("text_editor/completion_scroll_color", Color::html("ffffff"))); +	get_text_edit()->add_color_override("completion_font_color", EDITOR_DEF("text_editor/completion_font_color", Color::html("aaaaaa")));  	get_text_edit()->add_color_override("font_color",EDITOR_DEF("text_editor/text_color",Color(0,0,0)));  	get_text_edit()->add_color_override("line_number_color",EDITOR_DEF("text_editor/line_number_color",Color(0,0,0)));  	get_text_edit()->add_color_override("caret_color",EDITOR_DEF("text_editor/caret_color",Color(0,0,0))); diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 91a347c69b..a70df78697 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -77,21 +77,30 @@ void SpatialEditorViewport::_update_camera() {  String SpatialEditorGizmo::get_handle_name(int p_idx) const { +	if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) +		return get_script_instance()->call("get_handle_name", p_idx); +  	return "";  }  Variant SpatialEditorGizmo::get_handle_value(int p_idx) const{ +	if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) +		return get_script_instance()->call("get_handle_value", p_idx); +  	return Variant();  }  void SpatialEditorGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point) { +	if (get_script_instance() && get_script_instance()->has_method("set_handle")) +		get_script_instance()->call("set_handle", p_idx, p_camera, p_point);  }  void SpatialEditorGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){ - +	if (get_script_instance() && get_script_instance()->has_method("commit_handle")) +		get_script_instance()->call("commit_handle", p_idx, p_restore, p_cancel);  }  bool SpatialEditorGizmo::intersect_frustum(const Camera *p_camera,const Vector<Plane> &p_frustum) { diff --git a/tools/editor/plugins/tile_map_editor_plugin.cpp b/tools/editor/plugins/tile_map_editor_plugin.cpp index 9d27ac8aa3..d686c37d1a 100644 --- a/tools/editor/plugins/tile_map_editor_plugin.cpp +++ b/tools/editor/plugins/tile_map_editor_plugin.cpp @@ -412,6 +412,24 @@ void TileMapEditor::_draw_cell(int p_cell, const Point2i& p_point, bool p_flip_h  	if (node->get_tile_origin()==TileMap::TILE_ORIGIN_TOP_LEFT) {  		rect.pos+=tile_ofs; +	} else if (node->get_tile_origin()==TileMap::TILE_ORIGIN_BOTTOM_LEFT) { +		Size2 cell_size = node->get_cell_size(); +		 +		rect.pos+=tile_ofs; +		 +		if(p_transpose) +		{ +			if(p_flip_h) +				rect.pos.x-=cell_size.x; +			else +				rect.pos.x+=cell_size.x; +		} else { +			if(p_flip_v) +				rect.pos.y-=cell_size.y; +			else +				rect.pos.y+=cell_size.y; +		} +  	} else if (node->get_tile_origin()==TileMap::TILE_ORIGIN_CENTER) {  		rect.pos+=node->get_cell_size()/2;  		Vector2 s = r.size; diff --git a/tools/editor/plugins/tile_set_editor_plugin.cpp b/tools/editor/plugins/tile_set_editor_plugin.cpp index a2c7147bf3..39a15189e7 100644 --- a/tools/editor/plugins/tile_set_editor_plugin.cpp +++ b/tools/editor/plugins/tile_set_editor_plugin.cpp @@ -73,24 +73,24 @@ void TileSetEditor::_import_scene(Node *scene, Ref<TileSet> p_library, bool p_me  			p_library->tile_set_name(id,mi->get_name());  		} - -  		p_library->tile_set_texture(id,texture);  		p_library->tile_set_material(id,material);  		Vector2 phys_offset; +		Size2 s; -		if (mi->is_centered()) { -			Size2 s; -			if (mi->is_region()) { -				s=mi->get_region_rect().size; -			} else { -				s=texture->get_size(); -			} -			phys_offset+=-s/2; -		}  		if (mi->is_region()) { +			s=mi->get_region_rect().size;  			p_library->tile_set_region(id,mi->get_region_rect()); +		} else { +			const int frame = mi->get_frame(); +			const int hframes = mi->get_hframes(); +			s=texture->get_size()/Size2(hframes,mi->get_vframes()); +			p_library->tile_set_region(id,Rect2(Vector2(frame%hframes,frame/hframes)*s,s)); +		} +		 +		if (mi->is_centered()) { +			phys_offset+=-s/2;  		}  		Vector<Ref<Shape2D> >collisions; diff --git a/tools/editor/project_manager.cpp b/tools/editor/project_manager.cpp index 52f6d1dd9c..25d42eb601 100644 --- a/tools/editor/project_manager.cpp +++ b/tools/editor/project_manager.cpp @@ -49,17 +49,30 @@  #include "editor_initialize_ssl.h"  #include "editor_scale.h" +#include "io/zip_io.h" +  class NewProjectDialog : public ConfirmationDialog {  	OBJ_TYPE(NewProjectDialog,ConfirmationDialog); +public: + +	enum Mode { +		MODE_NEW, +		MODE_IMPORT, +		MODE_INSTALL +	}; +private: -	bool import_mode; +	Mode mode;  	Label *pp,*pn;  	Label *error;  	LineEdit *project_path;  	LineEdit *project_name;  	FileDialog *fdialog; +	String zip_path; +	String zip_title; +	AcceptDialog *dialog_error;  	bool _test_path() { @@ -72,7 +85,7 @@ class NewProjectDialog : public ConfirmationDialog {  			return false;  		} -		if (!import_mode) { +		if (mode!=MODE_IMPORT) {  			if (d->file_exists("engine.cfg")) { @@ -109,7 +122,7 @@ class NewProjectDialog : public ConfirmationDialog {  			if (lidx!=-1) {  				sp=sp.substr(lidx+1,sp.length());  			} -			if (sp=="" && import_mode ) +			if (sp=="" && mode==MODE_IMPORT )  				sp=TTR("Imported Project");  			project_name->set_text(sp); @@ -119,7 +132,7 @@ class NewProjectDialog : public ConfirmationDialog {  	void _file_selected(const String& p_path) {  		String p = p_path; -		if (import_mode) { +		if (mode==MODE_IMPORT) {  			if (p.ends_with("engine.cfg")) {  				p=p.get_base_dir(); @@ -141,7 +154,7 @@ class NewProjectDialog : public ConfirmationDialog {  	void _browse_path() { -		if (import_mode) { +		if (mode==MODE_IMPORT) {  			fdialog->set_mode(FileDialog::MODE_OPEN_FILE);  			fdialog->clear_filters(); @@ -163,7 +176,7 @@ class NewProjectDialog : public ConfirmationDialog {  		String dir; -		if (import_mode) { +		if (mode==MODE_IMPORT) {  			dir=project_path->get_text(); @@ -179,26 +192,130 @@ class NewProjectDialog : public ConfirmationDialog {  			dir=d->get_current_dir();  			memdelete(d); -			FileAccess *f = FileAccess::open(dir.plus_file("/engine.cfg"),FileAccess::WRITE); -			if (!f) { -				error->set_text(TTR("Couldn't create engine.cfg in project path.")); -			} else { +			if (mode==MODE_NEW) { + + + + +				FileAccess *f = FileAccess::open(dir.plus_file("/engine.cfg"),FileAccess::WRITE); +				if (!f) { +					error->set_text(TTR("Couldn't create engine.cfg in project path.")); +				} else { + +					f->store_line("; Engine configuration file."); +					f->store_line("; It's best to edit using the editor UI, not directly,"); +					f->store_line("; becausethe parameters that go here are not obvious."); +					f->store_line("; "); +					f->store_line("; Format: "); +					f->store_line(";   [section] ; section goes between []"); +					f->store_line(";   param=value ; assign values to parameters"); +					f->store_line("\n"); +					f->store_line("[application]"); +					f->store_line("name=\""+project_name->get_text()+"\""); +					f->store_line("icon=\"res://icon.png\""); + +					memdelete(f); + +					ResourceSaver::save(dir.plus_file("/icon.png"),get_icon("DefaultProjectIcon","EditorIcons")); +				} + +			} else if (mode==MODE_INSTALL) { + + +				FileAccess *src_f=NULL; +				zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + +				unzFile pkg = unzOpen2(zip_path.utf8().get_data(), &io); +				if (!pkg) { + +					dialog_error->set_text("Error opening package file, not in zip format."); +					return; +				} + +				int ret = unzGoToFirstFile(pkg); + +				Vector<String> failed_files; + +				int idx=0; +				while(ret==UNZ_OK) { + +					//get filename +					unz_file_info info; +					char fname[16384]; +					ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0); + +					String path=fname; + +					int depth=1; //stuff from github comes with tag +					bool skip=false; +					while(depth>0) { +						int pp = path.find("/"); +						if (pp==-1) { +							skip=true; +							break; +						} +						path=path.substr(pp+1,path.length()); +						depth--; +					} + + +					if (skip || path==String()) { +						// +					} else if (path.ends_with("/")) { // a dir + +						path=path.substr(0,path.length()-1); + +						DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); +						da->make_dir(dir.plus_file(path)); +						memdelete(da); + +					} else { + +						Vector<uint8_t> data; +						data.resize(info.uncompressed_size); + +						//read +						unzOpenCurrentFile(pkg); +						unzReadCurrentFile(pkg,data.ptr(),data.size()); +						unzCloseCurrentFile(pkg); + +						FileAccess *f=FileAccess::open(dir.plus_file(path),FileAccess::WRITE); + +						if (f) { +							f->store_buffer(data.ptr(),data.size()); +							memdelete(f); +						} else { +							failed_files.push_back(path); +						} + + +					} + +					idx++; +					ret = unzGoToNextFile(pkg); +				} + +				unzClose(pkg); + +				if (failed_files.size()) { +					String msg=TTR("The following files failed extraction from package:")+"\n\n"; +					for(int i=0;i<failed_files.size();i++) { + +						if (i>15) { +							msg+="\nAnd "+itos(failed_files.size()-i)+" more files."; +							break; +						} +						msg+=failed_files[i]+"\n"; +					} + +					dialog_error->set_text(msg); +					dialog_error->popup_centered_minsize(); + +				} else { +					dialog_error->set_text(TTR("Package Installed Successfully!")); +					dialog_error->popup_centered_minsize(); +				} -				f->store_line("; Engine configuration file."); -				f->store_line("; It's best to edit using the editor UI, not directly,"); -				f->store_line("; becausethe parameters that go here are not obvious."); -				f->store_line("; "); -				f->store_line("; Format: "); -				f->store_line(";   [section] ; section goes between []"); -				f->store_line(";   param=value ; assign values to parameters"); -				f->store_line("\n"); -				f->store_line("[application]"); -				f->store_line("name=\""+project_name->get_text()+"\""); -				f->store_line("icon=\"res://icon.png\""); - -				memdelete(f); - -				ResourceSaver::save(dir.plus_file("/icon.png"),get_icon("DefaultProjectIcon","EditorIcons"));  			} @@ -233,10 +350,16 @@ protected:  public: +	void set_zip_path(const String& p_path) { +		zip_path=p_path; +	} +	void set_zip_title(const String& p_title) { +		zip_title=p_title; +	} -	void set_import_mode(bool p_import ) { +	void set_mode(Mode p_mode) { -		import_mode=p_import; +		mode=p_mode;  	}  	void show_dialog() { @@ -245,7 +368,7 @@ public:  		project_path->clear();  		project_name->clear(); -		if (import_mode) { +		if (mode==MODE_IMPORT) {  			set_title(TTR("Import Existing Project"));  			get_ok()->set_text(TTR("Import"));  			pp->set_text(TTR("Project Path (Must Exist):")); @@ -253,9 +376,10 @@ public:  			pn->hide();  			project_name->hide(); -			popup_centered(Size2(500,125)); +			popup_centered(Size2(500,125)*EDSCALE); + +		} else if (mode==MODE_NEW){ -		} else {  			set_title(TTR("Create New Project"));  			get_ok()->set_text(TTR("Create"));  			pp->set_text(TTR("Project Path:")); @@ -263,7 +387,16 @@ public:  			pn->show();  			project_name->show(); -			popup_centered(Size2(500,145)); +			popup_centered(Size2(500,145)*EDSCALE); +		} else if (mode==MODE_INSTALL){ + +			set_title(TTR("Install Project: ")+zip_title); +			get_ok()->set_text(TTR("Install")); +			pp->set_text(TTR("Project Path:")); +			pn->hide(); +			project_name->hide(); + +			popup_centered(Size2(500,125)*EDSCALE);  		} @@ -329,7 +462,10 @@ public:  		fdialog->connect("dir_selected", this,"_path_selected");  		fdialog->connect("file_selected", this,"_file_selected");  		set_hide_on_ok(false); -		import_mode=false; +		mode=MODE_NEW; + +		dialog_error = memnew( AcceptDialog ); +		add_child(dialog_error);  	} @@ -616,6 +752,8 @@ void ProjectManager::_load_recent_projects() {  	run_btn->set_disabled(selected_list.size()<1 || (selected_list.size()==1 && single_selected_main==""));  	EditorSettings::get_singleton()->save(); + +	tabs->set_current_tab(0);  }  void ProjectManager::_open_project_confirm() { @@ -755,14 +893,14 @@ void ProjectManager::_scan_projects() {  void ProjectManager::_new_project()  { -	npdialog->set_import_mode(false); +	npdialog->set_mode(NewProjectDialog::MODE_NEW);  	npdialog->show_dialog();  }  void ProjectManager::_import_project()  { -	npdialog->set_import_mode(true); +	npdialog->set_mode(NewProjectDialog::MODE_IMPORT);  	npdialog->show_dialog();  } @@ -800,6 +938,15 @@ void ProjectManager::_exit_dialog()  {  	get_tree()->quit();  } + +void ProjectManager::_install_project(const String& p_zip_path,const String& p_title) { + +	npdialog->set_mode(NewProjectDialog::MODE_INSTALL); +	npdialog->set_zip_path(p_zip_path); +	npdialog->set_zip_title(p_title); +	npdialog->show_dialog(); +} +  void ProjectManager::_bind_methods() {  	ObjectTypeDB::bind_method("_open_project",&ProjectManager::_open_project); @@ -817,6 +964,7 @@ void ProjectManager::_bind_methods() {  	ObjectTypeDB::bind_method("_panel_draw",&ProjectManager::_panel_draw);  	ObjectTypeDB::bind_method("_panel_input",&ProjectManager::_panel_input);  	ObjectTypeDB::bind_method("_favorite_pressed",&ProjectManager::_favorite_pressed); +	ObjectTypeDB::bind_method("_install_project",&ProjectManager::_install_project);  } @@ -1016,6 +1164,7 @@ ProjectManager::ProjectManager() {  	gui_base->add_child(multi_run_ask); +	asset_library->connect("install_asset",this,"_install_project");  	OS::get_singleton()->set_low_processor_usage_mode(true); diff --git a/tools/editor/project_manager.h b/tools/editor/project_manager.h index 2db1bb839e..69467f50e7 100644 --- a/tools/editor/project_manager.h +++ b/tools/editor/project_manager.h @@ -88,6 +88,8 @@ class ProjectManager : public Control {  	void _load_recent_projects();  	void _scan_dir(DirAccess *da,float pos, float total,List<String> *r_projects); +	void _install_project(const String& p_zip_path,const String& p_title); +  	void _panel_draw(Node *p_hb);  	void _panel_input(const InputEvent& p_ev,Node *p_hb);  	void _favorite_pressed(Node *p_hb); diff --git a/tools/editor/project_settings.cpp b/tools/editor/project_settings.cpp index 6822e50b73..6be1abf52f 100644 --- a/tools/editor/project_settings.cpp +++ b/tools/editor/project_settings.cpp @@ -100,16 +100,6 @@ void ProjectSettings::_notification(int p_what) {  			translation_res_file_open->add_filter("*."+E->get());  			translation_res_option_file_open->add_filter("*."+E->get());  		} - -		List<String> afn; -		ResourceLoader::get_recognized_extensions_for_type("Script",&afn); -		ResourceLoader::get_recognized_extensions_for_type("PackedScene",&afn); - -		for (List<String>::Element *E=afn.front();E;E=E->next()) { - -			autoload_file_open->add_filter("*."+E->get()); -		} -  	}  } @@ -564,7 +554,7 @@ void ProjectSettings::popup_project_settings() {  	popup_centered_ratio();  	globals_editor->update_category_list();  	_update_translations(); -	_update_autoload(); +	autoload_settings->update_autoload();  	plugin_settings->update_plugins();  } @@ -616,10 +606,26 @@ void ProjectSettings::_item_add() {  	String name = catname!="" ? catname+"/"+propname : propname; -	Globals::get_singleton()->set(name,value); +	undo_redo->create_action("Add Global Property"); + +	undo_redo->add_do_property(Globals::get_singleton(), name, value); +	undo_redo->add_do_method(Globals::get_singleton(), "set_persisting", name, true); + +	if (Globals::get_singleton()->has(name)) { +		undo_redo->add_undo_property(Globals::get_singleton(), name, Globals::get_singleton()->get(name)); +	} else { +		undo_redo->add_undo_property(Globals::get_singleton(), name, Variant()); +	} + +	undo_redo->add_do_method(globals_editor, "update_category_list"); +	undo_redo->add_undo_method(globals_editor, "update_category_list"); + +	undo_redo->add_do_method(this, "_settings_changed"); +	undo_redo->add_undo_method(this, "_settings_changed"); + +	undo_redo->commit_action();  	globals_editor->set_current_section(catname); -	globals_editor->update_category_list();  	_settings_changed();  } @@ -633,10 +639,20 @@ void ProjectSettings::_item_del() {  	String name = catname!="" ? catname+"/"+propname : propname; -	Globals::get_singleton()->set(name,Variant()); +	undo_redo->create_action("Delete Global Property"); -	globals_editor->set_current_section(catname); -	globals_editor->update_category_list(); +	undo_redo->add_do_property(Globals::get_singleton(), name, Variant()); + +	undo_redo->add_undo_property(Globals::get_singleton(), name, Globals::get_singleton()->get(name)); +	undo_redo->add_undo_method(Globals::get_singleton(), "set_persisting", name, Globals::get_singleton()->is_persisting(name)); + +	undo_redo->add_do_method(globals_editor, "update_category_list"); +	undo_redo->add_undo_method(globals_editor, "update_category_list"); + +	undo_redo->add_do_method(this, "_settings_changed"); +	undo_redo->add_undo_method(this, "_settings_changed"); + +	undo_redo->commit_action();  	_settings_changed();  } @@ -811,263 +827,6 @@ void ProjectSettings::_translation_file_open() {  	translation_file_open->popup_centered_ratio();  } - -void ProjectSettings::_autoload_file_callback(const String& p_path) { - -	autoload_add_path->set_text(p_path); -	//if (autoload_add_name->get_text().strip_edges()==String()) { - -		autoload_add_name->set_text( p_path.get_file().basename() ); -	//} - -	//_translation_add(p_translation); -} - -void ProjectSettings::_autoload_file_open() { - -	autoload_file_open->popup_centered_ratio(); -} - -void ProjectSettings::_autoload_edited() { - -	if (updating_autoload) -		return; - -	TreeItem *ti = autoload_list->get_edited(); -	int column = autoload_list->get_edited_column(); - -	if (!ti || (column != 0 && column != 2)) -		return; - -	if (column == 0) { -		String name = ti->get_text(0); -		String old_name = selected_autoload.substr(selected_autoload.find("/")+1,selected_autoload.length()); - -		if (!name.is_valid_identifier()) { -			ti->set_text(0,old_name); -			message->set_text(TTR("Invalid name.")+"\n"+TTR("Valid characters:")+" a-z, A-Z, 0-9 or _"); -			message->popup_centered(Size2(300,100)); -			return; -		} - -		if (ObjectTypeDB::type_exists(name)) { -			ti->set_text(0,old_name); -			message->set_text(TTR("Invalid name. Must not collide with an existing engine class name.")); -			message->popup_centered(Size2(400,100)); -			return; -		} - -		for(int i=0;i<Variant::VARIANT_MAX;i++) { -			if (Variant::get_type_name(Variant::Type(i))==name) { -				ti->set_text(0,old_name); -				message->set_text(TTR("Invalid name. Must not collide with an existing buit-in type name.")); -				message->popup_centered(Size2(400,100)); -				return; -			} -		} - -		for(int i=0;i<GlobalConstants::get_global_constant_count();i++) { -			if (GlobalConstants::get_global_constant_name(i)==name) { -				ti->set_text(0,old_name); -				message->set_text(TTR("Invalid name. Must not collide with an existing global constant name.")); -				message->popup_centered(Size2(400,100)); -				return; -			} -		} - -		if (Globals::get_singleton()->has("autoload/"+name)) { -			ti->set_text(0,old_name); -			message->set_text(vformat(TTR("Autoload '%s' already exists!"),name)); -			message->popup_centered(Size2(300,100)); -			return; -		} - -		updating_autoload = true; - -		name = "autoload/"+name; -		String path = Globals::get_singleton()->get(selected_autoload); -		bool is_persisting = Globals::get_singleton()->is_persisting(selected_autoload); -		int order = Globals::get_singleton()->get_order(selected_autoload); - -		undo_redo->create_action(TTR("Rename Autoload")); -		undo_redo->add_do_property(Globals::get_singleton(),name,path); -		undo_redo->add_do_method(Globals::get_singleton(),"set_persisting",name,is_persisting); -		undo_redo->add_do_method(Globals::get_singleton(),"set_order",name,order); -		undo_redo->add_do_method(Globals::get_singleton(),"clear",selected_autoload); -		undo_redo->add_undo_property(Globals::get_singleton(),selected_autoload,path); -		undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",selected_autoload,is_persisting); -		undo_redo->add_undo_method(Globals::get_singleton(),"set_order",selected_autoload,order); -		undo_redo->add_undo_method(Globals::get_singleton(),"clear",name); -		undo_redo->add_do_method(this,"_update_autoload"); -		undo_redo->add_undo_method(this,"_update_autoload"); -		undo_redo->add_do_method(this,"_settings_changed"); -		undo_redo->add_undo_method(this,"_settings_changed"); -		undo_redo->commit_action(); - -		selected_autoload = name; -	} else if (column == 2) { -		updating_autoload = true; - -		bool checked = ti->is_checked(2); -		String base = "autoload/"+ti->get_text(0); -		String path = Globals::get_singleton()->get(base); -		int order = Globals::get_singleton()->get_order(base); - -		if (path.begins_with("*")) -			path = path.substr(1,path.length()); - -		if (checked) -			path = "*" + path; - -		undo_redo->create_action(TTR("Toggle AutoLoad Globals")); -		undo_redo->add_do_property(Globals::get_singleton(),base,path); -		undo_redo->add_undo_property(Globals::get_singleton(),base,Globals::get_singleton()->get(base)); -		undo_redo->add_do_method(Globals::get_singleton(),"set_order",base,order); // keep order, as config order matters for these -		undo_redo->add_undo_method(Globals::get_singleton(),"set_order",base,order); -		undo_redo->add_do_method(this,"_update_autoload"); -		undo_redo->add_undo_method(this,"_update_autoload"); -		undo_redo->add_do_method(this,"_settings_changed"); -		undo_redo->add_undo_method(this,"_settings_changed"); -		undo_redo->commit_action(); -	} - -	updating_autoload = false; -} - -void ProjectSettings::_autoload_add() { - -	String name = autoload_add_name->get_text(); -	if (!name.is_valid_identifier()) { -		message->set_text(TTR("Invalid name.")+"\n"+TTR("Valid characters:")+" a-z, A-Z, 0-9 or _"); -		message->popup_centered(Size2(300,100)); -		return; - -	} - -	if (ObjectTypeDB::type_exists(name)) { - -		message->set_text(TTR("Invalid name. Must not collide with an existing engine class name.")); -		message->popup_centered(Size2(300,100)); -		return; - -	} - -	for(int i=0;i<Variant::VARIANT_MAX;i++) { -		if (Variant::get_type_name(Variant::Type(i))==name) { - -			message->set_text(TTR("Invalid name. Must not collide with an existing buit-in type name.")); -			message->popup_centered(Size2(300,100)); -			return; - -		} -	} - -	for(int i=0;i<GlobalConstants::get_global_constant_count();i++) { - -		if (GlobalConstants::get_global_constant_name(i)==name) { - -			message->set_text(TTR("Invalid name. Must not collide with an existing global constant name.")); -			message->popup_centered(Size2(300,100)); -			return; -		} - -	} - -	String path = autoload_add_path->get_text(); -	if (!FileAccess::exists(path)) { -		message->set_text("Invalid Path.\nFile does not exist."); -		message->popup_centered(Size2(300,100)); -		return; - -	} -	if (!path.begins_with("res://")) { -		message->set_text("Invalid Path.\nNot in resource path."); -		message->popup_centered(Size2(300,100)); -		return; - -	} - -	undo_redo->create_action(TTR("Add Autoload")); -	name = "autoload/"+name; -	undo_redo->add_do_property(Globals::get_singleton(),name,"*"+path); -	if (Globals::get_singleton()->has(name)) -		undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name)); -	else -		undo_redo->add_undo_property(Globals::get_singleton(),name,Variant()); - -	undo_redo->add_do_method(Globals::get_singleton(),"set_persisting",name,true); -	undo_redo->add_do_method(this,"_update_autoload"); -	undo_redo->add_undo_method(this,"_update_autoload"); -	undo_redo->add_do_method(this,"_settings_changed"); -	undo_redo->add_undo_method(this,"_settings_changed"); -	undo_redo->commit_action(); - -	autoload_add_path->set_text(""); -	autoload_add_name->set_text(""); - -	//autoload_file_open->popup_centered_ratio(); -} - -void ProjectSettings::_autoload_delete(Object *p_item,int p_column, int p_button) { - - -	TreeItem *ti=p_item->cast_to<TreeItem>(); -	String name = "autoload/"+ti->get_text(0); - -	if (p_button==0) { -		//delete -		int order = Globals::get_singleton()->get_order(name); -		undo_redo->create_action(TTR("Remove Autoload")); -		undo_redo->add_do_property(Globals::get_singleton(),name,Variant()); -		undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name)); -		undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",name,true); -		undo_redo->add_undo_method(Globals::get_singleton(),"set_order",name,order); -		undo_redo->add_do_method(this,"_update_autoload"); -		undo_redo->add_undo_method(this,"_update_autoload"); -		undo_redo->add_do_method(this,"_settings_changed"); -		undo_redo->add_undo_method(this,"_settings_changed"); -		undo_redo->commit_action(); -	} else { - -		TreeItem *swap = NULL; - -		if (p_button==1) { -			swap=ti->get_prev(); -		} else if (p_button==2) { -			swap=ti->get_next(); -		} -		if (!swap) -			return; - -		String swap_name= "autoload/"+swap->get_text(0); - -		int order = Globals::get_singleton()->get_order(name); -		int swap_order = Globals::get_singleton()->get_order(swap_name); - -		undo_redo->create_action(TTR("Move Autoload")); -		undo_redo->add_do_method(Globals::get_singleton(),"set_order",swap_name,order); -		undo_redo->add_do_method(Globals::get_singleton(),"set_order",name,swap_order); -		undo_redo->add_undo_method(Globals::get_singleton(),"set_order",swap_name,swap_order); -		undo_redo->add_undo_method(Globals::get_singleton(),"set_order",name,order); -		undo_redo->add_do_method(this,"_update_autoload"); -		undo_redo->add_undo_method(this,"_update_autoload"); -		undo_redo->add_do_method(this,"_settings_changed"); -		undo_redo->add_undo_method(this,"_settings_changed"); -		undo_redo->commit_action(); - -	} - -} - -void ProjectSettings::_autoload_selected() { -	TreeItem *ti = autoload_list->get_selected(); - -	if (!ti) -		return; - -	selected_autoload = "autoload/"+ti->get_text(0); -} -  void ProjectSettings::_translation_delete(Object *p_item,int p_column, int p_button) {  	TreeItem *ti = p_item->cast_to<TreeItem>(); @@ -1393,55 +1152,6 @@ void ProjectSettings::_update_translations() {  } -void ProjectSettings::_update_autoload() { - -	if (updating_autoload) -		return; - -	updating_autoload=true; - -	autoload_list->clear(); -	TreeItem *root = autoload_list->create_item(); -	autoload_list->set_hide_root(true); - -	List<PropertyInfo> props; -	Globals::get_singleton()->get_property_list(&props); - -	for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { - -		const PropertyInfo &pi=E->get(); -		if (!pi.name.begins_with("autoload/")) -			continue; - -		String name = pi.name.get_slice("/",1); -		String path = Globals::get_singleton()->get(pi.name); - -		if (name=="") -			continue; -		bool global=false; -		if (path.begins_with("*")) { -			path=path.substr(1,path.length()); -			global=true; -		} -		TreeItem *t = autoload_list->create_item(root); -		t->set_text(0,name); -		t->set_editable(0,true); -		t->set_text(1,path); -		t->set_cell_mode(2,TreeItem::CELL_MODE_CHECK); -		t->set_editable(2,true); -		t->set_text(2,TTR("Enable")); -		t->set_checked(2,global); -		t->add_button(3,get_icon("MoveUp","EditorIcons"),1); -		t->add_button(3,get_icon("MoveDown","EditorIcons"),2); -		t->add_button(3,get_icon("Del","EditorIcons"),0); - - -	} - -	updating_autoload=false; - -} -  void ProjectSettings::_toggle_search_bar(bool p_pressed) {  	globals_editor->get_property_editor()->set_use_filter(p_pressed); @@ -1508,14 +1218,6 @@ void ProjectSettings::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("_translation_res_delete"),&ProjectSettings::_translation_res_delete);  	ObjectTypeDB::bind_method(_MD("_translation_res_option_delete"),&ProjectSettings::_translation_res_option_delete); -	ObjectTypeDB::bind_method(_MD("_autoload_add"),&ProjectSettings::_autoload_add); -	ObjectTypeDB::bind_method(_MD("_autoload_file_open"),&ProjectSettings::_autoload_file_open); -	ObjectTypeDB::bind_method(_MD("_autoload_file_callback"),&ProjectSettings::_autoload_file_callback); -	ObjectTypeDB::bind_method(_MD("_update_autoload"),&ProjectSettings::_update_autoload); -	ObjectTypeDB::bind_method(_MD("_autoload_delete"),&ProjectSettings::_autoload_delete); -	ObjectTypeDB::bind_method(_MD("_autoload_edited"),&ProjectSettings::_autoload_edited); -	ObjectTypeDB::bind_method(_MD("_autoload_selected"),&ProjectSettings::_autoload_selected); -  	ObjectTypeDB::bind_method(_MD("_clear_search_box"),&ProjectSettings::_clear_search_box);  	ObjectTypeDB::bind_method(_MD("_toggle_search_bar"),&ProjectSettings::_toggle_search_bar); @@ -1858,69 +1560,10 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {  	{ -		VBoxContainer *avb = memnew( VBoxContainer ); -		tab_container->add_child(avb); -		avb->set_name(TTR("AutoLoad")); -		HBoxContainer *ahb = memnew( HBoxContainer); -		avb->add_child(ahb); - - -		VBoxContainer *avb_path = memnew( VBoxContainer ); -		avb_path->set_h_size_flags(SIZE_EXPAND_FILL); -		HBoxContainer *ahb_path = memnew( HBoxContainer ); -		autoload_add_path = memnew(LineEdit); -		autoload_add_path->set_h_size_flags(SIZE_EXPAND_FILL); -		ahb_path->add_child(autoload_add_path); -		Button *browseaa = memnew( Button("..") ); -		ahb_path->add_child(browseaa); -		browseaa->connect("pressed",this,"_autoload_file_open"); - -		avb_path->add_margin_child(TTR("Path:"),ahb_path); -		ahb->add_child(avb_path); - -		VBoxContainer *avb_name = memnew( VBoxContainer ); -		avb_name->set_h_size_flags(SIZE_EXPAND_FILL); - -		HBoxContainer *ahb_name = memnew( HBoxContainer ); -		autoload_add_name = memnew(LineEdit); -		autoload_add_name->set_h_size_flags(SIZE_EXPAND_FILL); -		ahb_name->add_child(autoload_add_name); -		avb_name->add_margin_child(TTR("Node Name:"),ahb_name); -		Button *addaa = memnew( Button(TTR("Add")) ); -		ahb_name->add_child(addaa); -		addaa->connect("pressed",this,"_autoload_add"); - -		ahb->add_child(avb_name); - -		autoload_list = memnew( Tree ); -		autoload_list->set_v_size_flags(SIZE_EXPAND_FILL); -		avb->add_margin_child(TTR("List:"),autoload_list,true); - -		autoload_file_open=memnew( EditorFileDialog ); -		add_child(autoload_file_open); -		autoload_file_open->set_mode(EditorFileDialog::MODE_OPEN_FILE); -		autoload_file_open->connect("file_selected",this,"_autoload_file_callback"); - -		autoload_list->set_columns(4); -		autoload_list->set_column_titles_visible(true); -		autoload_list->set_column_title(0,TTR("Name")); -		autoload_list->set_column_expand(0,true); -		autoload_list->set_column_min_width(0,100); -		autoload_list->set_column_title(1,TTR("Path")); -		autoload_list->set_column_expand(1,true); -		autoload_list->set_column_min_width(1,100); -		autoload_list->set_column_title(2,TTR("Singleton")); -		autoload_list->set_column_expand(2,false); -		autoload_list->set_column_min_width(2,80); -		autoload_list->set_column_expand(3,false); -		autoload_list->set_column_min_width(3,80); - -		autoload_list->connect("button_pressed",this,"_autoload_delete"); -		autoload_list->connect("item_edited",this,"_autoload_edited"); -		autoload_list->connect("cell_selected", this, "_autoload_selected"); - -		updating_autoload=false; - +		autoload_settings = memnew( EditorAutoloadSettings ); +		autoload_settings->set_name(TTR("AutoLoad")); +		tab_container->add_child(autoload_settings); +		autoload_settings->connect("autoload_changed", this, "_settings_changed");  	}  	{ diff --git a/tools/editor/project_settings.h b/tools/editor/project_settings.h index 79e1acf75e..46e98f69ad 100644 --- a/tools/editor/project_settings.h +++ b/tools/editor/project_settings.h @@ -34,6 +34,7 @@  #include "undo_redo.h"  #include "editor_data.h"  #include "scene/gui/tab_container.h" +#include "editor_autoload_settings.h"  #include "editor_plugin_settings.h"  //#include "project_export_settings.h" @@ -88,26 +89,10 @@ class ProjectSettings : public AcceptDialog {  	Tree *translation_remap;  	Tree *translation_remap_options; - -	Tree *autoload_list; -	String selected_autoload; -	EditorFileDialog *autoload_file_open; -	LineEdit *autoload_add_name; -	LineEdit *autoload_add_path; - +	EditorAutoloadSettings *autoload_settings;  	EditorPluginSettings *plugin_settings; -	void _update_autoload(); -	void _autoload_file_callback(const String& p_path); -	void _autoload_add(); -	void _autoload_edited(); -	void _autoload_file_open(); -	void _autoload_delete(Object *p_item,int p_column, int p_button); -	void _autoload_selected(); -	bool updating_autoload; - -  	void _item_selected();  	void _item_adds(String);  	void _item_add(); diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index 7816dd9bc7..ceb62d5ff0 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -4187,6 +4187,8 @@ public:  void SectionedPropertyEditor::_bind_methods() {  	ObjectTypeDB::bind_method("_section_selected",&SectionedPropertyEditor::_section_selected); + +	ObjectTypeDB::bind_method("update_category_list", &SectionedPropertyEditor::update_category_list);  }  void SectionedPropertyEditor::_section_selected(int p_which) { diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp index 4526fa26aa..2e7d65eadc 100644 --- a/tools/editor/scene_tree_dock.cpp +++ b/tools/editor/scene_tree_dock.cpp @@ -243,7 +243,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {  			//if (!_validate_no_foreign())  			//	break; -			create_dialog->popup_centered_ratio(); +			create_dialog->popup(true);  		} break;  		case TOOL_INSTANCE: { @@ -281,7 +281,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {  		} break;  		case TOOL_REPLACE: { -			create_dialog->popup_centered_ratio(); +			create_dialog->popup(false);  		} break;  		case TOOL_CONNECT: { diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index edc2fc513d..480d33fd0a 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -623,12 +623,11 @@ void EditorSpatialGizmo::_bind_methods() {  	ObjectTypeDB::bind_method(_MD("add_unscaled_billboard","material:Material","default_scale"),&EditorSpatialGizmo::add_unscaled_billboard,DEFVAL(1));  	ObjectTypeDB::bind_method(_MD("add_handles","handles","billboard","secondary"),&EditorSpatialGizmo::add_handles,DEFVAL(false),DEFVAL(false));  	ObjectTypeDB::bind_method(_MD("set_spatial_node","node:Spatial"),&EditorSpatialGizmo::_set_spatial_node); +	ObjectTypeDB::bind_method(_MD("clear"),&EditorSpatialGizmo::clear);  	BIND_VMETHOD( MethodInfo("redraw"));  	BIND_VMETHOD( MethodInfo(Variant::STRING,"get_handle_name",PropertyInfo(Variant::INT,"index"))); -	{ -		BIND_VMETHOD( MethodInfo("get_handle_value:Variant",PropertyInfo(Variant::INT,"index"))); -	} +	BIND_VMETHOD( MethodInfo("get_handle_value:Variant",PropertyInfo(Variant::INT,"index")));  	BIND_VMETHOD( MethodInfo("set_handle",PropertyInfo(Variant::INT,"index"),PropertyInfo(Variant::OBJECT,"camera:Camera"),PropertyInfo(Variant::VECTOR2,"point")));  	MethodInfo cm = MethodInfo("commit_handle",PropertyInfo(Variant::INT,"index"),PropertyInfo(Variant::NIL,"restore:Variant"),PropertyInfo(Variant::BOOL,"cancel"));  	cm.default_arguments.push_back(false); diff --git a/tools/export/blender25/godot_export_manager.py b/tools/export/blender25/godot_export_manager.py deleted file mode 100644 index c91f55b51c..0000000000 --- a/tools/export/blender25/godot_export_manager.py +++ /dev/null @@ -1,576 +0,0 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -# Script copyright (c) Andreas Esau - -import bpy -from bpy.props import (StringProperty, BoolProperty, EnumProperty, -                       FloatProperty, IntProperty, CollectionProperty) -import os -from bpy.app.handlers import persistent -from mathutils import Matrix - -bl_info = { -    "name": "Godot Export Manager", -    "author": "Andreas Esau", -    "version": (1, 0), -    "blender": (2, 7, 0), -    "location": "Scene Properties > Godot Export Manager", -    "description": "Godot Export Manager uses the Better Collada Exporter" -    "to manage Export Groups and automatically export the objects groups" -    "to Collada Files.", -    "warning": "", -    "wiki_url": ("http://www.godotengine.org"), -    "tracker_url": "", -    "category": "Import-Export"} - - -class godot_export_manager(bpy.types.Panel): -    bl_label = "Godot Export Manager" -    bl_space_type = 'PROPERTIES' -    bl_region_type = 'WINDOW' -    bl_context = "scene" - -    bpy.types.Scene.godot_export_on_save = BoolProperty(default=False) - -    def draw(self, context): -        """ Draw function for all ui elements """ -        layout = self.layout -        split = self.layout.split() -        scene = bpy.data.scenes[0] -        ob = context.object -        scene = context.scene - -        row = layout.row() -        col = row.column() -        col.prop(scene, "godot_export_on_save", text="Export Groups on save") - -        row = layout.row() -        col = row.column(align=True) -        op = col.operator("scene.godot_add_objects_to_group", -                          text="Add selected objects to Group", -                          icon="COPYDOWN") - -        op = col.operator("scene.godot_delete_objects_from_group", -                          text="Delete selected objects from Group", -                          icon="PASTEDOWN") - -        row = layout.row() -        col = row.column() -        col.label(text="Export Groups:") - -        row = layout.row() -        col = row.column() - -        col.template_list("UI_List_Godot", "dummy", scene, -                          "godot_export_groups", scene, -                          "godot_export_groups_index", rows=1, maxrows=10, -                          type='DEFAULT') - -        col = row.column(align=True) -        col.operator("scene.godot_add_export_group", text="", icon="ZOOMIN") -        col.operator("scene.godot_delete_export_group", text="", -                     icon="ZOOMOUT") -        col.operator("scene.godot_export_all_groups", text="", icon="EXPORT") - -        if len(scene.godot_export_groups) > 0: -            row = layout.row() -            col = row.column() -            group = scene.godot_export_groups[scene.godot_export_groups_index] -            col.prop(group, "name", text="Group Name") -            col.prop(group, "export_name", text="Export Name") -            col.prop(group, "export_path", text="Export Filepath") - -            row = layout.row() -            col = row.column() -            row = layout.row() -            col = row.column() -            col.label(text="Export Settings:") - -            col = col.row(align=True) -            col.prop(group, "apply_loc", toggle=True, icon="MAN_TRANS") -            col.prop(group, "apply_rot", toggle=True, icon="MAN_ROT") -            col.prop(group, "apply_scale", toggle=True, icon="MAN_SCALE") - -            row = layout.row() -            col = row.column() - -            col.prop(group, "use_include_particle_duplicates") -            col.prop(group, "use_mesh_modifiers") -            col.prop(group, "use_tangent_arrays") -            col.prop(group, "use_triangles") -            col.prop(group, "use_copy_images") -            col.prop(group, "use_active_layers") -            col.prop(group, "use_anim") -            col.prop(group, "use_anim_action_all") -            col.prop(group, "use_anim_skip_noexp") -            col.prop(group, "use_anim_optimize") -            col.prop(group, "anim_optimize_precision") -            col.prop(group, "use_metadata") - - -class UI_List_Godot(bpy.types.UIList): -    """ Custom template_list look """ -    def draw_item(self, context, layout, data, item, icon, active_data, -                  active_propname, index): -        ob = data -        slot = item -        col = layout.row(align=True) - -        col.label(text=item.name, icon="GROUP") -        col.prop(item, "active", text="") - -        op = col.operator("scene.godot_select_group_objects", -                          text="", emboss=False, icon="RESTRICT_SELECT_OFF") -        op.idx = index -        op = col.operator("scene.godot_export_group", text="", emboss=False, -                          icon="EXPORT") -        op.idx = index - - -class add_objects_to_group(bpy.types.Operator): -    bl_idname = "scene.godot_add_objects_to_group" -    bl_label = "Add Objects to Group" -    bl_description = "Adds the selected Objects to the active group below." - -    undo = BoolProperty(default=True) - -    def execute(self, context): -        scene = context.scene - -        objects_str = "" -        if len(scene.godot_export_groups) > 0: -            for i, object in enumerate(context.selected_objects): -                if object.name not in scene.godot_export_groups[ -                        scene.godot_export_groups_index].nodes: -                    node = scene.godot_export_groups[ -                        scene.godot_export_groups_index].nodes.add() -                    node.name = object.name -                    if i == 0: -                        objects_str += object.name -                    else: -                        objects_str += ", "+object.name - -            self.report({'INFO'}, objects_str + " added to group.") -            if self.undo: -                bpy.ops.ed.undo_push(message="Objects added to group") -        else: -            self.report({'WARNING'}, "Create a group first.") - -        return {'FINISHED'} - - -class del_objects_from_group(bpy.types.Operator): -    bl_idname = "scene.godot_delete_objects_from_group" -    bl_label = "Delete Objects from Group" -    bl_description = "Delets the selected Objects from the active group below." - -    def execute(self, context): -        scene = context.scene - -        if len(scene.godot_export_groups) > 0: - -            selected_objects = [] -            for object in context.selected_objects: -                selected_objects.append(object.name) - -            objects_str = "" -            j = 0 -            for i, node in enumerate(scene.godot_export_groups[ -                    scene.godot_export_groups_index].nodes): -                if node.name in selected_objects: -                    scene.godot_export_groups[ -                        scene.godot_export_groups_index].nodes.remove(i) - -                    if j == 0: -                            objects_str += object.name -                    else: -                        objects_str += ", "+object.name -                    j += 1 - -            self.report({'INFO'}, objects_str + " deleted from group.") -            bpy.ops.ed.undo_push(message="Objects deleted from group") -        else: -            self.report({'WARNING'}, "There is no group to delete from.") - -        return {'FINISHED'} - - -class select_group_objects(bpy.types.Operator): -    bl_idname = "scene.godot_select_group_objects" -    bl_label = "Select Group Objects" -    bl_description = "Will select all group Objects in the scene." - -    idx = IntProperty() - -    def execute(self, context): -        scene = context.scene -        for object in context.scene.objects: -            object.select = False -        for node in scene.godot_export_groups[self.idx].nodes: -            if node.name in bpy.data.objects: -                bpy.data.objects[node.name].select = True -                context.scene.objects.active = bpy.data.objects[node.name] - -        return {'FINISHED'} - - -class export_groups_autosave(bpy.types.Operator): -    bl_idname = "scene.godot_export_groups_autosave" -    bl_label = "Export All Groups" -    bl_description = "Exports all groups to Collada." - -    def execute(self, context): -        scene = context.scene -        if scene.godot_export_on_save: -            for i in range(len(scene.godot_export_groups)): -                if scene.godot_export_groups[i].active: -                    bpy.ops.scene.godot_export_group(idx=i) -        self.report({'INFO'}, "All Groups exported.") -        bpy.ops.ed.undo_push(message="Export all Groups") - -        return {'FINISHED'} - - -class export_all_groups(bpy.types.Operator): -    bl_idname = "scene.godot_export_all_groups" -    bl_label = "Export All Groups" -    bl_description = "Exports all groups to Collada." - -    def execute(self, context): -        scene = context.scene - -        for i in range(0, len(scene.godot_export_groups)): -            bpy.ops.scene.godot_export_group(idx=i, export_all=True) - -        self.report({'INFO'}, "All Groups exported.") - -        return {'FINISHED'} - - -class export_group(bpy.types.Operator): -    bl_idname = "scene.godot_export_group" -    bl_label = "Export Group" -    bl_description = "Exports the active group to destination folder"\ -                     " as Collada file." - -    idx = IntProperty(default=0) -    export_all = BoolProperty(default=False) - -    def copy_object_recursive(self, ob, parent, single_user=True): -        new_ob = bpy.data.objects[ob.name].copy() -        if single_user or ob.type == "ARMATURE": -            new_mesh_data = new_ob.data.copy() -            new_ob.data = new_mesh_data -        bpy.context.scene.objects.link(new_ob) - -        if ob != parent: -            new_ob.parent = parent -        else: -            new_ob.parent = None - -        for child in ob.children: -            self.copy_object_recursive(child, new_ob, single_user) -        new_ob.select = True - -        return new_ob - -    def delete_object(self, ob): -        if ob is not None: -            for child in ob.children: -                self.delete_object(child) -            bpy.context.scene.objects.unlink(ob) -            bpy.data.objects.remove(ob) - -    def convert_group_to_node(self, group): -        if group.dupli_group is not None: -            for object in group.dupli_group.objects: -                if object.parent is None: -                    object = self.copy_object_recursive(object, object, True) -                    matrix = Matrix(object.matrix_local) -                    object.matrix_local = Matrix() -                    object.matrix_local *= group.matrix_local -                    object.matrix_local *= matrix - -            self.delete_object(group) - -    def execute(self, context): - -        scene = context.scene -        group = context.scene.godot_export_groups - -        if not group[self.idx].active and self.export_all: -            return{'FINISHED'} - -        for i, object in enumerate(group[self.idx].nodes): -            if object.name in bpy.data.objects: -                pass -            else: -                group[self.idx].nodes.remove(i) -        bpy.ops.ed.undo_push(message="Clear not existent Group Nodes.") - -        path = group[self.idx].export_path -        if (path.find("//") == 0 or path.find("\\\\") == 0): -            # If relative, convert to absolute -            path = bpy.path.abspath(path) -            path = path.replace("\\", "/") - -        # If path exists and group export name is set the group will be -        # exported -        if os.path.exists(path) and group[self.idx].export_name != "": - -            context.scene.layers = [True] * 20 - -            if group[self.idx].export_name.endswith(".dae"): -                path = os.path.join(path, group[self.idx].export_name) -            else: -                path = os.path.join(path, group[self.idx].export_name+".dae") - -            hide_select = [] -            for object in context.scene.objects: -                hide_select.append(object.hide_select) -                object.hide_select = False -                object.select = False -            context.scene.objects.active = None - -            # Make particle duplicates, parent and select them -            nodes_to_be_added = [] -            if group[self.idx].use_include_particle_duplicates: -                for i, object in enumerate(group[self.idx].nodes): -                    if bpy.data.objects[object.name].type != "EMPTY": -                        context.scene.objects.active = bpy.data.objects[ -                            object.name] -                        bpy.data.objects[object.name].select = True -                        bpy.ops.object.duplicates_make_real() -                        for object in context.selected_objects: -                            nodes_to_be_added.append(object) -                        bpy.ops.object.parent_set(type="OBJECT", -                                                  keep_transform=False) - -                        for object in context.selected_objects: -                            object.select = False -                        bpy.data.objects[object.name].select = False -                        context.scene.objects.active = None -            for object in nodes_to_be_added: -                object.select = True - -            # Select all other nodes from the group -            for i, object in enumerate(group[self.idx].nodes): -                if bpy.data.objects[object.name].type == "EMPTY": -                    self.convert_group_to_node(bpy.data.objects[object.name]) -                else: -                    bpy.data.objects[object.name].select = True - -            bpy.ops.object.transform_apply(location=group[self.idx].apply_loc, -                                           rotation=group[self.idx].apply_rot, -                                           scale=group[self.idx].apply_scale) -            bpy.ops.export_scene.dae( -                check_existing=True, filepath=path, filter_glob="*.dae", -                object_types=group[self.idx].object_types, -                use_export_selected=group[self.idx].use_export_selected, -                use_mesh_modifiers=group[self.idx].use_mesh_modifiers, -                use_tangent_arrays=group[self.idx].use_tangent_arrays, -                use_triangles=group[self.idx].use_triangles, -                use_copy_images=group[self.idx].use_copy_images, -                use_active_layers=group[self.idx].use_active_layers, -                use_anim=group[self.idx].use_anim, -                use_anim_action_all=group[self.idx].use_anim_action_all, -                use_anim_skip_noexp=group[self.idx].use_anim_skip_noexp, -                use_anim_optimize=group[self.idx].use_anim_optimize, -                anim_optimize_precision=group[ -                    self.idx].anim_optimize_precision, -                use_metadata=group[self.idx].use_metadata) - -            self.report({'INFO'}, -                        '"' + group[self.idx].name + '" Group exported.') -            msg = "Export Group "+group[self.idx].name - -            bpy.ops.ed.undo_push(message="") -            bpy.ops.ed.undo() -            bpy.ops.ed.undo_push(message=msg) - -        else: -            self.report({'INFO'}, "Define Export Name and Export Path.") - -        return{'FINISHED'} - - -class add_export_group(bpy.types.Operator): -    bl_idname = "scene.godot_add_export_group" -    bl_label = "Adds a new export Group" -    bl_description = "Creates a new Export Group with the selected"\ -                     " Objects assigned to it." - -    def execute(self, context): -        scene = context.scene - -        item = scene.godot_export_groups.add() -        item.name = "New Group" -        for object in context.selected_objects: -            node = item.nodes.add() -            node.name = object.name -        scene.godot_export_groups_index = len(scene.godot_export_groups)-1 -        bpy.ops.ed.undo_push(message="Create New Export Group") - -        return{'FINISHED'} - - -class del_export_group(bpy.types.Operator): -    bl_idname = "scene.godot_delete_export_group" -    bl_label = "Delets the selected export Group" -    bl_description = "Delets the active Export Group." - -    def invoke(self, context, event): -        wm = context.window_manager - -        return wm.invoke_confirm(self, event) - -    def execute(self, context): -        scene = context.scene - -        scene.godot_export_groups.remove(scene.godot_export_groups_index) -        if scene.godot_export_groups_index > 0: -            scene.godot_export_groups_index -= 1 -        bpy.ops.ed.undo_push(message="Delete Export Group") - -        return {'FINISHED'} - - -class godot_node_list(bpy.types.PropertyGroup): -    name = StringProperty() - - -class godot_export_groups(bpy.types.PropertyGroup): -    name = StringProperty(name="Group Name") -    export_name = StringProperty(name="scene_name") -    nodes = CollectionProperty(type=godot_node_list) -    export_path = StringProperty(subtype="DIR_PATH") -    active = BoolProperty(default=True, description="Export Group") - -    object_types = EnumProperty(name="Object Types", options={'ENUM_FLAG'}, -                                items=(('EMPTY', "Empty", ""), -                                       ('CAMERA', "Camera", ""), -                                       ('LAMP', "Lamp", ""), -                                       ('ARMATURE', "Armature", ""), -                                       ('MESH', "Mesh", ""), -                                       ('CURVE', "Curve", ""), ), -                                default={'EMPTY', 'CAMERA', 'LAMP', -                                         'ARMATURE', 'MESH', 'CURVE'}) - -    apply_scale = BoolProperty(name="Apply Scale", -                               description="Apply Scale before export.", -                               default=False) -    apply_rot = BoolProperty(name="Apply Rotation", -                             description="Apply Rotation before export.", -                             default=False) -    apply_loc = BoolProperty(name="Apply Location", -                             description="Apply Location before export.", -                             default=False) - -    use_export_selected = BoolProperty(name="Selected Objects", -                                       description="Export only selected" -                                       "objects (and visible in active layers " -                                       "if that applies).", default=True) -    use_mesh_modifiers = BoolProperty(name="Apply Modifiers", -                                      description="Apply modifiers to mesh" -                                      " objects (on a copy!).", default=True) -    use_tangent_arrays = BoolProperty(name="Tangent Arrays", -                                      description="Export Tangent and Binormal" -                                      " arrays (for normalmapping).", -                                      default=False) -    use_triangles = BoolProperty(name="Triangulate", -                                 description="Export Triangles instead of" -                                 " Polygons.", default=False) - -    use_copy_images = BoolProperty(name="Copy Images", -                                   description="Copy Images (create images/ " -                                   "subfolder)", default=False) -    use_active_layers = BoolProperty(name="Active Layers", -                                     description="Export only objects on the" -                                     " active layers.", default=True) -    use_anim = BoolProperty(name="Export Animation", -                            description="Export keyframe animation", -                            default=False) -    use_anim_action_all = BoolProperty(name="All Actions", -                                       description=("Export all actions for " -                                                    "the first armature found" -                                                    " in separate DAE files"), -                                       default=False) -    use_anim_skip_noexp = BoolProperty(name="Skip (-noexp) Actions", -                                       description="Skip exporting of" -                                       " actions whose name end in (-noexp)." -                                       " Useful to skip control animations.", -                                       default=True) -    use_anim_optimize = BoolProperty(name="Optimize Keyframes", -                                     description="Remove double keyframes", -                                     default=True) - -    anim_optimize_precision = FloatProperty( -        name="Precision", description=("Tolerence for comparing double " -                                       "keyframes (higher for greater " -                                       "accuracy)"), min=1, max=16, -        soft_min=1, soft_max=16, default=6.0) - -    use_metadata = BoolProperty(name="Use Metadata", default=True, -                                options={'HIDDEN'}) -    use_include_particle_duplicates = BoolProperty( -        name="Include Particle Duplicates", default=True) - - -def register(): -    bpy.utils.register_class(godot_export_manager) -    bpy.utils.register_class(godot_node_list) -    bpy.utils.register_class(godot_export_groups) -    bpy.utils.register_class(add_export_group) -    bpy.utils.register_class(del_export_group) -    bpy.utils.register_class(export_all_groups) -    bpy.utils.register_class(export_groups_autosave) -    bpy.utils.register_class(export_group) -    bpy.utils.register_class(add_objects_to_group) -    bpy.utils.register_class(del_objects_from_group) -    bpy.utils.register_class(select_group_objects) -    bpy.utils.register_class(UI_List_Godot) - -    bpy.types.Scene.godot_export_groups = CollectionProperty( -        type=godot_export_groups) -    bpy.types.Scene.godot_export_groups_index = IntProperty(default=0, min=0) - - -def unregister(): -    bpy.utils.unregister_class(godot_export_manager) -    bpy.utils.unregister_class(godot_node_list) -    bpy.utils.unregister_class(godot_export_groups) -    bpy.utils.unregister_class(export_groups_autosave) -    bpy.utils.unregister_class(add_export_group) -    bpy.utils.unregister_class(del_export_group) -    bpy.utils.unregister_class(export_all_groups) -    bpy.utils.unregister_class(export_group) -    bpy.utils.unregister_class(add_objects_to_group) -    bpy.utils.unregister_class(del_objects_from_group) -    bpy.utils.unregister_class(select_group_objects) -    bpy.utils.unregister_class(UI_List_Godot) - - -@persistent -def auto_export(dummy): -    bpy.ops.scene.godot_export_groups_autosave() - -bpy.app.handlers.save_post.append(auto_export) - -if __name__ == "__main__": -    register() diff --git a/tools/export/blender25/install.txt b/tools/export/blender25/install.txt deleted file mode 100644 index 049af8848e..0000000000 --- a/tools/export/blender25/install.txt +++ /dev/null @@ -1,11 +0,0 @@ -Godot Author's Own Collada Exporter ------------------------------------ - -1) Copy the "io_scene_dae" directory  to wherever blender stores the  -   scripts/addons folder (You will see many other io_scene_blahblah like -   folders). Copy the entire dir, not just the contents, make it just like -   the others. -2) Go to Blender settings and enable the "Better Collada" plugin -3) Enjoy proper Collada export. -4) If it's broken, contact us. -   
\ No newline at end of file diff --git a/tools/export/blender25/io_scene_dae/__init__.py b/tools/export/blender25/io_scene_dae/__init__.py deleted file mode 100644 index 0b82e1537b..0000000000 --- a/tools/export/blender25/io_scene_dae/__init__.py +++ /dev/null @@ -1,192 +0,0 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -#  This program is free software; you can redistribute it and/or -#  modify it under the terms of the GNU General Public License -#  as published by the Free Software Foundation; either version 2 -#  of the License, or (at your option) any later version. -# -#  This program is distributed in the hope that it will be useful, -#  but WITHOUT ANY WARRANTY; without even the implied warranty of -#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -#  GNU General Public License for more details. -# -#  You should have received a copy of the GNU General Public License -#  along with this program; if not, write to the Free Software Foundation, -#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -# <pep8-80 compliant> - -import bpy -from bpy.props import StringProperty, BoolProperty, FloatProperty, EnumProperty - -from bpy_extras.io_utils import ExportHelper -bl_info = { -    "name": "Better Collada Exporter", -    "author": "Juan Linietsky", -    "blender": (2, 5, 8), -    "api": 38691, -    "location": "File > Import-Export", -    "description": ("Export DAE Scenes, This plugin actually works better! " -                    "otherwise contact me."), -    "warning": "", -    "wiki_url": ("http://www.godotengine.org"), -    "tracker_url": "", -    "support": 'OFFICIAL', -    "category": "Import-Export"} - -if "bpy" in locals(): -    import imp -    if "export_dae" in locals(): -        imp.reload(export_dae) - - -class ExportDAE(bpy.types.Operator, ExportHelper): -    '''Selection to DAE''' -    bl_idname = "export_scene.dae" -    bl_label = "Export DAE" -    bl_options = {'PRESET'} - -    filename_ext = ".dae" -    filter_glob = StringProperty(default="*.dae", options={'HIDDEN'}) - -    # List of operator properties, the attributes will be assigned -    # to the class instance from the operator settings before calling. - -    object_types = EnumProperty( -        name="Object Types", -        options={'ENUM_FLAG'}, -        items=(('EMPTY', "Empty", ""), -               ('CAMERA', "Camera", ""), -               ('LAMP', "Lamp", ""), -               ('ARMATURE', "Armature", ""), -               ('MESH', "Mesh", ""), -               ('CURVE', "Curve", ""), -               ), -        default={'EMPTY', 'CAMERA', 'LAMP', 'ARMATURE', 'MESH', 'CURVE'}, -        ) - -    use_export_selected = BoolProperty( -        name="Selected Objects", -        description="Export only selected objects (and visible in active " -                    "layers if that applies).", -        default=False, -        ) -    use_mesh_modifiers = BoolProperty( -        name="Apply Modifiers", -        description="Apply modifiers to mesh objects (on a copy!).", -        default=False, -        ) -    use_tangent_arrays = BoolProperty( -        name="Tangent Arrays", -        description="Export Tangent and Binormal arrays " -                    "(for normalmapping).", -        default=False, -        ) -    use_triangles = BoolProperty( -        name="Triangulate", -        description="Export Triangles instead of Polygons.", -        default=False, -        ) - -    use_copy_images = BoolProperty( -        name="Copy Images", -        description="Copy Images (create images/ subfolder)", -        default=False, -        ) -    use_active_layers = BoolProperty( -        name="Active Layers", -        description="Export only objects on the active layers.", -        default=True, -        ) -    use_anim = BoolProperty( -        name="Export Animation", -        description="Export keyframe animation", -        default=False, -        ) -    use_anim_action_all = BoolProperty( -        name="All Actions", -        description=("Export all actions for the first armature found " -                     "in separate DAE files"), -        default=False, -        ) -    use_anim_skip_noexp = BoolProperty( -        name="Skip (-noexp) Actions", -        description="Skip exporting of actions whose name end in (-noexp)." -                    " Useful to skip control animations.", -        default=True, -        ) -    use_anim_optimize = BoolProperty( -        name="Optimize Keyframes", -        description="Remove double keyframes", -        default=True, -        ) - -    anim_optimize_precision = FloatProperty( -        name="Precision", -        description=("Tolerence for comparing double keyframes " -                     "(higher for greater accuracy)"), -        min=1, max=16, -        soft_min=1, soft_max=16, -        default=6.0, -        ) - -    use_metadata = BoolProperty( -        name="Use Metadata", -        default=True, -        options={'HIDDEN'}, -        ) - -    @property -    def check_extension(self): -        # return self.batch_mode == 'OFF' -        return True - -    def check(self, context): -        return True -        """ -        isretur_def_change = super().check(context) -        return (is_xna_change or is_def_change) -        """ - -    def execute(self, context): -        if not self.filepath: -            raise Exception("filepath not set") - -        """        global_matrix = Matrix() - -                global_matrix[0][0] = \ -                global_matrix[1][1] = \ -                global_matrix[2][2] = self.global_scale -        """ - -        keywords = self.as_keywords(ignore=("axis_forward", -                                            "axis_up", -                                            "global_scale", -                                            "check_existing", -                                            "filter_glob", -                                            "xna_validate", -                                            )) - -        from . import export_dae -        return export_dae.save(self, context, **keywords) - - -def menu_func(self, context): -    self.layout.operator(ExportDAE.bl_idname, text="Better Collada (.dae)") - - -def register(): -    bpy.utils.register_module(__name__) - -    bpy.types.INFO_MT_file_export.append(menu_func) - - -def unregister(): -    bpy.utils.unregister_module(__name__) - -    bpy.types.INFO_MT_file_export.remove(menu_func) - -if __name__ == "__main__": -    register() diff --git a/tools/export/blender25/io_scene_dae/export_dae.py b/tools/export/blender25/io_scene_dae/export_dae.py deleted file mode 100644 index 9f8458c0da..0000000000 --- a/tools/export/blender25/io_scene_dae/export_dae.py +++ /dev/null @@ -1,1923 +0,0 @@ -# ##### BEGIN GPL LICENSE BLOCK ##### -# -#  This program is free software; you can redistribute it and/or -#  modify it under the terms of the GNU General Public License -#  as published by the Free Software Foundation; either version 2 -#  of the License, or (at your option) any later version. -# -#  This program is distributed in the hope that it will be useful, -#  but WITHOUT ANY WARRANTY; without even the implied warranty of -#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -#  GNU General Public License for more details. -# -#  You should have received a copy of the GNU General Public License -#  along with this program; if not, write to the Free Software Foundation, -#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ##### END GPL LICENSE BLOCK ##### - -# <pep8 compliant> - -# Script copyright (C) Juan Linietsky -# Contact Info: juan@codenix.com - -""" -This script is an exporter to the Khronos Collada file format. - -http://www.khronos.org/collada/ -""" - -# TODO: -# Materials & Textures -# Optionally export Vertex Colors -# Morph Targets -# Control bone removal -# Copy textures -# Export Keyframe Optimization -# -- -# Morph Targets -# Blender native material? (?) - -import os -import time -import math  # math.pi -import shutil -import bpy -import bmesh -from mathutils import Vector, Matrix - -# According to collada spec, order matters -S_ASSET = 0 -S_IMGS = 1 -S_FX = 2 -S_MATS = 3 -S_GEOM = 4 -S_MORPH = 5 -S_SKIN = 6 -S_CONT = 7 -S_CAMS = 8 -S_LAMPS = 9 -S_ANIM_CLIPS = 10 -S_NODES = 11 -S_ANIM = 12 - -CMP_EPSILON = 0.0001 - - -def snap_tup(tup): -    ret = () -    for x in tup: -        ret += (x - math.fmod(x, 0.0001), ) - -    return tup - - -def strmtx(mtx): -    s = " " -    for x in range(4): -        for y in range(4): -            s += str(mtx[x][y]) -            s += " " -    s += " " -    return s - - -def numarr(a, mult=1.0): -    s = " " -    for x in a: -        s += " " + str(x * mult) -    s += " " -    return s - - -def numarr_alpha(a, mult=1.0): -    s = " " -    for x in a: -        s += " " + str(x * mult) -    if len(a) == 3: -        s += " 1.0" -    s += " " -    return s - - -def strarr(arr): -    s = " " -    for x in arr: -        s += " " + str(x) -    s += " " -    return s - - -class DaeExporter: - -    def validate_id(self, d): -        if (d.find("id-") == 0): -            return "z" + d -        return d - -    def new_id(self, t): -        self.last_id += 1 -        return "id-" + t + "-" + str(self.last_id) - -    class Vertex: - -        def close_to(self, v): -            if self.vertex - v.vertex.length() > CMP_EPSILON: -                return False -            if self.normal - v.normal.length() > CMP_EPSILON: -                return False -            if self.uv - v.uv.length() > CMP_EPSILON: -                return False -            if self.uv2 - v.uv2.length() > CMP_EPSILON: -                return False - -            return True - -        def get_tup(self): -            tup = (self.vertex.x, self.vertex.y, self.vertex.z, self.normal.x, -                   self.normal.y, self.normal.z) -            for t in self.uv: -                tup = tup + (t.x, t.y) -            if self.color is not None: -                tup = tup + (self.color.x, self.color.y, self.color.z) -            if self.tangent is not None: -                tup = tup + (self.tangent.x, self.tangent.y, self.tangent.z) -            if self.bitangent is not None: -                tup = tup + (self.bitangent.x, self.bitangent.y, -                             self.bitangent.z) -            for t in self.bones: -                tup = tup + (float(t), ) -            for t in self.weights: -                tup = tup + (float(t), ) - -            return tup - -        def __init__(self): -            self.vertex = Vector((0.0, 0.0, 0.0)) -            self.normal = Vector((0.0, 0.0, 0.0)) -            self.tangent = None -            self.bitangent = None -            self.color = None -            self.uv = [] -            self.uv2 = Vector((0.0, 0.0)) -            self.bones = [] -            self.weights = [] - -    def writel(self, section, indent, text): -        if (not (section in self.sections)): -            self.sections[section] = [] -        line = "" -        for x in range(indent): -            line += "\t" -        line += text -        self.sections[section].append(line) - -    def export_image(self, image): -        if (image in self.image_cache): -            return self.image_cache[image] - -        imgpath = image.filepath -        if (imgpath.find("//") == 0 or imgpath.find("\\\\") == 0): -            # If relative, convert to absolute -            imgpath = bpy.path.abspath(imgpath) - -        # Path is absolute, now do something! - -        if (self.config["use_copy_images"]): -            # copy image -            basedir = os.path.dirname(self.path) + "/images" -            if (not os.path.isdir(basedir)): -                os.makedirs(basedir) - -            if os.path.isfile(imgpath): -                dstfile = basedir + "/" + os.path.basename(imgpath) - -                if not os.path.isfile(dstfile): -                    shutil.copy(imgpath, dstfile) -                imgpath = "images/" + os.path.basename(imgpath) -            else: -                # If file is not found save it as png file in the destination -                # folder -                img_tmp_path = image.filepath -                if img_tmp_path.endswith((".bmp", ".rgb", ".png", ".jpeg", -                                          ".jpg", ".jp2", ".tga", ".cin", -                                          ".dpx", ".exr", ".hdr", ".tif")): -                    image.filepath = basedir + "/" + \ -                        os.path.basename(img_tmp_path) -                else: -                    image.filepath = basedir + "/" + image.name + ".png" - -                dstfile = basedir + "/" + os.path.basename(image.filepath) - -                if not os.path.isfile(dstfile): -                    image.save() -                imgpath = "images/" + os.path.basename(image.filepath) -                image.filepath = img_tmp_path - -        else: -            # Export relative, always, no one wants absolute paths. -            try: -                # Export unix compatible always -                imgpath = os.path.relpath( -                    imgpath, os.path.dirname(self.path)).replace("\\", "/") - -            except: -                # Fails sometimes, not sure why -                pass - -        imgid = self.new_id("image") - -        print("FOR: " + imgpath) - -#        if (not os.path.isfile(imgpath)): -#            print("NOT FILE?") -#            if imgpath.endswith((".bmp", ".rgb", ".png", ".jpeg", ".jpg", -#                                 ".jp2", ".tga", ".cin", ".dpx", ".exr", -#                                 ".hdr", ".tif")): -#                imgpath="images/"+os.path.basename(imgpath) -#            else: -#                imgpath="images/"+image.name+".png" - -        self.writel(S_IMGS, 1, '<image id="' + imgid + -                    '" name="' + image.name + '">') -        self.writel(S_IMGS, 2, '<init_from>' + imgpath + '</init_from>') -        self.writel(S_IMGS, 1, '</image>') -        self.image_cache[image] = imgid -        return imgid - -    def export_material(self, material, double_sided_hint=True): -        if (material in self.material_cache): -            return self.material_cache[material] - -        fxid = self.new_id("fx") -        self.writel(S_FX, 1, '<effect id="' + fxid + '" name="' + -                    material.name + '-fx">') -        self.writel(S_FX, 2, '<profile_COMMON>') - -        # Find and fetch the textures and create sources -        sampler_table = {} -        diffuse_tex = None -        specular_tex = None -        emission_tex = None -        normal_tex = None -        for i in range(len(material.texture_slots)): -            ts = material.texture_slots[i] -            if not ts: -                continue -            if not ts.use: -                continue -            if not ts.texture: -                continue -            if ts.texture.type != "IMAGE": -                continue - -            if ts.texture.image is None: -                continue - -            # Image -            imgid = self.export_image(ts.texture.image) - -            # Surface -            surface_sid = self.new_id("fx_surf") -            self.writel(S_FX, 3, '<newparam sid="' + surface_sid + '">') -            self.writel(S_FX, 4, '<surface type="2D">') -            # This is sooo weird -            self.writel(S_FX, 5, '<init_from>' + imgid + '</init_from>') -            self.writel(S_FX, 5, '<format>A8R8G8B8</format>') -            self.writel(S_FX, 4, '</surface>') -            self.writel(S_FX, 3, '</newparam>') -            # Sampler, collada sure likes it difficult -            sampler_sid = self.new_id("fx_sampler") -            self.writel(S_FX, 3, '<newparam sid="' + sampler_sid + '">') -            self.writel(S_FX, 4, '<sampler2D>') -            self.writel(S_FX, 5, '<source>' + surface_sid + '</source>') -            self.writel(S_FX, 4, '</sampler2D>') -            self.writel(S_FX, 3, '</newparam>') -            sampler_table[i] = sampler_sid - -            if ts.use_map_color_diffuse and diffuse_tex is None: -                diffuse_tex = sampler_sid -            if ts.use_map_color_spec and specular_tex is None: -                specular_tex = sampler_sid -            if ts.use_map_emit and emission_tex is None: -                emission_tex = sampler_sid -            if ts.use_map_normal and normal_tex is None: -                normal_tex = sampler_sid - -        self.writel(S_FX, 3, '<technique sid="common">') -        shtype = "blinn" -        self.writel(S_FX, 4, '<' + shtype + '>') -        # Ambient? from where? - -        self.writel(S_FX, 5, '<emission>') -        if emission_tex is not None: -            self.writel(S_FX, 6, '<texture texture="' + emission_tex + -                        '" texcoord="CHANNEL1"/>') -        else: -            self.writel(S_FX, 6, '<color>' + -                        numarr_alpha(material.diffuse_color, material.emit) + -                        ' </color>')  # not totally right but good enough -        self.writel(S_FX, 5, '</emission>') - -        self.writel(S_FX, 5, '<ambient>') -        self.writel(S_FX, 6, '<color>' + -                    numarr_alpha(self.scene.world.ambient_color, -                                 material.ambient) + ' </color>') -        self.writel(S_FX, 5, '</ambient>') - -        self.writel(S_FX, 5, '<diffuse>') -        if diffuse_tex is not None: -            self.writel(S_FX, 6, '<texture texture="' + diffuse_tex + -                        '" texcoord="CHANNEL1"/>') -        else: -            self.writel(S_FX, 6, -                        '<color>' + numarr_alpha(material.diffuse_color, -                                                 material.diffuse_intensity) + -                        '</color>') -        self.writel(S_FX, 5, '</diffuse>') - -        self.writel(S_FX, 5, '<specular>') -        if specular_tex is not None: -            self.writel(S_FX, 6, '<texture texture="' + specular_tex + -                        '" texcoord="CHANNEL1"/>') -        else: -            self.writel(S_FX, 6, '<color>' + numarr_alpha( -                material.specular_color, material.specular_intensity) + -                '</color>') -        self.writel(S_FX, 5, '</specular>') - -        self.writel(S_FX, 5, '<shininess>') -        self.writel(S_FX, 6, '<float>' + str(material.specular_hardness) + -                    '</float>') -        self.writel(S_FX, 5, '</shininess>') - -        self.writel(S_FX, 5, '<reflective>') -        self.writel(S_FX, 6, '<color>' + numarr_alpha(material.mirror_color) + -                    '</color>') -        self.writel(S_FX, 5, '</reflective>') - -        if (material.use_transparency): -            self.writel(S_FX, 5, '<transparency>') -            self.writel(S_FX, 6, '<float>' + str(material.alpha) + '</float>') -            self.writel(S_FX, 5, '</transparency>') - -        self.writel(S_FX, 5, '<index_of_refraction>') -        self.writel(S_FX, 6, '<float>' + str(material.specular_ior) + -                    '</float>') -        self.writel(S_FX, 5, '</index_of_refraction>') - -        self.writel(S_FX, 4, '</' + shtype + '>') - -        self.writel(S_FX, 4, '<extra>') -        self.writel(S_FX, 5, '<technique profile="FCOLLADA">') -        if (normal_tex): -            self.writel(S_FX, 6, '<bump bumptype="NORMALMAP">') -            self.writel(S_FX, 7, '<texture texture="' + normal_tex + -                        '" texcoord="CHANNEL1"/>') -            self.writel(S_FX, 6, '</bump>') - -        self.writel(S_FX, 5, '</technique>') -        self.writel(S_FX, 5, '<technique profile="GOOGLEEARTH">') -        self.writel(S_FX, 6, '<double_sided>' + ["0", "1"][double_sided_hint] + -                    "</double_sided>") -        self.writel(S_FX, 5, '</technique>') - -        if (material.use_shadeless): -            self.writel(S_FX, 5, '<technique profile="GODOT">') -            self.writel(S_FX, 6, '<unshaded>1</unshaded>') -            self.writel(S_FX, 5, '</technique>') - -        self.writel(S_FX, 4, '</extra>') - -        self.writel(S_FX, 3, '</technique>') -        self.writel(S_FX, 2, '</profile_COMMON>') -        self.writel(S_FX, 1, '</effect>') - -        # Also export blender material in all it's glory (if set as active) - -        # Material -        matid = self.new_id("material") -        self.writel(S_MATS, 1, '<material id="' + matid + '" name="' + -                    material.name + '">') -        self.writel(S_MATS, 2, '<instance_effect url="#' + fxid + '"/>') -        self.writel(S_MATS, 1, '</material>') - -        self.material_cache[material] = matid -        return matid - -    def export_mesh(self, node, armature=None, skeyindex=-1, skel_source=None, -                    custom_name=None): -        mesh = node.data - -        if (node.data in self.mesh_cache): -            return self.mesh_cache[mesh] - -        if (skeyindex == -1 and mesh.shape_keys is not None and len( -                mesh.shape_keys.key_blocks)): -            values = [] -            morph_targets = [] -            md = None -            for k in range(0, len(mesh.shape_keys.key_blocks)): -                shape = node.data.shape_keys.key_blocks[k] -                values += [shape.value]  # save value -                shape.value = 0 - -            mid = self.new_id("morph") - -            for k in range(0, len(mesh.shape_keys.key_blocks)): - -                shape = node.data.shape_keys.key_blocks[k] -                node.show_only_shape_key = True -                node.active_shape_key_index = k -                shape.value = 1.0 -                mesh.update() -                """ -                oldval = shape.value -                shape.value = 1.0 - -                """ -                p = node.data -                v = node.to_mesh(bpy.context.scene, True, "RENDER") -                node.data = v -#                self.export_node(node, il, shape.name) -                node.data.update() -                if (armature and k == 0): -                    md = self.export_mesh(node, armature, k, mid, shape.name) -                else: -                    md = self.export_mesh(node, None, k, None, shape.name) - -                node.data = p -                node.data.update() -                shape.value = 0.0 -                morph_targets.append(md) - -                """ -                shape.value = oldval -                """ -            node.show_only_shape_key = False -            node.active_shape_key_index = 0 - -            self.writel(S_MORPH, 1, '<controller id="' + mid + '" name="">') -            # if ("skin_id" in morph_targets[0]): -            #    self.writel(S_MORPH, 2, '<morph source="#'+morph_targets[0][ -            #    "skin_id"]+'" method="NORMALIZED">') -            # else: -            self.writel(S_MORPH, 2, '<morph source="#' + -                        morph_targets[0]["id"] + '" method="NORMALIZED">') - -            self.writel(S_MORPH, 3, '<source id="' + mid + '-morph-targets">') -            self.writel(S_MORPH, 4, '<IDREF_array id="' + mid + -                        '-morph-targets-array" count="' + -                        str(len(morph_targets) - 1) + '">') -            marr = "" -            warr = "" -            for i in range(len(morph_targets)): -                if (i == 0): -                    continue -                elif (i > 1): -                    marr += " " - -                if ("skin_id" in morph_targets[i]): -                    marr += morph_targets[i]["skin_id"] -                else: -                    marr += morph_targets[i]["id"] - -                warr += " 0" - -            self.writel(S_MORPH, 5, marr) -            self.writel(S_MORPH, 4, '</IDREF_array>') -            self.writel(S_MORPH, 4, '<technique_common>') -            self.writel(S_MORPH, 5, '<accessor source="#' + mid + -                        '-morph-targets-array" count="' + -                        str(len(morph_targets) - 1) + '" stride="1">') -            self.writel( -                S_MORPH, 6, '<param name="MORPH_TARGET" type="IDREF"/>') -            self.writel(S_MORPH, 5, '</accessor>') -            self.writel(S_MORPH, 4, '</technique_common>') -            self.writel(S_MORPH, 3, '</source>') - -            self.writel(S_MORPH, 3, '<source id="' + mid + '-morph-weights">') -            self.writel(S_MORPH, 4, '<float_array id="' + mid + -                        '-morph-weights-array" count="' + -                        str(len(morph_targets) - 1) + '" >') -            self.writel(S_MORPH, 5, warr) -            self.writel(S_MORPH, 4, '</float_array>') -            self.writel(S_MORPH, 4, '<technique_common>') -            self.writel(S_MORPH, 5, '<accessor source="#' + mid + -                        '-morph-weights-array" count="' + -                        str(len(morph_targets) - 1) + '" stride="1">') -            self.writel( -                S_MORPH, 6, '<param name="MORPH_WEIGHT" type="float"/>') -            self.writel(S_MORPH, 5, '</accessor>') -            self.writel(S_MORPH, 4, '</technique_common>') -            self.writel(S_MORPH, 3, '</source>') - -            self.writel(S_MORPH, 3, '<targets>') -            self.writel( -                S_MORPH, 4, '<input semantic="MORPH_TARGET" source="#' + mid + -                '-morph-targets"/>') -            self.writel( -                S_MORPH, 4, '<input semantic="MORPH_WEIGHT" source="#' + mid + -                '-morph-weights"/>') -            self.writel(S_MORPH, 3, '</targets>') -            self.writel(S_MORPH, 2, '</morph>') -            self.writel(S_MORPH, 1, '</controller>') -            if armature is not None: - -                self.armature_for_morph[node] = armature - -            meshdata = {} -            if (armature): -                meshdata = morph_targets[0] -                meshdata["morph_id"] = mid -            else: -                meshdata["id"] = morph_targets[0]["id"] -                meshdata["morph_id"] = mid -                meshdata["material_assign"] = morph_targets[ -                    0]["material_assign"] - -            self.mesh_cache[node.data] = meshdata -            return meshdata - -        apply_modifiers = len(node.modifiers) and self.config[ -            "use_mesh_modifiers"] - -        name_to_use = mesh.name -        # print("name to use: "+mesh.name) -        if (custom_name is not None and custom_name != ""): -            name_to_use = custom_name - -        mesh = node.to_mesh(self.scene, apply_modifiers, -                            "RENDER")  # is this allright? - -        triangulate = self.config["use_triangles"] -        if (triangulate): -            bm = bmesh.new() -            bm.from_mesh(mesh) -            bmesh.ops.triangulate(bm, faces=bm.faces) -            bm.to_mesh(mesh) -            bm.free() - -        mesh.update(calc_tessface=True) -        vertices = [] -        vertex_map = {} -        surface_indices = {} -        materials = {} - -        materials = {} - -        si = None -        if armature is not None: -            si = self.skeleton_info[armature] - -        has_uv = False -        has_uv2 = False -        has_weights = armature is not None -        has_tangents = self.config["use_tangent_arrays"]  # could detect.. -        has_colors = len(mesh.vertex_colors) -        mat_assign = [] - -        uv_layer_count = len(mesh.uv_textures) -        if has_tangents and len(mesh.uv_textures): -            try: -                mesh.calc_tangents() -            except: -                self.operator.report( -                    {'WARNING'}, 'CalcTangets failed for mesh "' + mesh.name + -                    '", no tangets will be exported.') -                # uv_layer_count=0 -                mesh.calc_normals_split() -                has_tangents = False - -        else: -            mesh.calc_normals_split() -            has_tangents = False - -        for fi in range(len(mesh.polygons)): -            f = mesh.polygons[fi] - -            if not (f.material_index in surface_indices): -                surface_indices[f.material_index] = [] -                # print("Type: " + str(type(f.material_index))) -                # print("IDX: " + str(f.material_index) + "/" + str( -                #     len(mesh.materials))) - -                try: -                    # Bizarre blender behavior i don't understand, -                    # so catching exception -                    mat = mesh.materials[f.material_index] -                except: -                    mat = None - -                if (mat is not None): -                    materials[f.material_index] = self.export_material( -                        mat, mesh.show_double_sided) -                else: -                    # weird, has no material? -                    materials[f.material_index] = None - -            indices = surface_indices[f.material_index] -            vi = [] -            # Vertices always 3 -            """ -            if (len(f.vertices)==3): -                vi.append(0) -                vi.append(1) -                vi.append(2) -            elif (len(f.vertices)==4): -                #todo, should use shortest path -                vi.append(0) -                vi.append(1) -                vi.append(2) -                vi.append(0) -                vi.append(2) -                vi.append(3) -            """ - -            for lt in range(f.loop_total): -                loop_index = f.loop_start + lt -                ml = mesh.loops[loop_index] -                mv = mesh.vertices[ml.vertex_index] - -                v = self.Vertex() -                v.vertex = Vector(mv.co) - -                for xt in mesh.uv_layers: -                    v.uv.append(Vector(xt.data[loop_index].uv)) - -                if (has_colors): -                    v.color = Vector( -                        mesh.vertex_colors[0].data[loop_index].color) - -                v.normal = Vector(ml.normal) - -                if (has_tangents): -                    v.tangent = Vector(ml.tangent) -                    v.bitangent = Vector(ml.bitangent) - -                    # if (armature): -                    #         v.vertex = node.matrix_world * v.vertex - -                # v.color=Vertex(mv. ??? - -                if armature is not None: -                    wsum = 0.0 -                    zero_bones = [] - -                    for vg in mv.groups: -                        if vg.group >= len(node.vertex_groups): -                            continue -                        name = node.vertex_groups[vg.group].name - -                        if (name in si["bone_index"]): -                            # could still put the weight as 0.0001 maybe -                            # blender has a lot of zero weight stuff -                            if (vg.weight > 0.001): -                                v.bones.append(si["bone_index"][name]) -                                v.weights.append(vg.weight) -                                wsum += vg.weight -                    if (wsum == 0.0): -                        if not self.wrongvtx_report: -                            self.operator.report( -                                {'WARNING'}, 'Mesh for object "' + node.name + -                                '" has unassigned weights. ' -                                'This may look wrong in exported model.') -                            self.wrongvtx_report = True - -                        # blender can have bones assigned that weight zero -                        # so they remain local -                        # this is the best it can be done? -                        v.bones.append(0) -                        v.weights.append(1) - -                tup = v.get_tup() -                idx = 0 -                # do not optmize if using shapekeys -                if (skeyindex == -1 and tup in vertex_map): -                    idx = vertex_map[tup] -                else: -                    idx = len(vertices) -                    vertices.append(v) -                    vertex_map[tup] = idx - -                vi.append(idx) - -            if (len(vi) > 2): -                # only triangles and above -                indices.append(vi) - -        meshid = self.new_id("mesh") -        self.writel(S_GEOM, 1, '<geometry id="' + meshid + -                    '" name="' + name_to_use + '">') - -        self.writel(S_GEOM, 2, '<mesh>') - -        # Vertex Array -        self.writel(S_GEOM, 3, '<source id="' + meshid + '-positions">') -        float_values = "" -        for v in vertices: -            float_values += " " + str(v.vertex.x) + " " + \ -                str(v.vertex.y) + " " + str(v.vertex.z) -        self.writel(S_GEOM, 4, '<float_array id="' + meshid + -                    '-positions-array" count="' + -                    str(len(vertices) * 3) + '">' + float_values + -                    '</float_array>') -        self.writel(S_GEOM, 4, '<technique_common>') -        self.writel(S_GEOM, 4, '<accessor source="#' + meshid + -                    '-positions-array" count="' + str(len(vertices)) + -                    '" stride="3">') -        self.writel(S_GEOM, 5, '<param name="X" type="float"/>') -        self.writel(S_GEOM, 5, '<param name="Y" type="float"/>') -        self.writel(S_GEOM, 5, '<param name="Z" type="float"/>') -        self.writel(S_GEOM, 4, '</accessor>') -        self.writel(S_GEOM, 4, '</technique_common>') -        self.writel(S_GEOM, 3, '</source>') - -        # Normal Array - -        self.writel(S_GEOM, 3, '<source id="' + meshid + '-normals">') -        float_values = "" -        for v in vertices: -            float_values += " " + str(v.normal.x) + " " + \ -                str(v.normal.y) + " " + str(v.normal.z) -        self.writel(S_GEOM, 4, '<float_array id="' + meshid + -                    '-normals-array" count="' + -                    str(len(vertices) * 3) + '">' + float_values + -                    '</float_array>') -        self.writel(S_GEOM, 4, '<technique_common>') -        self.writel(S_GEOM, 4, '<accessor source="#' + meshid + -                    '-normals-array" count="' + str(len(vertices)) + -                    '" stride="3">') -        self.writel(S_GEOM, 5, '<param name="X" type="float"/>') -        self.writel(S_GEOM, 5, '<param name="Y" type="float"/>') -        self.writel(S_GEOM, 5, '<param name="Z" type="float"/>') -        self.writel(S_GEOM, 4, '</accessor>') -        self.writel(S_GEOM, 4, '</technique_common>') -        self.writel(S_GEOM, 3, '</source>') - -        if (has_tangents): -            self.writel(S_GEOM, 3, '<source id="' + meshid + '-tangents">') -            float_values = "" -            for v in vertices: -                float_values += " " + \ -                    str(v.tangent.x) + " " + \ -                    str(v.tangent.y) + " " + str(v.tangent.z) -            self.writel(S_GEOM, 4, '<float_array id="' + meshid + -                        '-tangents-array" count="' + -                        str(len(vertices) * 3) + '">' + float_values + -                        '</float_array>') -            self.writel(S_GEOM, 4, '<technique_common>') -            self.writel(S_GEOM, 4, '<accessor source="#' + meshid + -                        '-tangents-array" count="' + str(len(vertices)) + -                        '" stride="3">') -            self.writel(S_GEOM, 5, '<param name="X" type="float"/>') -            self.writel(S_GEOM, 5, '<param name="Y" type="float"/>') -            self.writel(S_GEOM, 5, '<param name="Z" type="float"/>') -            self.writel(S_GEOM, 4, '</accessor>') -            self.writel(S_GEOM, 4, '</technique_common>') -            self.writel(S_GEOM, 3, '</source>') - -            self.writel(S_GEOM, 3, '<source id="' + meshid + '-bitangents">') -            float_values = "" -            for v in vertices: -                float_values += " " + \ -                    str(v.bitangent.x) + " " + \ -                    str(v.bitangent.y) + " " + str(v.bitangent.z) -            self.writel(S_GEOM, 4, '<float_array id="' + meshid + -                        '-bitangents-array" count="' + -                        str(len(vertices) * 3) + '">' + float_values + -                        '</float_array>') -            self.writel(S_GEOM, 4, '<technique_common>') -            self.writel(S_GEOM, 4, '<accessor source="#' + meshid + -                        '-bitangents-array" count="' + str(len(vertices)) + -                        '" stride="3">') -            self.writel(S_GEOM, 5, '<param name="X" type="float"/>') -            self.writel(S_GEOM, 5, '<param name="Y" type="float"/>') -            self.writel(S_GEOM, 5, '<param name="Z" type="float"/>') -            self.writel(S_GEOM, 4, '</accessor>') -            self.writel(S_GEOM, 4, '</technique_common>') -            self.writel(S_GEOM, 3, '</source>') - -        # UV Arrays - -        for uvi in range(uv_layer_count): - -            self.writel(S_GEOM, 3, '<source id="' + meshid + -                        '-texcoord-' + str(uvi) + '">') -            float_values = "" -            for v in vertices: -                try: -                    float_values += " " + \ -                        str(v.uv[uvi].x) + " " + str(v.uv[uvi].y) -                except: -                    # I don't understand this weird multi-uv-layer API, but -                    # with this it seems to works -                    float_values += " 0 0 " - -            self.writel(S_GEOM, 4, '<float_array id="' + meshid + -                        '-texcoord-' + str(uvi) + -                        '-array" count="' + str(len(vertices) * 2) + '">' + -                        float_values + '</float_array>') -            self.writel(S_GEOM, 4, '<technique_common>') -            self.writel(S_GEOM, 4, '<accessor source="#' + meshid + -                        '-texcoord-' + -                        str(uvi) + '-array" count="' + str(len(vertices)) + -                        '" stride="2">') -            self.writel(S_GEOM, 5, '<param name="S" type="float"/>') -            self.writel(S_GEOM, 5, '<param name="T" type="float"/>') -            self.writel(S_GEOM, 4, '</accessor>') -            self.writel(S_GEOM, 4, '</technique_common>') -            self.writel(S_GEOM, 3, '</source>') - -        # Color Arrays - -        if (has_colors): -            self.writel(S_GEOM, 3, '<source id="' + meshid + '-colors">') -            float_values = "" -            for v in vertices: -                float_values += " " + \ -                    str(v.color.x) + " " + \ -                    str(v.color.y) + " " + str(v.color.z) -            self.writel(S_GEOM, 4, '<float_array id="' + meshid + -                        '-colors-array" count="' + -                        str(len(vertices) * 3) + '">' + float_values + -                        '</float_array>') -            self.writel(S_GEOM, 4, '<technique_common>') -            self.writel(S_GEOM, 4, '<accessor source="#' + meshid + -                        '-colors-array" count="' + str(len(vertices)) + -                        '" stride="3">') -            self.writel(S_GEOM, 5, '<param name="X" type="float"/>') -            self.writel(S_GEOM, 5, '<param name="Y" type="float"/>') -            self.writel(S_GEOM, 5, '<param name="Z" type="float"/>') -            self.writel(S_GEOM, 4, '</accessor>') -            self.writel(S_GEOM, 4, '</technique_common>') -            self.writel(S_GEOM, 3, '</source>') - -        # Triangle Lists -        self.writel(S_GEOM, 3, '<vertices id="' + meshid + '-vertices">') -        self.writel( -            S_GEOM, 4, '<input semantic="POSITION" source="#' + meshid + -            '-positions"/>') -        self.writel(S_GEOM, 3, '</vertices>') - -        prim_type = "" -        if (triangulate): -            prim_type = "triangles" -        else: -            prim_type = "polygons" - -        for m in surface_indices: -            indices = surface_indices[m] -            mat = materials[m] - -            if (mat is not None): -                matref = self.new_id("trimat") -                self.writel(S_GEOM, 3, '<' + prim_type + ' count="' + str( -                    int(len(indices))) + '" material="' + matref + -                            '">')  # todo material -                mat_assign.append((mat, matref)) -            else: -                self.writel(S_GEOM, 3, '<' + prim_type + ' count="' + -                            str(int(len(indices))) + '">')  # todo material - -            self.writel(S_GEOM, 4, '<input semantic="VERTEX" source="#' + -                        meshid + '-vertices" offset="0"/>') -            self.writel(S_GEOM, 4, '<input semantic="NORMAL" source="#' + -                        meshid + '-normals" offset="0"/>') - -            for uvi in range(uv_layer_count): -                self.writel(S_GEOM, 4, '<input semantic="TEXCOORD" source="#' + -                            meshid + -                            '-texcoord-' + str(uvi) + '" offset="0" set="' + -                            str(uvi) + '"/>') - -            if (has_colors): -                self.writel(S_GEOM, 4, '<input semantic="COLOR" source="#' + -                            meshid + '-colors" offset="0"/>') -            if (has_tangents): -                self.writel(S_GEOM, 4, -                            '<input semantic="TEXTANGENT" source="#' + -                            meshid + '-tangents" offset="0"/>') -                self.writel(S_GEOM, 4, -                            '<input semantic="TEXBINORMAL" source="#' + -                            meshid + '-bitangents" offset="0"/>') - -            if (triangulate): -                int_values = "<p>" -                for p in indices: -                    for i in p: -                        int_values += " " + str(i) -                int_values += " </p>" -                self.writel(S_GEOM, 4, int_values) -            else: -                for p in indices: -                    int_values = "<p>" -                    for i in p: -                        int_values += " " + str(i) -                    int_values += " </p>" -                    self.writel(S_GEOM, 4, int_values) - -            self.writel(S_GEOM, 3, '</' + prim_type + '>') - -        self.writel(S_GEOM, 2, '</mesh>') -        self.writel(S_GEOM, 1, '</geometry>') - -        meshdata = {} -        meshdata["id"] = meshid -        meshdata["material_assign"] = mat_assign -        if (skeyindex == -1): -            self.mesh_cache[node.data] = meshdata - -        # Export armature data (if armature exists) - -        if (armature is not None and ( -                skel_source is not None or skeyindex == -1)): - -            contid = self.new_id("controller") - -            self.writel(S_SKIN, 1, '<controller id="' + contid + '">') -            if (skel_source is not None): -                self.writel(S_SKIN, 2, '<skin source="#' + skel_source + '">') -            else: -                self.writel(S_SKIN, 2, '<skin source="#' + meshid + '">') - -            self.writel(S_SKIN, 3, '<bind_shape_matrix>' + -                        strmtx(node.matrix_world) + '</bind_shape_matrix>') -            # Joint Names -            self.writel(S_SKIN, 3, '<source id="' + contid + '-joints">') -            name_values = "" -            for v in si["bone_names"]: -                name_values += " " + v - -            self.writel(S_SKIN, 4, '<Name_array id="' + contid + -                        '-joints-array" count="' + -                        str(len(si["bone_names"])) + '">' + name_values + -                        '</Name_array>') -            self.writel(S_SKIN, 4, '<technique_common>') -            self.writel(S_SKIN, 4, '<accessor source="#' + contid + -                        '-joints-array" count="' + str(len(si["bone_names"])) + -                        '" stride="1">') -            self.writel(S_SKIN, 5, '<param name="JOINT" type="Name"/>') -            self.writel(S_SKIN, 4, '</accessor>') -            self.writel(S_SKIN, 4, '</technique_common>') -            self.writel(S_SKIN, 3, '</source>') -            # Pose Matrices! -            self.writel(S_SKIN, 3, '<source id="' + contid + '-bind_poses">') -            pose_values = "" -            for v in si["bone_bind_poses"]: -                pose_values += " " + strmtx(v) - -            self.writel(S_SKIN, 4, '<float_array id="' + contid + -                        '-bind_poses-array" count="' + -                        str(len(si["bone_bind_poses"]) * 16) + '">' + -                        pose_values + '</float_array>') -            self.writel(S_SKIN, 4, '<technique_common>') -            self.writel(S_SKIN, 4, '<accessor source="#' + contid + -                        '-bind_poses-array" count="' + -                        str(len(si["bone_bind_poses"])) + '" stride="16">') -            self.writel(S_SKIN, 5, '<param name="TRANSFORM" type="float4x4"/>') -            self.writel(S_SKIN, 4, '</accessor>') -            self.writel(S_SKIN, 4, '</technique_common>') -            self.writel(S_SKIN, 3, '</source>') -            # Skin Weights! -            self.writel(S_SKIN, 3, '<source id="' + contid + '-skin_weights">') -            skin_weights = "" -            skin_weights_total = 0 -            for v in vertices: -                skin_weights_total += len(v.weights) -                for w in v.weights: -                    skin_weights += " " + str(w) - -            self.writel(S_SKIN, 4, '<float_array id="' + contid + -                        '-skin_weights-array" count="' + -                        str(skin_weights_total) + '">' + skin_weights + -                        '</float_array>') -            self.writel(S_SKIN, 4, '<technique_common>') -            self.writel(S_SKIN, 4, '<accessor source="#' + contid + -                        '-skin_weights-array" count="' + -                        str(skin_weights_total) + '" stride="1">') -            self.writel(S_SKIN, 5, '<param name="WEIGHT" type="float"/>') -            self.writel(S_SKIN, 4, '</accessor>') -            self.writel(S_SKIN, 4, '</technique_common>') -            self.writel(S_SKIN, 3, '</source>') - -            self.writel(S_SKIN, 3, '<joints>') -            self.writel( -                S_SKIN, 4, '<input semantic="JOINT" source="#' + contid + -                '-joints"/>') -            self.writel( -                S_SKIN, 4, '<input semantic="INV_BIND_MATRIX" source="#' + -                contid + '-bind_poses"/>') -            self.writel(S_SKIN, 3, '</joints>') -            self.writel(S_SKIN, 3, '<vertex_weights count="' + -                        str(len(vertices)) + '">') -            self.writel(S_SKIN, 4, '<input semantic="JOINT" source="#' + -                        contid + '-joints" offset="0"/>') -            self.writel(S_SKIN, 4, '<input semantic="WEIGHT" source="#' + -                        contid + '-skin_weights" offset="1"/>') -            vcounts = "" -            vs = "" -            vcount = 0 -            for v in vertices: -                vcounts += " " + str(len(v.weights)) -                for b in v.bones: -                    vs += " " + str(b) -                    vs += " " + str(vcount) -                    vcount += 1 -            self.writel(S_SKIN, 4, '<vcount>' + vcounts + '</vcount>') -            self.writel(S_SKIN, 4, '<v>' + vs + '</v>') -            self.writel(S_SKIN, 3, '</vertex_weights>') - -            self.writel(S_SKIN, 2, '</skin>') -            self.writel(S_SKIN, 1, '</controller>') -            meshdata["skin_id"] = contid - -        return meshdata - -    def export_mesh_node(self, node, il): -        if (node.data is None): -            return - -        armature = None -        armcount = 0 -        for n in node.modifiers: -            if (n.type == "ARMATURE"): -                armcount += 1 - -        if (node.parent is not None): -            if (node.parent.type == "ARMATURE"): -                armature = node.parent -                if (armcount > 1): -                    self.operator.report({'WARNING'}, 'Object "' + node.name + -                                         '" refers to more than one armature! ' -                                         'This is unsupported.') -                if (armcount == 0): -                    self.operator.report({'WARNING'}, 'Object "' + node.name + -                                         '" is child of an armature, but has ' -                                         'no armature modifier.') - -        if (armcount > 0 and not armature): -            self.operator.report({'WARNING'}, 'Object "' + node.name + -                                 '" has armature modifier, but is not a child ' -                                 'of an armature. This is unsupported.') - -        if (node.data.shape_keys is not None): -            sk = node.data.shape_keys -            if (sk.animation_data): -                    # print("HAS ANIM") -                    # print("DRIVERS: "+str(len(sk.animation_data.drivers))) -                for d in sk.animation_data.drivers: -                    if (d.driver): -                        for v in d.driver.variables: -                            for t in v.targets: -                                if (t.id is not None and -                                        t.id.name in self.scene.objects): -                                    # print("LINKING " + str(node) + " WITH " + -                                    #     str(t.id.name)) -                                    self.armature_for_morph[ -                                        node] = self.scene.objects[t.id.name] - -        meshdata = self.export_mesh(node, armature) -        close_controller = False - -        if ("skin_id" in meshdata): -            close_controller = True -            self.writel(S_NODES, il, '<instance_controller url="#' + -                        meshdata["skin_id"] + '">') -            for sn in self.skeleton_info[armature]["skeleton_nodes"]: -                self.writel(S_NODES, il + 1, '<skeleton>#' + -                            sn + '</skeleton>') -        elif ("morph_id" in meshdata): -            self.writel(S_NODES, il, '<instance_controller url="#' + -                        meshdata["morph_id"] + '">') -            close_controller = True -        elif (armature is None): -            self.writel(S_NODES, il, '<instance_geometry url="#' + -                        meshdata["id"] + '">') - -        if (len(meshdata["material_assign"]) > 0): - -            self.writel(S_NODES, il + 1, '<bind_material>') -            self.writel(S_NODES, il + 2, '<technique_common>') -            for m in meshdata["material_assign"]: -                self.writel(S_NODES, il + 3, '<instance_material symbol="' + -                            m[1] + '" target="#' + m[0] + '"/>') - -            self.writel(S_NODES, il + 2, '</technique_common>') -            self.writel(S_NODES, il + 1, '</bind_material>') - -        if (close_controller): -            self.writel(S_NODES, il, '</instance_controller>') -        else: -            self.writel(S_NODES, il, '</instance_geometry>') - -    def export_armature_bone(self, bone, il, si): -        boneid = self.new_id("bone") -        boneidx = si["bone_count"] -        si["bone_count"] += 1 -        bonesid = si["id"] + "-" + str(boneidx) -        if (bone.name in self.used_bones): -            if (self.config["use_anim_action_all"]): -                self.operator.report({'WARNING'}, 'Bone name "' + bone.name + -                                     '" used in more than one skeleton. ' -                                     'Actions might export wrong.') -        else: -            self.used_bones.append(bone.name) - -        si["bone_index"][bone.name] = boneidx -        si["bone_ids"][bone] = boneid -        si["bone_names"].append(bonesid) -        self.writel(S_NODES, il, '<node id="' + boneid + '" sid="' + -                    bonesid + '" name="' + bone.name + '" type="JOINT">') -        il += 1 -        xform = bone.matrix_local -        si["bone_bind_poses"].append((si["armature_xform"] * xform).inverted()) - -        if (bone.parent is not None): -            xform = bone.parent.matrix_local.inverted() * xform -        else: -            si["skeleton_nodes"].append(boneid) - -        self.writel(S_NODES, il, '<matrix sid="transform">' + -                    strmtx(xform) + '</matrix>') -        for c in bone.children: -            self.export_armature_bone(c, il, si) -        il -= 1 -        self.writel(S_NODES, il, '</node>') - -    def export_armature_node(self, node, il): -        if (node.data is None): -            return - -        self.skeletons.append(node) - -        armature = node.data -        self.skeleton_info[node] = { -            "bone_count": 0, -            "id": self.new_id("skelbones"), -            "name": node.name, "bone_index": {}, -            "bone_ids": {}, "bone_names": [], "bone_bind_poses": [], -            "skeleton_nodes": [], -            "armature_xform": node.matrix_world} - -        for b in armature.bones: -            if (b.parent is not None): -                continue -            self.export_armature_bone(b, il, self.skeleton_info[node]) - -        if (node.pose): -            for b in node.pose.bones: -                for x in b.constraints: -                    if (x.type == 'ACTION'): -                        self.action_constraints.append(x.action) - -    def export_camera_node(self, node, il): -        if (node.data is None): -            return - -        camera = node.data -        camid = self.new_id("camera") -        self.writel(S_CAMS, 1, '<camera id="' + camid + -                    '" name="' + camera.name + '">') -        self.writel(S_CAMS, 2, '<optics>') -        self.writel(S_CAMS, 3, '<technique_common>') -        if (camera.type == "PERSP"): -            self.writel(S_CAMS, 4, '<perspective>') -            self.writel(S_CAMS, 5, '<yfov> ' + -                        # I think? -                        str(math.degrees(camera.angle)) + ' </yfov>') -            self.writel(S_CAMS, 5, '<aspect_ratio> ' + -                        str(self.scene.render.resolution_x / -                            self.scene.render.resolution_y) + -                        ' </aspect_ratio>') -            self.writel(S_CAMS, 5, '<znear> ' + -                        str(camera.clip_start) + ' </znear>') -            self.writel(S_CAMS, 5, '<zfar> ' + -                        str(camera.clip_end) + ' </zfar>') -            self.writel(S_CAMS, 4, '</perspective>') -        else: -            self.writel(S_CAMS, 4, '<orthographic>') -            self.writel(S_CAMS, 5, '<xmag> ' + -                        str(camera.ortho_scale * 0.5) + ' </xmag>')  # I think? -            self.writel(S_CAMS, 5, '<aspect_ratio> ' + str( -                self.scene.render.resolution_x / -                self.scene.render.resolution_y) + ' </aspect_ratio>') -            self.writel(S_CAMS, 5, '<znear> ' + -                        str(camera.clip_start) + ' </znear>') -            self.writel(S_CAMS, 5, '<zfar> ' + -                        str(camera.clip_end) + ' </zfar>') -            self.writel(S_CAMS, 4, '</orthographic>') - -        self.writel(S_CAMS, 3, '</technique_common>') -        self.writel(S_CAMS, 2, '</optics>') -        self.writel(S_CAMS, 1, '</camera>') - -        self.writel(S_NODES, il, '<instance_camera url="#' + camid + '"/>') - -    def export_lamp_node(self, node, il): -        if (node.data is None): -            return - -        light = node.data -        lightid = self.new_id("light") -        self.writel(S_LAMPS, 1, '<light id="' + lightid + -                    '" name="' + light.name + '">') -        # self.writel(S_LAMPS, 2, '<optics>') -        self.writel(S_LAMPS, 3, '<technique_common>') - -        if (light.type == "POINT"): -            self.writel(S_LAMPS, 4, '<point>') -            self.writel(S_LAMPS, 5, '<color>' + -                        strarr(light.color) + '</color>') -            # convert to linear attenuation -            att_by_distance = 2.0 / light.distance -            self.writel(S_LAMPS, 5, '<linear_attenuation>' + -                        str(att_by_distance) + '</linear_attenuation>') -            if (light.use_sphere): -                self.writel(S_LAMPS, 5, '<zfar>' + -                            str(light.distance) + '</zfar>') - -            self.writel(S_LAMPS, 4, '</point>') -        elif (light.type == "SPOT"): -            self.writel(S_LAMPS, 4, '<spot>') -            self.writel(S_LAMPS, 5, '<color>' + -                        strarr(light.color) + '</color>') -            # convert to linear attenuation -            att_by_distance = 2.0 / light.distance -            self.writel(S_LAMPS, 5, '<linear_attenuation>' + -                        str(att_by_distance) + '</linear_attenuation>') -            self.writel(S_LAMPS, 5, '<falloff_angle>' + -                        str(math.degrees(light.spot_size / 2)) + -                        '</falloff_angle>') -            self.writel(S_LAMPS, 4, '</spot>') - -        else:  # write a sun lamp for everything else (not supported) -            self.writel(S_LAMPS, 4, '<directional>') -            self.writel(S_LAMPS, 5, '<color>' + -                        strarr(light.color) + '</color>') -            self.writel(S_LAMPS, 4, '</directional>') - -        self.writel(S_LAMPS, 3, '</technique_common>') -        # self.writel(S_LAMPS, 2, '</optics>') -        self.writel(S_LAMPS, 1, '</light>') - -        self.writel(S_NODES, il, '<instance_light url="#' + lightid + '"/>') - -    def export_empty_node(self, node, il): -        self.writel(S_NODES, 4, '<extra>') -        self.writel(S_NODES, 5, '<technique profile="GODOT">') -        self.writel(S_NODES, 6, '<empty_draw_type>' + -                    node.empty_draw_type + '</empty_draw_type>') -        self.writel(S_NODES, 5, '</technique>') -        self.writel(S_NODES, 4, '</extra>') - -    def export_curve(self, curve): -        splineid = self.new_id("spline") - -        self.writel(S_GEOM, 1, '<geometry id="' + -                    splineid + '" name="' + curve.name + '">') -        self.writel(S_GEOM, 2, '<spline closed="0">') - -        points = [] -        interps = [] -        handles_in = [] -        handles_out = [] -        tilts = [] - -        for cs in curve.splines: - -            if (cs.type == "BEZIER"): -                for s in cs.bezier_points: -                    points.append(s.co[0]) -                    points.append(s.co[1]) -                    points.append(s.co[2]) - -                    handles_in.append(s.handle_left[0]) -                    handles_in.append(s.handle_left[1]) -                    handles_in.append(s.handle_left[2]) - -                    handles_out.append(s.handle_right[0]) -                    handles_out.append(s.handle_right[1]) -                    handles_out.append(s.handle_right[2]) - -                    tilts.append(s.tilt) -                    interps.append("BEZIER") -            else: - -                for s in cs.points: -                    points.append(s.co[0]) -                    points.append(s.co[1]) -                    points.append(s.co[2]) -                    handles_in.append(s.co[0]) -                    handles_in.append(s.co[1]) -                    handles_in.append(s.co[2]) -                    handles_out.append(s.co[0]) -                    handles_out.append(s.co[1]) -                    handles_out.append(s.co[2]) -                    tilts.append(s.tilt) -                    interps.append("LINEAR") - -        self.writel(S_GEOM, 3, '<source id="' + splineid + '-positions">') -        position_values = "" -        for x in points: -            position_values += " " + str(x) -        self.writel(S_GEOM, 4, '<float_array id="' + splineid + -                    '-positions-array" count="' + -                    str(len(points)) + '">' + position_values + -                    '</float_array>') -        self.writel(S_GEOM, 4, '<technique_common>') -        self.writel(S_GEOM, 4, '<accessor source="#' + splineid + -                    '-positions-array" count="' + str(len(points) / 3) + -                    '" stride="3">') -        self.writel(S_GEOM, 5, '<param name="X" type="float"/>') -        self.writel(S_GEOM, 5, '<param name="Y" type="float"/>') -        self.writel(S_GEOM, 5, '<param name="Z" type="float"/>') -        self.writel(S_GEOM, 4, '</accessor>') -        self.writel(S_GEOM, 3, '</source>') - -        self.writel(S_GEOM, 3, '<source id="' + splineid + '-intangents">') -        intangent_values = "" -        for x in handles_in: -            intangent_values += " " + str(x) -        self.writel(S_GEOM, 4, '<float_array id="' + splineid + -                    '-intangents-array" count="' + -                    str(len(points)) + '">' + intangent_values + -                    '</float_array>') -        self.writel(S_GEOM, 4, '<technique_common>') -        self.writel(S_GEOM, 4, '<accessor source="#' + splineid + -                    '-intangents-array" count="' + str(len(points) / 3) + -                    '" stride="3">') -        self.writel(S_GEOM, 5, '<param name="X" type="float"/>') -        self.writel(S_GEOM, 5, '<param name="Y" type="float"/>') -        self.writel(S_GEOM, 5, '<param name="Z" type="float"/>') -        self.writel(S_GEOM, 4, '</accessor>') -        self.writel(S_GEOM, 3, '</source>') - -        self.writel(S_GEOM, 3, '<source id="' + splineid + '-outtangents">') -        outtangent_values = "" -        for x in handles_out: -            outtangent_values += " " + str(x) -        self.writel(S_GEOM, 4, '<float_array id="' + splineid + -                    '-outtangents-array" count="' + -                    str(len(points)) + '">' + outtangent_values + -                    '</float_array>') -        self.writel(S_GEOM, 4, '<technique_common>') -        self.writel(S_GEOM, 4, '<accessor source="#' + splineid + -                    '-outtangents-array" count="' + str(len(points) / 3) + -                    '" stride="3">') -        self.writel(S_GEOM, 5, '<param name="X" type="float"/>') -        self.writel(S_GEOM, 5, '<param name="Y" type="float"/>') -        self.writel(S_GEOM, 5, '<param name="Z" type="float"/>') -        self.writel(S_GEOM, 4, '</accessor>') -        self.writel(S_GEOM, 3, '</source>') - -        self.writel(S_GEOM, 3, '<source id="' + splineid + '-interpolations">') -        interpolation_values = "" -        for x in interps: -            interpolation_values += " " + x -        self.writel(S_GEOM, 4, '<Name_array id="' + splineid + -                    '-interpolations-array" count="' + -                    str(len(interps)) + '">' + interpolation_values + -                    '</Name_array>') -        self.writel(S_GEOM, 4, '<technique_common>') -        self.writel(S_GEOM, 4, '<accessor source="#' + splineid + -                    '-interpolations-array" count="' + str(len(interps)) + -                    '" stride="1">') -        self.writel(S_GEOM, 5, '<param name="INTERPOLATION" type="name"/>') -        self.writel(S_GEOM, 4, '</accessor>') -        self.writel(S_GEOM, 3, '</source>') - -        self.writel(S_GEOM, 3, '<source id="' + splineid + '-tilts">') -        tilt_values = "" -        for x in tilts: -            tilt_values += " " + str(x) -        self.writel(S_GEOM, 4, '<float_array id="' + splineid + -                    '-tilts-array" count="' + -                    str(len(tilts)) + '">' + tilt_values + '</float_array>') -        self.writel(S_GEOM, 4, '<technique_common>') -        self.writel(S_GEOM, 4, '<accessor source="#' + splineid + -                    '-tilts-array" count="' + str(len(tilts)) + -                    '" stride="1">') -        self.writel(S_GEOM, 5, '<param name="TILT" type="float"/>') -        self.writel(S_GEOM, 4, '</accessor>') -        self.writel(S_GEOM, 3, '</source>') - -        self.writel(S_GEOM, 3, '<control_vertices>') -        self.writel( -            S_GEOM, 4, '<input semantic="POSITION" source="#' + splineid + -            '-positions"/>') -        self.writel(S_GEOM, 4, '<input semantic="IN_TANGENT" source="#' + -                    splineid + '-intangents"/>') -        self.writel(S_GEOM, 4, '<input semantic="OUT_TANGENT" source="#' + -                    splineid + '-outtangents"/>') -        self.writel(S_GEOM, 4, '<input semantic="INTERPOLATION" source="#' + -                    splineid + '-interpolations"/>') -        self.writel(S_GEOM, 4, '<input semantic="TILT" source="#' + -                    splineid + '-tilts"/>') -        self.writel(S_GEOM, 3, '</control_vertices>') - -        self.writel(S_GEOM, 2, '</spline>') -        self.writel(S_GEOM, 1, '</geometry>') - -        return splineid - -    def export_curve_node(self, node, il): -        if (node.data is None): -            return - -        curveid = self.export_curve(node.data) - -        self.writel(S_NODES, il, '<instance_geometry url="#' + curveid + '">') -        self.writel(S_NODES, il, '</instance_geometry>') - -    def export_node(self, node, il): -        if (node not in self.valid_nodes): -            return - -        prev_node = bpy.context.scene.objects.active -        bpy.context.scene.objects.active = node - -        self.writel(S_NODES, il, '<node id="' + self.validate_id(node.name) + -                    '" name="' + node.name + '" type="NODE">') -        il += 1 - -        self.writel(S_NODES, il, '<matrix sid="transform">' + -                    strmtx(node.matrix_local) + '</matrix>') -        # print("NODE TYPE: "+node.type+" NAME: "+node.name) -        if (node.type == "MESH"): -            self.export_mesh_node(node, il) -        elif (node.type == "CURVE"): -            self.export_curve_node(node, il) -        elif (node.type == "ARMATURE"): -            self.export_armature_node(node, il) -        elif (node.type == "CAMERA"): -            self.export_camera_node(node, il) -        elif (node.type == "LAMP"): -            self.export_lamp_node(node, il) -        elif (node.type == "EMPTY"): -            self.export_empty_node(node, il) - -        for x in node.children: -            self.export_node(x, il) - -        il -= 1 -        self.writel(S_NODES, il, '</node>') -        # make previous node active again -        bpy.context.scene.objects.active = prev_node - -    def is_node_valid(self, node): -        if (node.type not in self.config["object_types"]): -            return False - -        if (self.config["use_active_layers"]): -            valid = False -            # print("NAME: "+node.name) -            for i in range(20): -                if (node.layers[i] and self.scene.layers[i]): -                    valid = True -                    break -            if (not valid): -                return False - -        if (self.config["use_export_selected"] and not node.select): -            return False - -        return True - -    def export_scene(self): -        self.writel(S_NODES, 0, '<library_visual_scenes>') -        self.writel(S_NODES, 1, '<visual_scene id="' + -                    self.scene_name + '" name="scene">') - -        # validate nodes -        for obj in self.scene.objects: -            if (obj in self.valid_nodes): -                continue -            if (self.is_node_valid(obj)): -                n = obj -                while (n is not None): -                    if (n not in self.valid_nodes): -                        self.valid_nodes.append(n) -                    n = n.parent - -        for obj in self.scene.objects: -            if (obj in self.valid_nodes and obj.parent is None): -                self.export_node(obj, 2) - -        self.writel(S_NODES, 1, '</visual_scene>') -        self.writel(S_NODES, 0, '</library_visual_scenes>') - -    def export_asset(self): -        self.writel(S_ASSET, 0, '<asset>') -        # Why is this time stuff mandatory?, no one could care less... -        self.writel(S_ASSET, 1, '<contributor>') -        # Who made Collada, the FBI ? -        self.writel(S_ASSET, 2, '<author> Anonymous </author>') -        # Who made Collada, the FBI ? -        self.writel( -            S_ASSET, 2, '<authoring_tool> Collada Exporter for Blender 2.6+, ' -            'by Juan Linietsky (juan@codenix.com) </authoring_tool>') -        self.writel(S_ASSET, 1, '</contributor>') -        self.writel(S_ASSET, 1, '<created>' + -                    time.strftime("%Y-%m-%dT%H:%M:%SZ     ") + '</created>') -        self.writel(S_ASSET, 1, '<modified>' + -                    time.strftime("%Y-%m-%dT%H:%M:%SZ") + '</modified>') -        self.writel(S_ASSET, 1, '<unit meter="1.0" name="meter"/>') -        self.writel(S_ASSET, 1, '<up_axis>Z_UP</up_axis>') -        self.writel(S_ASSET, 0, '</asset>') - -    def export_animation_transform_channel(self, target, keys, matrices=True): -        frame_total = len(keys) -        anim_id = self.new_id("anim") -        self.writel(S_ANIM, 1, '<animation id="' + anim_id + '">') -        source_frames = "" -        source_transforms = "" -        source_interps = "" - -        for k in keys: -            source_frames += " " + str(k[0]) -            if (matrices): -                source_transforms += " " + strmtx(k[1]) -            else: -                source_transforms += " " + str(k[1]) - -            source_interps += " LINEAR" - -        # Time Source -        self.writel(S_ANIM, 2, '<source id="' + anim_id + '-input">') -        self.writel(S_ANIM, 3, '<float_array id="' + anim_id + -                    '-input-array" count="' + -                    str(frame_total) + '">' + source_frames + '</float_array>') -        self.writel(S_ANIM, 3, '<technique_common>') -        self.writel(S_ANIM, 4, '<accessor source="#' + anim_id + -                    '-input-array" count="' + str(frame_total) + -                    '" stride="1">') -        self.writel(S_ANIM, 5, '<param name="TIME" type="float"/>') -        self.writel(S_ANIM, 4, '</accessor>') -        self.writel(S_ANIM, 3, '</technique_common>') -        self.writel(S_ANIM, 2, '</source>') - -        if (matrices): -            # Transform Source -            self.writel(S_ANIM, 2, '<source id="' + -                        anim_id + '-transform-output">') -            self.writel(S_ANIM, 3, '<float_array id="' + anim_id + -                        '-transform-output-array" count="' + -                        str(frame_total * 16) + '">' + source_transforms + -                        '</float_array>') -            self.writel(S_ANIM, 3, '<technique_common>') -            self.writel(S_ANIM, 4, '<accessor source="#' + anim_id + -                        '-transform-output-array" count="' + str(frame_total) + -                        '" stride="16">') -            self.writel(S_ANIM, 5, '<param name="TRANSFORM" type="float4x4"/>') -            self.writel(S_ANIM, 4, '</accessor>') -            self.writel(S_ANIM, 3, '</technique_common>') -            self.writel(S_ANIM, 2, '</source>') -        else: -            # Value Source -            self.writel(S_ANIM, 2, '<source id="' + -                        anim_id + '-transform-output">') -            self.writel(S_ANIM, 3, '<float_array id="' + anim_id + -                        '-transform-output-array" count="' + -                        str(frame_total) + '">' + source_transforms + -                        '</float_array>') -            self.writel(S_ANIM, 3, '<technique_common>') -            self.writel(S_ANIM, 4, '<accessor source="#' + anim_id + -                        '-transform-output-array" count="' + str(frame_total) + -                        '" stride="1">') -            self.writel(S_ANIM, 5, '<param name="X" type="float"/>') -            self.writel(S_ANIM, 4, '</accessor>') -            self.writel(S_ANIM, 3, '</technique_common>') -            self.writel(S_ANIM, 2, '</source>') - -        # Interpolation Source -        self.writel(S_ANIM, 2, '<source id="' + -                    anim_id + '-interpolation-output">') -        self.writel(S_ANIM, 3, '<Name_array id="' + anim_id + -                    '-interpolation-output-array" count="' + -                    str(frame_total) + '">' + source_interps + '</Name_array>') -        self.writel(S_ANIM, 3, '<technique_common>') -        self.writel(S_ANIM, 4, '<accessor source="#' + anim_id + -                    '-interpolation-output-array" count="' + str(frame_total) + -                    '" stride="1">') -        self.writel(S_ANIM, 5, '<param name="INTERPOLATION" type="Name"/>') -        self.writel(S_ANIM, 4, '</accessor>') -        self.writel(S_ANIM, 3, '</technique_common>') -        self.writel(S_ANIM, 2, '</source>') - -        self.writel(S_ANIM, 2, '<sampler id="' + anim_id + '-sampler">') -        self.writel(S_ANIM, 3, '<input semantic="INPUT" source="#' + -                    anim_id + '-input"/>') -        self.writel(S_ANIM, 3, '<input semantic="OUTPUT" source="#' + -                    anim_id + '-transform-output"/>') -        self.writel(S_ANIM, 3, '<input semantic="INTERPOLATION" source="#' + -                    anim_id + '-interpolation-output"/>') -        self.writel(S_ANIM, 2, '</sampler>') -        if (matrices): -            self.writel(S_ANIM, 2, '<channel source="#' + anim_id + -                        '-sampler" target="' + target + '/transform"/>') -        else: -            self.writel(S_ANIM, 2, '<channel source="#' + -                        anim_id + '-sampler" target="' + target + '"/>') -        self.writel(S_ANIM, 1, '</animation>') - -        return [anim_id] - -    def export_animation(self, start, end, allowed=None): -        # Blender -> Collada frames needs a little work -        # Collada starts from 0, blender usually from 1 -        # The last frame must be included also - -        frame_orig = self.scene.frame_current - -        frame_len = 1.0 / self.scene.render.fps -        frame_total = end - start + 1 -        frame_sub = 0 -        if (start > 0): -            frame_sub = start * frame_len - -        tcn = [] -        xform_cache = {} -        blend_cache = {} -        # Change frames first, export objects last -        # This improves performance enormously - -        # print("anim from: " + str(start) + " to " + str(end) + " allowed: " + -        #     str(allowed)) -        for t in range(start, end + 1): -            self.scene.frame_set(t) -            key = t * frame_len - frame_sub -#            print("Export Anim Frame "+str(t)+"/"+str(self.scene.frame_end+1)) - -            for node in self.scene.objects: - -                if (node not in self.valid_nodes): -                    continue -                if (allowed is not None and not (node in allowed)): -                    if (node.type == "MESH" and node.data is not None and -                        (node in self.armature_for_morph) and ( -                            self.armature_for_morph[node] in allowed)): -                        # all good you pass with flying colors for morphs -                        # inside of action -                        pass -                    else: -                        # print("fail "+str((node in self.armature_for_morph))) -                        continue -                if (node.type == "MESH" and node.data is not None and -                    node.data.shape_keys is not None and ( -                        node.data in self.mesh_cache) and len( -                            node.data.shape_keys.key_blocks)): -                    target = self.mesh_cache[node.data]["morph_id"] -                    for i in range(len(node.data.shape_keys.key_blocks)): - -                        if (i == 0): -                            continue - -                        name = target + "-morph-weights(" + str(i - 1) + ")" -                        if (not (name in blend_cache)): -                            blend_cache[name] = [] - -                        blend_cache[name].append( -                            (key, node.data.shape_keys.key_blocks[i].value)) - -                if (node.type == "MESH" and node.parent and -                        node.parent.type == "ARMATURE"): - -                    # In Collada, nodes that have skin modifier must not export -                    # animation, animate the skin instead. -                    continue - -                if (len(node.constraints) > 0 or -                        node.animation_data is not None): -                    # If the node has constraints, or animation data, then -                    # export a sampled animation track -                    name = self.validate_id(node.name) -                    if (not (name in xform_cache)): -                        xform_cache[name] = [] - -                    mtx = node.matrix_world.copy() -                    if (node.parent): -                        mtx = node.parent.matrix_world.inverted() * mtx - -                    xform_cache[name].append((key, mtx)) - -                if (node.type == "ARMATURE"): -                    # All bones exported for now - -                    for bone in node.data.bones: - -                        bone_name = self.skeleton_info[node]["bone_ids"][bone] - -                        if (not (bone_name in xform_cache)): -                            # print("has bone: " + bone_name) -                            xform_cache[bone_name] = [] - -                        posebone = node.pose.bones[bone.name] -                        parent_posebone = None - -                        mtx = posebone.matrix.copy() -                        if (bone.parent): -                            parent_posebone = node.pose.bones[bone.parent.name] -                            parent_invisible = False - -                            for i in range(3): -                                if (parent_posebone.scale[i] == 0.0): -                                    parent_invisible = True - -                            if (not parent_invisible): -                                mtx = parent_posebone.matrix.inverted() * mtx - -                        xform_cache[bone_name].append((key, mtx)) - -        self.scene.frame_set(frame_orig) - -        # export animation xml -        for nid in xform_cache: -            tcn += self.export_animation_transform_channel( -                nid, xform_cache[nid], True) -        for nid in blend_cache: -            tcn += self.export_animation_transform_channel( -                nid, blend_cache[nid], False) - -        return tcn - -    def export_animations(self): -        tmp_mat = [] -        for s in self.skeletons: -            tmp_bone_mat = [] -            for bone in s.pose.bones: -                tmp_bone_mat.append(Matrix(bone.matrix_basis)) -                bone.matrix_basis = Matrix() -            tmp_mat.append([Matrix(s.matrix_local), tmp_bone_mat]) - -        self.writel(S_ANIM, 0, '<library_animations>') - -        if (self.config["use_anim_action_all"] and len(self.skeletons)): - -            cached_actions = {} - -            for s in self.skeletons: -                if s.animation_data and s.animation_data.action: -                    cached_actions[s] = s.animation_data.action.name - -            self.writel(S_ANIM_CLIPS, 0, '<library_animation_clips>') - -            for x in bpy.data.actions[:]: -                if x.users == 0 or x in self.action_constraints: -                    continue -                if (self.config["use_anim_skip_noexp"] and -                        x.name.endswith("-noexp")): -                    continue - -                bones = [] -                # find bones used -                for p in x.fcurves: -                    dp = str(p.data_path) -                    base = "pose.bones[\"" -                    if (dp.find(base) == 0): -                        dp = dp[len(base):] -                        if (dp.find('"') != -1): -                            dp = dp[:dp.find('"')] -                            if (dp not in bones): -                                bones.append(dp) - -                allowed_skeletons = [] -                for i, y in enumerate(self.skeletons): -                    if (y.animation_data): -                        for z in y.pose.bones: -                            if (z.bone.name in bones): -                                if (y not in allowed_skeletons): -                                    allowed_skeletons.append(y) -                        y.animation_data.action = x - -                        y.matrix_local = tmp_mat[i][0] -                        for j, bone in enumerate(s.pose.bones): -                            bone.matrix_basis = Matrix() - -                # print("allowed skeletons "+str(allowed_skeletons)) - -                # print(str(x)) - -                tcn = self.export_animation(int(x.frame_range[0]), int( -                    x.frame_range[1] + 0.5), allowed_skeletons) -                framelen = (1.0 / self.scene.render.fps) -                start = x.frame_range[0] * framelen -                end = x.frame_range[1] * framelen -                # print("Export anim: "+x.name) -                self.writel( -                    S_ANIM_CLIPS, 1, '<animation_clip name="' + x.name + -                    '" start="' + str(start) + '" end="' + str(end) + '">') -                for z in tcn: -                    self.writel(S_ANIM_CLIPS, 2, -                                '<instance_animation url="#' + z + '"/>') -                self.writel(S_ANIM_CLIPS, 1, '</animation_clip>') -                if (len(tcn) == 0): -                    self.operator.report( -                        {'WARNING'}, 'Animation clip "' + x.name + -                        '" contains no tracks.') - -            self.writel(S_ANIM_CLIPS, 0, '</library_animation_clips>') - -            for i, s in enumerate(self.skeletons): -                if (s.animation_data is None): -                    continue -                if s in cached_actions: -                    s.animation_data.action = bpy.data.actions[ -                        cached_actions[s]] -                else: -                    s.animation_data.action = None -                    for j, bone in enumerate(s.pose.bones): -                        bone.matrix_basis = tmp_mat[i][1][j] - -        else: -            self.export_animation(self.scene.frame_start, self.scene.frame_end) - -        self.writel(S_ANIM, 0, '</library_animations>') - -    def export(self): -        self.writel(S_GEOM, 0, '<library_geometries>') -        self.writel(S_CONT, 0, '<library_controllers>') -        self.writel(S_CAMS, 0, '<library_cameras>') -        self.writel(S_LAMPS, 0, '<library_lights>') -        self.writel(S_IMGS, 0, '<library_images>') -        self.writel(S_MATS, 0, '<library_materials>') -        self.writel(S_FX, 0, '<library_effects>') - -        self.skeletons = [] -        self.action_constraints = [] -        self.export_asset() -        self.export_scene() - -        self.writel(S_GEOM, 0, '</library_geometries>') - -        # morphs always go before skin controllers -        if S_MORPH in self.sections: -            for l in self.sections[S_MORPH]: -                self.writel(S_CONT, 0, l) -            del self.sections[S_MORPH] - -        # morphs always go before skin controllers -        if S_SKIN in self.sections: -            for l in self.sections[S_SKIN]: -                self.writel(S_CONT, 0, l) -            del self.sections[S_SKIN] - -        self.writel(S_CONT, 0, '</library_controllers>') -        self.writel(S_CAMS, 0, '</library_cameras>') -        self.writel(S_LAMPS, 0, '</library_lights>') -        self.writel(S_IMGS, 0, '</library_images>') -        self.writel(S_MATS, 0, '</library_materials>') -        self.writel(S_FX, 0, '</library_effects>') - -        if (self.config["use_anim"]): -            self.export_animations() - -        try: -            f = open(self.path, "wb") -        except: -            return False - -        f.write(bytes('<?xml version="1.0" encoding="utf-8"?>\n', "UTF-8")) -        f.write(bytes( -            '<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" ' -            'version="1.4.1">\n', "UTF-8")) - -        s = [] -        for x in self.sections.keys(): -            s.append(x) -        s.sort() -        for x in s: -            for l in self.sections[x]: -                f.write(bytes(l + "\n", "UTF-8")) - -        f.write(bytes('<scene>\n', "UTF-8")) -        f.write(bytes('\t<instance_visual_scene url="#' + -                      self.scene_name + '" />\n', "UTF-8")) -        f.write(bytes('</scene>\n', "UTF-8")) -        f.write(bytes('</COLLADA>\n', "UTF-8")) -        return True - -    def __init__(self, path, kwargs, operator): -        self.operator = operator -        self.scene = bpy.context.scene -        self.last_id = 0 -        self.scene_name = self.new_id("scene") -        self.sections = {} -        self.path = path -        self.mesh_cache = {} -        self.curve_cache = {} -        self.material_cache = {} -        self.image_cache = {} -        self.skeleton_info = {} -        self.config = kwargs -        self.valid_nodes = [] -        self.armature_for_morph = {} -        self.used_bones = [] -        self.wrongvtx_report = False - - -def save(operator, context, filepath="", use_selection=False, **kwargs): -    exp = DaeExporter(filepath, kwargs, operator) -    exp.export() - -    return {'FINISHED'}  # so the script wont run after we have batch exported.  |