summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/editor/editor_file_dialog.cpp874
-rw-r--r--tools/editor/editor_file_dialog.h198
-rw-r--r--tools/editor/editor_node.cpp153
-rw-r--r--tools/editor/editor_node.h12
-rw-r--r--tools/editor/editor_resource_preview.cpp260
-rw-r--r--tools/editor/editor_resource_preview.h95
-rw-r--r--tools/editor/editor_settings.cpp2
-rw-r--r--tools/editor/icons/icon_wait_no_preview.pngbin0 -> 1041 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_1.pngbin0 -> 1208 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_2.pngbin0 -> 1270 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_3.pngbin0 -> 1190 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_4.pngbin0 -> 1269 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_5.pngbin0 -> 1191 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_6.pngbin0 -> 1278 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_7.pngbin0 -> 1192 bytes
-rw-r--r--tools/editor/icons/icon_wait_preview_8.pngbin0 -> 1341 bytes
-rw-r--r--tools/editor/plugins/editor_preview_plugins.cpp664
-rw-r--r--tools/editor/plugins/editor_preview_plugins.h69
-rw-r--r--tools/editor/plugins/sample_editor_plugin.cpp119
-rw-r--r--tools/editor/plugins/spatial_editor_plugin.h8
-rw-r--r--tools/editor/resources_dock.cpp4
-rw-r--r--tools/editor/resources_dock.h3
22 files changed, 2444 insertions, 17 deletions
diff --git a/tools/editor/editor_file_dialog.cpp b/tools/editor/editor_file_dialog.cpp
new file mode 100644
index 0000000000..359f807ae4
--- /dev/null
+++ b/tools/editor/editor_file_dialog.cpp
@@ -0,0 +1,874 @@
+#include "editor_file_dialog.h"
+#include "scene/gui/label.h"
+#include "scene/gui/center_container.h"
+#include "print_string.h"
+#include "os/keyboard.h"
+#include "editor_resource_preview.h"
+
+
+EditorFileDialog::GetIconFunc EditorFileDialog::get_icon_func=NULL;
+EditorFileDialog::GetIconFunc EditorFileDialog::get_large_icon_func=NULL;
+
+EditorFileDialog::RegisterFunc EditorFileDialog::register_func=NULL;
+EditorFileDialog::RegisterFunc EditorFileDialog::unregister_func=NULL;
+
+
+VBoxContainer *EditorFileDialog::get_vbox() {
+ return vbox;
+
+}
+
+void EditorFileDialog::_notification(int p_what) {
+ if (p_what==NOTIFICATION_PROCESS) {
+
+ if (preview_waiting) {
+ preview_wheel_timeout-=get_process_delta_time();
+ if (preview_wheel_timeout<=0) {
+ preview_wheel_index++;
+ if (preview_wheel_index>=8)
+ preview_wheel_index=0;
+ Ref<Texture> frame = get_icon("WaitPreview"+itos(preview_wheel_index+1),"EditorIcons");
+ preview->set_texture(frame);
+ preview_wheel_timeout=0.1;
+ }
+ }
+ }
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ //RID ci = get_canvas_item();
+ //get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size()));
+ }
+}
+
+void EditorFileDialog::set_enable_multiple_selection(bool p_enable) {
+
+ tree->set_select_mode(p_enable?Tree::SELECT_MULTI : Tree::SELECT_SINGLE);
+};
+
+Vector<String> EditorFileDialog::get_selected_files() const {
+
+ Vector<String> list;
+
+ TreeItem* item = tree->get_root();
+ while ( (item = tree->get_next_selected(item)) ) {
+
+ list.push_back(dir_access->get_current_dir().plus_file(item->get_text(0)));
+ };
+
+ return list;
+};
+
+void EditorFileDialog::update_dir() {
+
+ dir->set_text(dir_access->get_current_dir());
+}
+
+void EditorFileDialog::_dir_entered(String p_dir) {
+
+
+ dir_access->change_dir(p_dir);
+ file->set_text("");
+ invalidate();
+ update_dir();
+}
+
+void EditorFileDialog::_file_entered(const String& p_file) {
+
+ _action_pressed();
+}
+
+void EditorFileDialog::_save_confirm_pressed() {
+ String f=dir_access->get_current_dir().plus_file(file->get_text());
+ emit_signal("file_selected",f);
+ hide();
+}
+
+void EditorFileDialog::_post_popup() {
+
+ ConfirmationDialog::_post_popup();
+ if (invalidated) {
+ update_file_list();
+ invalidated=false;
+ }
+ if (mode==MODE_SAVE_FILE)
+ file->grab_focus();
+ else
+ tree->grab_focus();
+
+ if (is_visible() && get_current_file()!="")
+ _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+
+}
+
+void EditorFileDialog::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) {
+
+ set_process(false);
+ preview_waiting=false;
+
+ if (p_preview.is_valid() && get_current_path()==p_path) {
+
+ preview->set_texture(p_preview);
+ preview_vb->show();
+
+ } else {
+ preview_vb->hide();
+ preview->set_texture(Ref<Texture>());
+
+ }
+
+}
+
+void EditorFileDialog::_request_single_thumbnail(const String& p_path) {
+
+ EditorResourcePreview::get_singleton()->queue_resource_preview(p_path,this,"_thumbnail_done",p_path);
+ print_line("want file "+p_path);
+ set_process(true);
+ preview_waiting=true;
+ preview_wheel_timeout=0;
+
+}
+
+void EditorFileDialog::_action_pressed() {
+
+ if (mode==MODE_OPEN_FILES) {
+
+ TreeItem *ti=tree->get_next_selected(NULL);
+ String fbase=dir_access->get_current_dir();
+
+ DVector<String> files;
+ while(ti) {
+
+ files.push_back( fbase.plus_file(ti->get_text(0)) );
+ ti=tree->get_next_selected(ti);
+ }
+
+ if (files.size()) {
+ emit_signal("files_selected",files);
+ hide();
+ }
+
+ return;
+ }
+
+ String f=dir_access->get_current_dir().plus_file(file->get_text());
+
+ if (mode==MODE_OPEN_FILE && dir_access->file_exists(f)) {
+ emit_signal("file_selected",f);
+ hide();
+ }
+
+ if (mode==MODE_OPEN_DIR) {
+
+
+ String path=dir_access->get_current_dir();
+ /*if (tree->get_selected()) {
+ Dictionary d = tree->get_selected()->get_metadata(0);
+ if (d["dir"]) {
+ path=path+"/"+String(d["name"]);
+ }
+ }*/
+ path=path.replace("\\","/");
+ emit_signal("dir_selected",path);
+ hide();
+ }
+
+ if (mode==MODE_SAVE_FILE) {
+
+ bool valid=false;
+
+ if (filter->get_selected()==filter->get_item_count()-1) {
+ valid=true; //match none
+ } else if (filters.size()>1 && filter->get_selected()==0) {
+ // match all filters
+ for (int i=0;i<filters.size();i++) {
+
+ String flt=filters[i].get_slice(";",0);
+ for (int j=0;j<flt.get_slice_count(",");j++) {
+
+ String str = flt.get_slice(",",j).strip_edges();
+ if (f.match(str)) {
+ valid=true;
+ break;
+ }
+ }
+ if (valid)
+ break;
+ }
+ } else {
+ int idx=filter->get_selected();
+ if (filters.size()>1)
+ idx--;
+ if (idx>=0 && idx<filters.size()) {
+
+ String flt=filters[idx].get_slice(";",0);
+ int filterSliceCount=flt.get_slice_count(",");
+ for (int j=0;j<filterSliceCount;j++) {
+
+ String str = (flt.get_slice(",",j).strip_edges());
+ if (f.match(str)) {
+ valid=true;
+ break;
+ }
+ }
+
+ if (!valid && filterSliceCount>0) {
+ String str = (flt.get_slice(",",0).strip_edges());
+ f+=str.substr(1, str.length()-1);
+ _request_single_thumbnail(get_current_dir().plus_file(f.get_file()));
+ file->set_text(f.get_file());
+ valid=true;
+ }
+ } else {
+ valid=true;
+ }
+ }
+
+
+ if (!valid) {
+
+ exterr->popup_centered_minsize(Size2(250,80));
+ return;
+
+ }
+
+ if (dir_access->file_exists(f)) {
+ confirm_save->set_text("File Exists, Overwrite?");
+ confirm_save->popup_centered(Size2(200,80));
+ } else {
+
+
+ emit_signal("file_selected",f);
+ hide();
+ }
+ }
+}
+
+void EditorFileDialog::_cancel_pressed() {
+
+ file->set_text("");
+ invalidate();
+ hide();
+}
+
+void EditorFileDialog::_tree_selected() {
+
+ TreeItem *ti=tree->get_selected();
+ if (!ti)
+ return;
+ Dictionary d=ti->get_metadata(0);
+
+ if (!d["dir"]) {
+
+ file->set_text(d["name"]);
+ _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ }
+}
+
+void EditorFileDialog::_tree_dc_selected() {
+
+
+ TreeItem *ti=tree->get_selected();
+ if (!ti)
+ return;
+
+ Dictionary d=ti->get_metadata(0);
+
+ if (d["dir"]) {
+
+ dir_access->change_dir(d["name"]);
+ if (mode==MODE_OPEN_FILE || mode==MODE_OPEN_FILES || mode==MODE_OPEN_DIR)
+ file->set_text("");
+ call_deferred("_update_file_list");
+ call_deferred("_update_dir");
+ } else {
+
+ _action_pressed();
+ }
+}
+
+void EditorFileDialog::update_file_list() {
+
+ tree->clear();
+ dir_access->list_dir_begin();
+
+ TreeItem *root = tree->create_item();
+ Ref<Texture> folder = get_icon("folder","FileDialog");
+ List<String> files;
+ List<String> dirs;
+
+ bool isdir;
+ bool ishidden;
+ bool show_hidden = show_hidden_files;
+ String item;
+
+ while ((item=dir_access->get_next(&isdir))!="") {
+
+ ishidden = dir_access->current_is_hidden();
+
+ if (show_hidden || !ishidden) {
+ if (!isdir)
+ files.push_back(item);
+ else
+ dirs.push_back(item);
+ }
+ }
+
+ dirs.sort_custom<NoCaseComparator>();
+ files.sort_custom<NoCaseComparator>();
+
+ while(!dirs.empty()) {
+
+ if (dirs.front()->get()!=".") {
+ TreeItem *ti=tree->create_item(root);
+ ti->set_text(0,dirs.front()->get()+"/");
+ ti->set_icon(0,folder);
+ Dictionary d;
+ d["name"]=dirs.front()->get();
+ d["dir"]=true;
+ ti->set_metadata(0,d);
+ }
+ dirs.pop_front();
+
+ }
+
+ dirs.clear();
+
+ List<String> patterns;
+ // build filter
+ if (filter->get_selected()==filter->get_item_count()-1) {
+
+ // match all
+ } else if (filters.size()>1 && filter->get_selected()==0) {
+ // match all filters
+ for (int i=0;i<filters.size();i++) {
+
+ String f=filters[i].get_slice(";",0);
+ for (int j=0;j<f.get_slice_count(",");j++) {
+
+ patterns.push_back(f.get_slice(",",j).strip_edges());
+ }
+ }
+ } else {
+ int idx=filter->get_selected();
+ if (filters.size()>1)
+ idx--;
+
+ if (idx>=0 && idx<filters.size()) {
+
+ String f=filters[idx].get_slice(";",0);
+ for (int j=0;j<f.get_slice_count(",");j++) {
+
+ patterns.push_back(f.get_slice(",",j).strip_edges());
+ }
+ }
+ }
+
+
+ String base_dir = dir_access->get_current_dir();
+
+
+ while(!files.empty()) {
+
+ bool match=patterns.empty();
+
+ for(List<String>::Element *E=patterns.front();E;E=E->next()) {
+
+ if (files.front()->get().matchn(E->get())) {
+
+ match=true;
+ break;
+ }
+ }
+
+ if (match) {
+ TreeItem *ti=tree->create_item(root);
+ ti->set_text(0,files.front()->get());
+
+ if (get_icon_func) {
+
+ Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get()));
+ ti->set_icon(0,icon);
+ }
+
+ if (mode==MODE_OPEN_DIR) {
+ ti->set_custom_color(0,get_color("files_disabled"));
+ ti->set_selectable(0,false);
+ }
+ Dictionary d;
+ d["name"]=files.front()->get();
+ d["dir"]=false;
+ ti->set_metadata(0,d);
+
+ if (file->get_text()==files.front()->get())
+ ti->select(0);
+ }
+
+ files.pop_front();
+ }
+
+ if (tree->get_root() && tree->get_root()->get_children())
+ tree->get_root()->get_children()->select(0);
+
+ files.clear();
+
+}
+
+void EditorFileDialog::_filter_selected(int) {
+
+ update_file_list();
+}
+
+void EditorFileDialog::update_filters() {
+
+ filter->clear();
+
+ if (filters.size()>1) {
+ String all_filters;
+
+ const int max_filters=5;
+
+ for(int i=0;i<MIN( max_filters, filters.size()) ;i++) {
+ String flt=filters[i].get_slice(";",0);
+ if (i>0)
+ all_filters+=",";
+ all_filters+=flt;
+ }
+
+ if (max_filters<filters.size())
+ all_filters+=", ...";
+
+ filter->add_item("All Recognized ( "+all_filters+" )");
+ }
+ for(int i=0;i<filters.size();i++) {
+
+ String flt=filters[i].get_slice(";",0).strip_edges();
+ String desc=filters[i].get_slice(";",1).strip_edges();
+ if (desc.length())
+ filter->add_item(desc+" ( "+flt+" )");
+ else
+ filter->add_item("( "+flt+" )");
+ }
+
+ filter->add_item("All Files (*)");
+
+}
+
+void EditorFileDialog::clear_filters() {
+
+ filters.clear();
+ update_filters();
+ invalidate();
+}
+void EditorFileDialog::add_filter(const String& p_filter) {
+
+ filters.push_back(p_filter);
+ update_filters();
+ invalidate();
+
+}
+
+String EditorFileDialog::get_current_dir() const {
+
+ return dir->get_text();
+}
+String EditorFileDialog::get_current_file() const {
+
+ return file->get_text();
+}
+String EditorFileDialog::get_current_path() const {
+
+ return dir->get_text().plus_file(file->get_text());
+}
+void EditorFileDialog::set_current_dir(const String& p_dir) {
+
+ dir_access->change_dir(p_dir);
+ update_dir();
+ invalidate();
+
+}
+void EditorFileDialog::set_current_file(const String& p_file) {
+
+ file->set_text(p_file);
+ update_dir();
+ invalidate();
+ int lp = p_file.find_last(".");
+ if (lp!=-1) {
+ file->select(0,lp);
+ file->grab_focus();
+ }
+
+ if (is_visible())
+ _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+
+
+}
+void EditorFileDialog::set_current_path(const String& p_path) {
+
+ if (!p_path.size())
+ return;
+ int pos=MAX( p_path.find_last("/"), p_path.find_last("\\") );
+ if (pos==-1) {
+
+ set_current_file(p_path);
+ } else {
+
+ String dir=p_path.substr(0,pos);
+ String file=p_path.substr(pos+1,p_path.length());
+ set_current_dir(dir);
+ set_current_file(file);
+ }
+}
+
+
+void EditorFileDialog::set_mode(Mode p_mode) {
+
+ mode=p_mode;
+ switch(mode) {
+
+ case MODE_OPEN_FILE: get_ok()->set_text("Open"); set_title("Open a File"); makedir->hide(); break;
+ case MODE_OPEN_FILES: get_ok()->set_text("Open"); set_title("Open File(s)"); makedir->hide(); break;
+ case MODE_SAVE_FILE: get_ok()->set_text("Save"); set_title("Save a File"); makedir->show(); break;
+ case MODE_OPEN_DIR: get_ok()->set_text("Open"); set_title("Open a Directory"); makedir->show(); break;
+ }
+
+ if (mode==MODE_OPEN_FILES) {
+ tree->set_select_mode(Tree::SELECT_MULTI);
+ } else {
+ tree->set_select_mode(Tree::SELECT_SINGLE);
+
+ }
+}
+
+EditorFileDialog::Mode EditorFileDialog::get_mode() const {
+
+ return mode;
+}
+
+void EditorFileDialog::set_access(Access p_access) {
+
+ ERR_FAIL_INDEX(p_access,3);
+ if (access==p_access)
+ return;
+ memdelete( dir_access );
+ switch(p_access) {
+ case ACCESS_FILESYSTEM: {
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ } break;
+ case ACCESS_RESOURCES: {
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ } break;
+ case ACCESS_USERDATA: {
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_USERDATA);
+ } break;
+ }
+ access=p_access;
+ _update_drives();
+ invalidate();
+ update_filters();
+ update_dir();
+}
+
+void EditorFileDialog::invalidate() {
+
+ if (is_visible()) {
+ update_file_list();
+ invalidated=false;
+ } else {
+ invalidated=true;
+ }
+
+}
+
+EditorFileDialog::Access EditorFileDialog::get_access() const{
+
+ return access;
+}
+
+void EditorFileDialog::_make_dir_confirm() {
+
+
+ Error err = dir_access->make_dir( makedirname->get_text() );
+ if (err==OK) {
+ dir_access->change_dir(makedirname->get_text());
+ invalidate();
+ update_filters();
+ update_dir();
+ } else {
+ mkdirerr->popup_centered_minsize(Size2(250,50));
+ }
+}
+
+
+void EditorFileDialog::_make_dir() {
+
+ makedialog->popup_centered_minsize(Size2(250,80));
+ makedirname->grab_focus();
+
+}
+
+void EditorFileDialog::_select_drive(int p_idx) {
+
+ String d = drives->get_item_text(p_idx);
+ dir_access->change_dir(d);
+ file->set_text("");
+ invalidate();
+ update_dir();
+
+}
+
+void EditorFileDialog::_update_drives() {
+
+
+ int dc = dir_access->get_drive_count();
+ if (dc==0 || access!=ACCESS_FILESYSTEM) {
+ drives->hide();
+ } else {
+ drives->clear();
+ drives->show();
+
+ for(int i=0;i<dir_access->get_drive_count();i++) {
+ String d = dir_access->get_drive(i);
+ drives->add_item(dir_access->get_drive(i));
+ }
+
+ drives->select(dir_access->get_current_drive());
+
+ }
+}
+
+bool EditorFileDialog::default_show_hidden_files=true;
+
+
+void EditorFileDialog::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_tree_selected"),&EditorFileDialog::_tree_selected);
+ ObjectTypeDB::bind_method(_MD("_tree_db_selected"),&EditorFileDialog::_tree_dc_selected);
+ ObjectTypeDB::bind_method(_MD("_dir_entered"),&EditorFileDialog::_dir_entered);
+ ObjectTypeDB::bind_method(_MD("_file_entered"),&EditorFileDialog::_file_entered);
+ ObjectTypeDB::bind_method(_MD("_action_pressed"),&EditorFileDialog::_action_pressed);
+ ObjectTypeDB::bind_method(_MD("_cancel_pressed"),&EditorFileDialog::_cancel_pressed);
+ ObjectTypeDB::bind_method(_MD("_filter_selected"),&EditorFileDialog::_filter_selected);
+ ObjectTypeDB::bind_method(_MD("_save_confirm_pressed"),&EditorFileDialog::_save_confirm_pressed);
+
+ ObjectTypeDB::bind_method(_MD("clear_filters"),&EditorFileDialog::clear_filters);
+ ObjectTypeDB::bind_method(_MD("add_filter","filter"),&EditorFileDialog::add_filter);
+ ObjectTypeDB::bind_method(_MD("get_current_dir"),&EditorFileDialog::get_current_dir);
+ ObjectTypeDB::bind_method(_MD("get_current_file"),&EditorFileDialog::get_current_file);
+ ObjectTypeDB::bind_method(_MD("get_current_path"),&EditorFileDialog::get_current_path);
+ ObjectTypeDB::bind_method(_MD("set_current_dir","dir"),&EditorFileDialog::set_current_dir);
+ ObjectTypeDB::bind_method(_MD("set_current_file","file"),&EditorFileDialog::set_current_file);
+ ObjectTypeDB::bind_method(_MD("set_current_path","path"),&EditorFileDialog::set_current_path);
+ ObjectTypeDB::bind_method(_MD("set_mode","mode"),&EditorFileDialog::set_mode);
+ ObjectTypeDB::bind_method(_MD("get_mode"),&EditorFileDialog::get_mode);
+ ObjectTypeDB::bind_method(_MD("get_vbox:VBoxContainer"),&EditorFileDialog::get_vbox);
+ ObjectTypeDB::bind_method(_MD("set_access","access"),&EditorFileDialog::set_access);
+ ObjectTypeDB::bind_method(_MD("get_access"),&EditorFileDialog::get_access);
+ ObjectTypeDB::bind_method(_MD("set_show_hidden_files"),&EditorFileDialog::set_show_hidden_files);
+ ObjectTypeDB::bind_method(_MD("is_showing_hidden_files"),&EditorFileDialog::is_showing_hidden_files);
+ ObjectTypeDB::bind_method(_MD("_select_drive"),&EditorFileDialog::_select_drive);
+ ObjectTypeDB::bind_method(_MD("_make_dir"),&EditorFileDialog::_make_dir);
+ ObjectTypeDB::bind_method(_MD("_make_dir_confirm"),&EditorFileDialog::_make_dir_confirm);
+ ObjectTypeDB::bind_method(_MD("_update_file_list"),&EditorFileDialog::update_file_list);
+ ObjectTypeDB::bind_method(_MD("_update_dir"),&EditorFileDialog::update_dir);
+ ObjectTypeDB::bind_method(_MD("_thumbnail_done"),&EditorFileDialog::_thumbnail_done);
+
+ ObjectTypeDB::bind_method(_MD("invalidate"),&EditorFileDialog::invalidate);
+
+ ADD_SIGNAL(MethodInfo("file_selected",PropertyInfo( Variant::STRING,"path")));
+ ADD_SIGNAL(MethodInfo("files_selected",PropertyInfo( Variant::STRING_ARRAY,"paths")));
+ ADD_SIGNAL(MethodInfo("dir_selected",PropertyInfo( Variant::STRING,"dir")));
+
+ BIND_CONSTANT( MODE_OPEN_FILE );
+ BIND_CONSTANT( MODE_OPEN_FILES );
+ BIND_CONSTANT( MODE_OPEN_DIR );
+ BIND_CONSTANT( MODE_SAVE_FILE );
+
+ BIND_CONSTANT( ACCESS_RESOURCES );
+ BIND_CONSTANT( ACCESS_USERDATA );
+ BIND_CONSTANT( ACCESS_FILESYSTEM );
+
+}
+
+
+void EditorFileDialog::set_show_hidden_files(bool p_show) {
+ show_hidden_files=p_show;
+ invalidate();
+}
+
+bool EditorFileDialog::is_showing_hidden_files() const {
+ return show_hidden_files;
+}
+
+void EditorFileDialog::set_default_show_hidden_files(bool p_show) {
+ default_show_hidden_files=p_show;
+}
+
+EditorFileDialog::EditorFileDialog() {
+
+ show_hidden_files=true;
+
+ VBoxContainer *vbc = memnew( VBoxContainer );
+ add_child(vbc);
+ set_child_rect(vbc);
+
+ mode=MODE_SAVE_FILE;
+ set_title("Save a File");
+
+ dir = memnew(LineEdit);
+ HBoxContainer *pathhb = memnew( HBoxContainer );
+ pathhb->add_child(dir);
+ dir->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ drives = memnew( OptionButton );
+ pathhb->add_child(drives);
+ drives->connect("item_selected",this,"_select_drive");
+
+ makedir = memnew( Button );
+ makedir->set_text("Create Folder");
+ makedir->connect("pressed",this,"_make_dir");
+ pathhb->add_child(makedir);
+
+ vbc->add_margin_child("Path:",pathhb);
+
+ list_hb = memnew( HBoxContainer );
+ vbc->add_margin_child("Directories & Files:",list_hb,true);
+
+ tree = memnew(Tree);
+ tree->set_hide_root(true);
+ tree->set_h_size_flags(SIZE_EXPAND_FILL);
+ list_hb->add_child(tree);
+
+ HBoxContainer* filter_hb = memnew( HBoxContainer );
+ vbc->add_child(filter_hb);
+
+ VBoxContainer *filter_vb = memnew( VBoxContainer );
+ filter_hb->add_child(filter_vb);
+ filter_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ preview_vb = memnew( VBoxContainer );
+ filter_hb->add_child(preview_vb);
+ CenterContainer *prev_cc = memnew( CenterContainer );
+ preview_vb->add_margin_child("Preview:",prev_cc);
+ preview = memnew( TextureFrame );
+ prev_cc->add_child(preview);
+ preview_vb->hide();
+
+
+ file = memnew(LineEdit);
+ //add_child(file);
+ filter_vb->add_margin_child("File:",file);
+
+
+ filter = memnew( OptionButton );
+ //add_child(filter);
+ filter_vb->add_margin_child("Filter:",filter);
+ filter->set_clip_text(true);//too many extensions overflow it
+
+ dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ access=ACCESS_RESOURCES;
+ _update_drives();
+
+
+ connect("confirmed", this,"_action_pressed");
+ //cancel->connect("pressed", this,"_cancel_pressed");
+ tree->connect("cell_selected", this,"_tree_selected",varray(),CONNECT_DEFERRED);
+ tree->connect("item_activated", this,"_tree_db_selected",varray());
+ dir->connect("text_entered", this,"_dir_entered");
+ file->connect("text_entered", this,"_file_entered");
+ filter->connect("item_selected", this,"_filter_selected");
+
+
+ confirm_save = memnew( ConfirmationDialog );
+ confirm_save->set_as_toplevel(true);
+ add_child(confirm_save);
+
+
+ confirm_save->connect("confirmed", this,"_save_confirm_pressed");
+
+ makedialog = memnew( ConfirmationDialog );
+ makedialog->set_title("Create Folder");
+ VBoxContainer *makevb= memnew( VBoxContainer );
+ makedialog->add_child(makevb);
+ makedialog->set_child_rect(makevb);
+ makedirname = memnew( LineEdit );
+ makevb->add_margin_child("Name:",makedirname);
+ add_child(makedialog);
+ makedialog->register_text_enter(makedirname);
+ makedialog->connect("confirmed",this,"_make_dir_confirm");
+ mkdirerr = memnew( AcceptDialog );
+ mkdirerr->set_text("Could not create folder.");
+ add_child(mkdirerr);
+
+ exterr = memnew( AcceptDialog );
+ exterr->set_text("Must use a valid extension.");
+ add_child(exterr);
+
+
+ //update_file_list();
+ update_filters();
+ update_dir();
+
+ set_hide_on_ok(false);
+ vbox=vbc;
+
+
+ invalidated=true;
+ if (register_func)
+ register_func(this);
+
+ preview_wheel_timeout=0;
+ preview_wheel_index=0;
+ preview_waiting=false;
+
+}
+
+
+EditorFileDialog::~EditorFileDialog() {
+
+ if (unregister_func)
+ unregister_func(this);
+ memdelete(dir_access);
+}
+
+
+void EditorLineEditFileChooser::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_browse"),&EditorLineEditFileChooser::_browse);
+ ObjectTypeDB::bind_method(_MD("_chosen"),&EditorLineEditFileChooser::_chosen);
+ ObjectTypeDB::bind_method(_MD("get_button:Button"),&EditorLineEditFileChooser::get_button);
+ ObjectTypeDB::bind_method(_MD("get_line_edit:LineEdit"),&EditorLineEditFileChooser::get_line_edit);
+ ObjectTypeDB::bind_method(_MD("get_file_dialog:EditorFileDialog"),&EditorLineEditFileChooser::get_file_dialog);
+
+}
+
+void EditorLineEditFileChooser::_chosen(const String& p_text){
+
+ line_edit->set_text(p_text);
+ line_edit->emit_signal("text_entered",p_text);
+}
+
+void EditorLineEditFileChooser::_browse() {
+
+ dialog->popup_centered_ratio();
+}
+
+EditorLineEditFileChooser::EditorLineEditFileChooser() {
+
+ line_edit = memnew( LineEdit );
+ add_child(line_edit);
+ line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ button = memnew( Button );
+ button->set_text(" .. ");
+ add_child(button);
+ button->connect("pressed",this,"_browse");
+ dialog = memnew( EditorFileDialog);
+ add_child(dialog);
+ dialog->connect("file_selected",this,"_chosen");
+ dialog->connect("dir_selected",this,"_chosen");
+ dialog->connect("files_selected",this,"_chosen");
+
+}
diff --git a/tools/editor/editor_file_dialog.h b/tools/editor/editor_file_dialog.h
new file mode 100644
index 0000000000..72b8848788
--- /dev/null
+++ b/tools/editor/editor_file_dialog.h
@@ -0,0 +1,198 @@
+/*************************************************************************/
+/* file_dialog.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2015 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 EDITORFILEDIALOG_H
+#define EDITORFILEDIALOG_H
+
+#include "scene/gui/dialogs.h"
+#include "scene/gui/tree.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/dialogs.h"
+#include "os/dir_access.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/texture_frame.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class EditorFileDialog : public ConfirmationDialog {
+
+ OBJ_TYPE( EditorFileDialog, ConfirmationDialog );
+
+public:
+
+ enum Access {
+ ACCESS_RESOURCES,
+ ACCESS_USERDATA,
+ ACCESS_FILESYSTEM
+ };
+
+
+ enum Mode {
+ MODE_OPEN_FILE,
+ MODE_OPEN_FILES,
+ MODE_OPEN_DIR,
+ MODE_SAVE_FILE,
+ };
+
+ typedef Ref<Texture> (*GetIconFunc)(const String&);
+ typedef void (*RegisterFunc)(EditorFileDialog*);
+
+ static GetIconFunc get_icon_func;
+ static GetIconFunc get_large_icon_func;
+ static RegisterFunc register_func;
+ static RegisterFunc unregister_func;
+
+private:
+
+ ConfirmationDialog *makedialog;
+ LineEdit *makedirname;
+
+ Button *makedir;
+ Access access;
+ //Button *action;
+ VBoxContainer *vbox;
+ Mode mode;
+ LineEdit *dir;
+ OptionButton *drives;
+ Tree *tree;
+ TextureFrame *preview;
+ VBoxContainer *preview_vb;
+ HBoxContainer *list_hb;
+ LineEdit *file;
+ AcceptDialog *mkdirerr;
+ AcceptDialog *exterr;
+ OptionButton *filter;
+ DirAccess *dir_access;
+ ConfirmationDialog *confirm_save;
+
+ Vector<String> filters;
+
+ bool preview_waiting;
+ int preview_wheel_index;
+ float preview_wheel_timeout;
+ static bool default_show_hidden_files;
+ bool show_hidden_files;
+
+ bool invalidated;
+
+ void update_dir();
+ void update_file_list();
+ void update_filters();
+
+ void _tree_selected();
+
+ void _select_drive(int p_idx);
+ void _tree_dc_selected();
+ void _dir_entered(String p_dir);
+ void _file_entered(const String& p_file);
+ void _action_pressed();
+ void _save_confirm_pressed();
+ void _cancel_pressed();
+ void _filter_selected(int);
+ void _make_dir();
+ void _make_dir_confirm();
+
+ void _update_drives();
+
+ virtual void _post_popup();
+
+
+ //callback funtion is callback(String p_path,Ref<Texture> preview,Variant udata) preview null if could not load
+
+ void _thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata);
+ void _request_single_thumbnail(const String& p_path);
+
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+ //bind helpers
+public:
+
+ void clear_filters();
+ void add_filter(const String& p_filter);
+
+ void set_enable_multiple_selection(bool p_enable);
+ Vector<String> get_selected_files() const;
+
+ String get_current_dir() const;
+ String get_current_file() const;
+ String get_current_path() const;
+ void set_current_dir(const String& p_dir);
+ void set_current_file(const String& p_file);
+ void set_current_path(const String& p_path);
+
+ void set_mode(Mode p_mode);
+ Mode get_mode() const;
+
+ VBoxContainer *get_vbox();
+ LineEdit *get_line_edit() { return file; }
+
+ void set_access(Access p_access);
+ Access get_access() const;
+
+ void set_show_hidden_files(bool p_show);
+ bool is_showing_hidden_files() const;
+
+ static void set_default_show_hidden_files(bool p_show);
+
+ void invalidate();
+
+ EditorFileDialog();
+ ~EditorFileDialog();
+
+};
+
+class EditorLineEditFileChooser : public HBoxContainer {
+
+ OBJ_TYPE( EditorLineEditFileChooser, HBoxContainer );
+ Button *button;
+ LineEdit *line_edit;
+ EditorFileDialog *dialog;
+
+ void _chosen(const String& p_text);
+ void _browse();
+protected:
+ static void _bind_methods();
+public:
+
+ Button *get_button() { return button; }
+ LineEdit *get_line_edit() { return line_edit; }
+ EditorFileDialog *get_file_dialog() { return dialog; }
+
+ EditorLineEditFileChooser();
+};
+
+VARIANT_ENUM_CAST( EditorFileDialog::Mode );
+VARIANT_ENUM_CAST( EditorFileDialog::Access );
+
+#endif // EDITORFILEDIALOG_H
diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp
index 7157dbda96..500f8d232e 100644
--- a/tools/editor/editor_node.cpp
+++ b/tools/editor/editor_node.cpp
@@ -99,6 +99,7 @@
#include "tools/editor/io_plugins/editor_translation_import_plugin.h"
#include "tools/editor/io_plugins/editor_mesh_import_plugin.h"
+#include "plugins/editor_preview_plugins.h"
EditorNode *EditorNode::singleton=NULL;
@@ -320,6 +321,11 @@ void EditorNode::_fs_changed() {
E->get()->invalidate();
}
+
+ for(Set<EditorFileDialog*>::Element *E=editor_file_dialogs.front();E;E=E->next()) {
+
+ E->get()->invalidate();
+ }
}
void EditorNode::_sources_changed(bool p_exist) {
@@ -386,7 +392,7 @@ void EditorNode::edit_node(Node *p_node) {
void EditorNode::open_resource(const String& p_type) {
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type(p_type,&extensions);
@@ -718,6 +724,96 @@ void EditorNode::_save_edited_subresources(Node* scene,Map<RES,bool>& processed,
}
+void EditorNode::_find_node_types(Node* p_node, int&count_2d, int&count_3d) {
+
+ if (p_node->is_type("Viewport") || (p_node!=get_edited_scene() && p_node->get_owner()!=get_edited_scene()))
+ return;
+
+ if (p_node->is_type("CanvasItem"))
+ count_2d++;
+ else if (p_node->is_type("Spatial"))
+ count_3d++;
+
+ for(int i=0;i<p_node->get_child_count();i++)
+ _find_node_types(p_node->get_child(i),count_2d,count_3d);
+
+}
+
+
+void EditorNode::_save_scene_with_preview(String p_file) {
+
+ int c2d=0;
+ int c3d=0;
+
+ EditorProgress save("save","Saving Scene",4);
+ save.step("Analyzing",0);
+ _find_node_types(get_edited_scene(),c2d,c3d);
+
+ RID viewport;
+ bool is2d;
+ if (c3d<c2d) {
+ viewport=scene_root->get_viewport();
+ is2d=true;
+ } else {
+ viewport=SpatialEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_viewport();
+ is2d=false;
+
+ }
+ save.step("Creating Thumbnail",1);
+ //current view?
+ int screen =-1;
+ for(int i=0;i<editor_table.size();i++) {
+ if (editor_plugin_screen==editor_table[i]) {
+ screen=i;
+ break;
+ }
+ }
+
+ _editor_select(is2d?0:1);
+
+ VS::get_singleton()->viewport_queue_screen_capture(viewport);
+ save.step("Creating Thumbnail",2);
+ save.step("Creating Thumbnail",3);
+ Image img = VS::get_singleton()->viewport_get_screen_capture(viewport);
+ int preview_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");;
+ int width,height;
+ if (img.get_width() > preview_size && img.get_width() >= img.get_height()) {
+
+ width=preview_size;
+ height = img.get_height() * preview_size / img.get_width();
+ } else if (img.get_height() > preview_size && img.get_height() >= img.get_width()) {
+
+ height=preview_size;
+ width = img.get_width() * preview_size / img.get_height();
+ } else {
+
+ width=img.get_width();
+ height=img.get_height();
+ }
+
+ img.convert(Image::FORMAT_RGB);
+ img.resize(width,height);
+
+ String pfile = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/last_scene_preview.png");
+ img.save_png(pfile);
+ Vector<uint8_t> imgdata = FileAccess::get_file_as_array(pfile);
+
+ print_line("img data is "+itos(imgdata.size()));
+
+ if (scene_import_metadata.is_null())
+ scene_import_metadata = Ref<ResourceImportMetadata>( memnew( ResourceImportMetadata ) );
+ scene_import_metadata->set_option("thumbnail",imgdata);
+
+ //tamanio tel thumbnail
+ if (screen!=-1) {
+ _editor_select(screen);
+ }
+ save.step("Saving Scene",4);
+ _save_scene(p_file);
+
+}
+
+
void EditorNode::_save_scene(String p_file) {
Node *scene = edited_scene;
@@ -1016,7 +1112,9 @@ void EditorNode::_dialog_action(String p_file) {
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
- _save_scene(p_file);
+ //_save_scene(p_file);
+ _save_scene_with_preview(p_file);
+
}
} break;
@@ -1024,7 +1122,8 @@ void EditorNode::_dialog_action(String p_file) {
case FILE_SAVE_AND_RUN: {
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
- _save_scene(p_file);
+ //_save_scene(p_file);
+ _save_scene_with_preview(p_file);
_run(false);
}
} break;
@@ -1177,7 +1276,8 @@ void EditorNode::_dialog_action(String p_file) {
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
- _save_scene(p_file);
+ //_save_scene(p_file);
+ _save_scene_with_preview(p_file);
}
} break;
@@ -1505,7 +1605,8 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
return;
}
- _save_scene(scene->get_filename());
+ //_save_scene(scene->get_filename());
+ _save_scene_with_preview(scene->get_filename());
}
}
@@ -1608,7 +1709,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
//print_tree();
- file->set_mode(FileDialog::MODE_OPEN_FILE);
+ file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
//not for now?
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene",&extensions);
@@ -1659,7 +1760,8 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
Node *scene = edited_scene;
if (scene && scene->get_filename()!="") {
- _save_scene(scene->get_filename());
+ //_save_scene(scene->get_filename());
+ _save_scene_with_preview(scene->get_filename());
return;
};
// fallthrough to save_as
@@ -1678,7 +1780,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
break;
}
- file->set_mode(FileDialog::MODE_SAVE_FILE);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
bool relpaths = (scene->has_meta("__editor_relpaths__") && scene->get_meta("__editor_relpaths__").operator bool());
@@ -1761,7 +1863,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
bool relpaths = (scene->has_meta("__editor_relpaths__") && scene->get_meta("__editor_relpaths__").operator bool());
- file->set_mode(FileDialog::MODE_SAVE_FILE);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
file->set_current_path(cpath);
file->set_title("Save Translatable Strings");
@@ -1810,7 +1912,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
break;
}
- file->set_mode(FileDialog::MODE_SAVE_FILE);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
List<String> extensions;
Ref<PackedScene> sd = memnew( PackedScene );
@@ -3132,6 +3234,7 @@ void EditorNode::register_editor_types() {
ObjectTypeDB::register_type<EditorImportPlugin>();
ObjectTypeDB::register_type<EditorScenePostImport>();
ObjectTypeDB::register_type<EditorScript>();
+ ObjectTypeDB::register_type<EditorFileDialog>();
//ObjectTypeDB::register_type<EditorImporter>();
@@ -3282,6 +3385,16 @@ void EditorNode::_file_dialog_unregister(FileDialog *p_dialog){
singleton->file_dialogs.erase(p_dialog);
}
+void EditorNode::_editor_file_dialog_register(EditorFileDialog *p_dialog) {
+
+ singleton->editor_file_dialogs.insert(p_dialog);
+}
+
+void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog){
+
+ singleton->editor_file_dialogs.erase(p_dialog);
+}
+
Vector<EditorNodeInitCallback> EditorNode::_init_callbacks;
Error EditorNode::export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after) {
@@ -3334,6 +3447,11 @@ EditorNode::EditorNode() {
FileDialog::register_func=_file_dialog_register;
FileDialog::unregister_func=_file_dialog_unregister;
+ EditorFileDialog::get_icon_func=_file_dialog_get_icon;
+ EditorFileDialog::register_func=_editor_file_dialog_register;
+ EditorFileDialog::unregister_func=_editor_file_dialog_unregister;
+
+
editor_import_export = memnew( EditorImportExport );
add_child(editor_import_export);
@@ -3358,6 +3476,9 @@ EditorNode::EditorNode() {
editor_register_icons(theme);
editor_register_fonts(theme);
+ //theme->set_icon("folder","EditorFileDialog",Theme::get_default()->get_icon("folder","EditorFileDialog"));
+ //theme->set_color("files_disabled","EditorFileDialog",Color(0,0,0,0.7));
+
String global_font = EditorSettings::get_singleton()->get("global/font");
if (global_font!="") {
Ref<Font> fnt = ResourceLoader::load(global_font);
@@ -3376,6 +3497,8 @@ EditorNode::EditorNode() {
theme->set_stylebox("EditorFocus","EditorStyles",focus_sbt);
+ resource_preview = memnew( EditorResourcePreview );
+ add_child(resource_preview);
progress_dialog = memnew( ProgressDialog );
gui_base->add_child(progress_dialog);
@@ -3473,6 +3596,7 @@ EditorNode::EditorNode() {
animation_panel=pc;
animation_panel->hide();
+
HBoxContainer *animation_hb = memnew( HBoxContainer);
animation_vb->add_child(animation_hb);
@@ -4031,7 +4155,7 @@ EditorNode::EditorNode() {
file_templates->add_filter("*.tpz ; Template Package");
- file = memnew( FileDialog );
+ file = memnew( EditorFileDialog );
gui_base->add_child(file);
file->set_current_dir("res://");
@@ -4161,6 +4285,13 @@ EditorNode::EditorNode() {
for(int i=0;i<EditorPlugins::get_plugin_count();i++)
add_editor_plugin( EditorPlugins::create(i,this) );
+
+ resource_preview->add_preview_generator( Ref<EditorTexturePreviewPlugin>( memnew(EditorTexturePreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorPackedScenePreviewPlugin>( memnew(EditorPackedScenePreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorMaterialPreviewPlugin>( memnew(EditorMaterialPreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorScriptPreviewPlugin>( memnew(EditorScriptPreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorSamplePreviewPlugin>( memnew(EditorSamplePreviewPlugin )));
+
circle_step_msec=OS::get_singleton()->get_ticks_msec();
circle_step_frame=OS::get_singleton()->get_frames_drawn();;
circle_step=0;
diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h
index 614cec5bcc..365dff84ee 100644
--- a/tools/editor/editor_node.h
+++ b/tools/editor/editor_node.h
@@ -78,7 +78,7 @@
#include "tools/editor/editor_plugin.h"
#include "fileserver/editor_file_server.h"
-
+#include "editor_resource_preview.h"
@@ -238,7 +238,7 @@ class EditorNode : public Node {
EditorSettingsDialog *settings_config_dialog;
RunSettingsDialog *run_settings_dialog;
ProjectSettings *project_settings;
- FileDialog *file;
+ EditorFileDialog *file;
FileDialog *file_templates;
FileDialog *file_export;
FileDialog *file_export_lib;
@@ -304,6 +304,7 @@ class EditorNode : public Node {
EditorSelection *editor_selection;
ProjectExport *project_export;
ProjectExportDialog *project_export_settings;
+ EditorResourcePreview *resource_preview;
EditorFileServer *file_server;
@@ -381,11 +382,15 @@ class EditorNode : public Node {
String import_reload_fn;
Set<FileDialog*> file_dialogs;
+ Set<EditorFileDialog*> editor_file_dialogs;
+
Map<String,Ref<Texture> > icon_type_cache;
static Ref<Texture> _file_dialog_get_icon(const String& p_path);
static void _file_dialog_register(FileDialog *p_dialog);
static void _file_dialog_unregister(FileDialog *p_dialog);
+ static void _editor_file_dialog_register(EditorFileDialog *p_dialog);
+ static void _editor_file_dialog_unregister(EditorFileDialog *p_dialog);
void _cleanup_scene();
@@ -394,6 +399,9 @@ class EditorNode : public Node {
bool _find_and_save_edited_subresources(Object *obj,Map<RES,bool>& processed,int32_t flags);
void _save_edited_subresources(Node* scene,Map<RES,bool>& processed,int32_t flags);
+ void _find_node_types(Node* p_node, int&count_2d, int&count_3d);
+ void _save_scene_with_preview(String p_file);
+
struct ExportDefer {
String platform;
diff --git a/tools/editor/editor_resource_preview.cpp b/tools/editor/editor_resource_preview.cpp
new file mode 100644
index 0000000000..9b7d8d227e
--- /dev/null
+++ b/tools/editor/editor_resource_preview.cpp
@@ -0,0 +1,260 @@
+#include "editor_resource_preview.h"
+#include "editor_settings.h"
+#include "os/file_access.h"
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "globals.h"
+
+
+Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String& p_path) {
+
+ RES res = ResourceLoader::load(p_path);
+ if (!res.is_valid())
+ return res;
+ return generate(res);
+}
+
+EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() {
+
+
+}
+
+
+EditorResourcePreview* EditorResourcePreview::singleton=NULL;
+
+
+void EditorResourcePreview::_thread_func(void *ud) {
+
+ EditorResourcePreview *erp=(EditorResourcePreview*)ud;
+ erp->_thread();
+
+}
+
+
+void EditorResourcePreview::_preview_ready(const String& p_str,const Ref<Texture>& p_texture,ObjectID id,const StringName& p_func,const Variant& p_ud) {
+
+ print_line("preview is ready");
+ preview_mutex->lock();
+
+ Item item;
+ item.order=order++;
+ item.preview=p_texture;
+ cache[p_str]=item;
+
+ Object *recv = ObjectDB::get_instance(id);
+ if (recv) {
+ recv->call_deferred(p_func,p_str,p_texture,p_ud);
+ }
+
+ preview_mutex->unlock();
+}
+
+Ref<Texture> EditorResourcePreview::_generate_preview(const QueueItem& p_item,const String& cache_base) {
+
+ String type = ResourceLoader::get_resource_type(p_item.path);
+ print_line("resource type is: "+type);
+
+ if (type=="")
+ return Ref<Texture>(); //could not guess type
+
+ Ref<Texture> generated;
+
+ for(int i=0;i<preview_generators.size();i++) {
+ if (!preview_generators[i]->handles(type))
+ continue;
+ generated = preview_generators[i]->generate_from_path(p_item.path);
+
+ break;
+ }
+
+ if (generated.is_valid()) {
+ print_line("was generated");
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ //wow it generated a preview... save cache
+ ResourceSaver::save(cache_base+".png",generated);
+ FileAccess *f=FileAccess::open(cache_base+".txt",FileAccess::WRITE);
+ f->store_line(itos(thumbnail_size));
+ f->store_line(itos(FileAccess::get_modified_time(p_item.path)));
+ f->store_line(FileAccess::get_md5(p_item.path));
+ memdelete(f);
+ } else {
+ print_line("was not generated");
+
+ }
+
+ return generated;
+}
+
+void EditorResourcePreview::_thread() {
+
+ print_line("begin thread");
+ while(!exit) {
+
+ print_line("wait for semaphore");
+ preview_sem->wait();
+ preview_mutex->lock();
+
+ print_line("blue team go");
+
+ if (queue.size()) {
+
+ print_line("pop from queue");
+
+ QueueItem item = queue.front()->get();
+ queue.pop_front();
+ preview_mutex->unlock();
+
+ Ref<Texture> texture;
+
+
+ uint64_t modtime = FileAccess::get_modified_time(item.path);
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+
+ if (cache.has(item.path)) {
+ //already has it because someone loaded it, just let it know it's ready
+ call_deferred("_preview_ready",item.path,cache[item.path].preview,item.id,item.function,item.userdata);
+
+ } else {
+
+
+ String temp_path=EditorSettings::get_singleton()->get_settings_path().plus_file("tmp");
+ String cache_base = Globals::get_singleton()->globalize_path(item.path).md5_text();
+ cache_base = temp_path.plus_file("resthumb-"+cache_base);
+
+ //does not have it, try to load a cached thumbnail
+
+ String file = cache_base+".txt";
+ print_line("cachetxt at "+file);
+ FileAccess *f=FileAccess::open(file,FileAccess::READ);
+ if (!f) {
+
+ print_line("generate because not cached");
+
+ //generate
+ texture=_generate_preview(item,cache_base);
+ } else {
+
+ int tsize = f->get_line().to_int64();
+ uint64_t last_modtime = f->get_line().to_int64();
+
+ bool cache_valid = true;
+
+ if (tsize!=thumbnail_size) {
+ cache_valid=false;
+ memdelete(f);
+ } else if (last_modtime!=modtime) {
+
+ String last_md5 = f->get_line();
+ String md5 = FileAccess::get_md5(item.path);
+ memdelete(f);
+
+ if (last_md5!=md5) {
+
+ cache_valid=false;
+ } else {
+ //update modified time
+
+ f=FileAccess::open(file,FileAccess::WRITE);
+ f->store_line(itos(modtime));
+ f->store_line(md5);
+ memdelete(f);
+ }
+ } else {
+ memdelete(f);
+ }
+
+ if (cache_valid) {
+
+ texture = ResourceLoader::load(cache_base+".png","ImageTexture",true);
+ if (!texture.is_valid()) {
+ //well fuck
+ cache_valid=false;
+ }
+ }
+
+ if (!cache_valid) {
+
+ texture=_generate_preview(item,cache_base);
+ }
+
+ }
+
+ print_line("notify of preview ready");
+ call_deferred("_preview_ready",item.path,texture,item.id,item.function,item.userdata);
+
+ }
+
+ } else {
+ preview_mutex->unlock();
+ }
+
+ }
+}
+
+
+
+
+void EditorResourcePreview::queue_resource_preview(const String& p_path, Object* p_receiver, const StringName& p_receiver_func, const Variant& p_userdata) {
+
+ ERR_FAIL_NULL(p_receiver);
+ preview_mutex->lock();
+ if (cache.has(p_path)) {
+ cache[p_path].order=order++;
+ p_receiver->call_deferred(p_receiver_func,p_path,cache[p_path].preview,p_userdata);
+ preview_mutex->unlock();
+ return;
+
+ }
+
+ print_line("send to thread");
+ QueueItem item;
+ item.function=p_receiver_func;
+ item.id=p_receiver->get_instance_ID();
+ item.path=p_path;
+ item.userdata=p_userdata;
+
+ queue.push_back(item);
+ preview_mutex->unlock();
+ preview_sem->post();
+
+}
+
+void EditorResourcePreview::add_preview_generator(const Ref<EditorResourcePreviewGenerator>& p_generator) {
+
+ preview_generators.push_back(p_generator);
+}
+
+EditorResourcePreview* EditorResourcePreview::get_singleton() {
+
+ return singleton;
+}
+
+void EditorResourcePreview::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_preview_ready",&EditorResourcePreview::_preview_ready);
+}
+
+EditorResourcePreview::EditorResourcePreview() {
+ singleton=this;
+ preview_mutex = Mutex::create();
+ preview_sem = Semaphore::create();
+ order=0;
+ exit=false;
+
+ thread = Thread::create(_thread_func,this);
+}
+
+
+EditorResourcePreview::~EditorResourcePreview()
+{
+
+ exit=true;
+ preview_sem->post();
+ Thread::wait_to_finish(thread);
+ memdelete(thread);
+ memdelete(preview_mutex);
+ memdelete(preview_sem);
+
+
+}
+
diff --git a/tools/editor/editor_resource_preview.h b/tools/editor/editor_resource_preview.h
new file mode 100644
index 0000000000..f8b96eca22
--- /dev/null
+++ b/tools/editor/editor_resource_preview.h
@@ -0,0 +1,95 @@
+#ifndef EDITORRESOURCEPREVIEW_H
+#define EDITORRESOURCEPREVIEW_H
+
+#include "scene/main/node.h"
+#include "os/semaphore.h"
+#include "os/thread.h"
+#include "scene/resources/texture.h"
+
+/* make previews for:
+*packdscene
+-wav
+*image
+-mesh
+-font
+*script
+*material
+-shader
+-shader graph?
+-navigation mesh
+-collision?
+-occluder polygon
+-navigation polygon
+-tileset
+-curve and curve2D
+*/
+
+
+class EditorResourcePreviewGenerator : public Reference {
+
+ OBJ_TYPE(EditorResourcePreviewGenerator,Reference );
+
+public:
+
+ virtual bool handles(const String& p_type) const=0;
+ virtual Ref<Texture> generate(const RES& p_from)=0;
+ virtual Ref<Texture> generate_from_path(const String& p_path);
+
+ EditorResourcePreviewGenerator();
+};
+
+
+class EditorResourcePreview : public Node {
+
+ OBJ_TYPE(EditorResourcePreview,Node);
+
+
+ static EditorResourcePreview* singleton;
+
+ struct QueueItem {
+ String path;
+ ObjectID id;
+ StringName function;
+ Variant userdata;
+ };
+
+ List<QueueItem> queue;
+
+ Mutex *preview_mutex;
+ Semaphore *preview_sem;
+ Thread *thread;
+ bool exit;
+
+ struct Item {
+ Ref<Texture> preview;
+ int order;
+ };
+
+ int order;
+
+ Map<String,Item> cache;
+
+ void _preview_ready(const String& p_str,const Ref<Texture>& p_texture, ObjectID id, const StringName &p_func, const Variant &p_ud);
+ Ref<Texture> _generate_preview(const QueueItem& p_item, const String &cache_base);
+
+ static void _thread_func(void *ud);
+ void _thread();
+
+ Vector<Ref<EditorResourcePreviewGenerator> > preview_generators;
+protected:
+
+ static void _bind_methods();
+public:
+
+ static EditorResourcePreview* get_singleton();
+
+ //callback funtion is callback(String p_path,Ref<Texture> preview,Variant udata) preview null if could not load
+ void queue_resource_preview(const String& p_path, Object* p_receiver, const StringName& p_receiver_func, const Variant& p_userdata);
+
+ void add_preview_generator(const Ref<EditorResourcePreviewGenerator>& p_generator);
+
+ EditorResourcePreview();
+ ~EditorResourcePreview();
+};
+
+#endif // EDITORRESOURCEPREVIEW_H
diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp
index f49d3b496d..2fac05753a 100644
--- a/tools/editor/editor_settings.cpp
+++ b/tools/editor/editor_settings.cpp
@@ -448,6 +448,8 @@ void EditorSettings::_load_defaults() {
set("text_editor/create_signal_callbacks",true);
set("file_dialog/show_hidden_files", false);
+ set("file_dialog/thumbnail_size", 64);
+ hints["file_dialog/thumbnail_size"]=PropertyInfo(Variant::INT,"file_dialog/thumbnail_size",PROPERTY_HINT_RANGE,"32,128,16");
set("animation/autorename_animation_tracks",true);
set("animation/confirm_insert_track",true);
diff --git a/tools/editor/icons/icon_wait_no_preview.png b/tools/editor/icons/icon_wait_no_preview.png
new file mode 100644
index 0000000000..5d20cd99ec
--- /dev/null
+++ b/tools/editor/icons/icon_wait_no_preview.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_1.png b/tools/editor/icons/icon_wait_preview_1.png
new file mode 100644
index 0000000000..0aab42e04a
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_1.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_2.png b/tools/editor/icons/icon_wait_preview_2.png
new file mode 100644
index 0000000000..f476b9ce1f
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_2.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_3.png b/tools/editor/icons/icon_wait_preview_3.png
new file mode 100644
index 0000000000..2775d1ef43
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_3.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_4.png b/tools/editor/icons/icon_wait_preview_4.png
new file mode 100644
index 0000000000..2eaa86fec9
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_4.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_5.png b/tools/editor/icons/icon_wait_preview_5.png
new file mode 100644
index 0000000000..6590644bc1
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_5.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_6.png b/tools/editor/icons/icon_wait_preview_6.png
new file mode 100644
index 0000000000..307e412310
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_6.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_7.png b/tools/editor/icons/icon_wait_preview_7.png
new file mode 100644
index 0000000000..b0edc94d93
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_7.png
Binary files differ
diff --git a/tools/editor/icons/icon_wait_preview_8.png b/tools/editor/icons/icon_wait_preview_8.png
new file mode 100644
index 0000000000..67a2f48ec3
--- /dev/null
+++ b/tools/editor/icons/icon_wait_preview_8.png
Binary files differ
diff --git a/tools/editor/plugins/editor_preview_plugins.cpp b/tools/editor/plugins/editor_preview_plugins.cpp
new file mode 100644
index 0000000000..64814cce6a
--- /dev/null
+++ b/tools/editor/plugins/editor_preview_plugins.cpp
@@ -0,0 +1,664 @@
+#include "editor_preview_plugins.h"
+#include "io/resource_loader.h"
+#include "tools/editor/editor_settings.h"
+#include "io/file_access_memory.h"
+#include "os/os.h"
+#include "scene/resources/material.h"
+#include "scene/resources/sample.h"
+
+bool EditorTexturePreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"ImageTexture");
+}
+
+Ref<Texture> EditorTexturePreviewPlugin::generate(const RES& p_from) {
+
+ Ref<ImageTexture> tex =p_from;
+ Image img = tex->get_data();
+ if (img.empty())
+ return Ref<Texture>();
+
+ img.clear_mipmaps();
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ if (img.is_compressed()) {
+ if (img.decompress()!=OK)
+ return Ref<Texture>();
+ } else if (img.get_format()!=Image::FORMAT_RGB && img.get_format()!=Image::FORMAT_RGB) {
+ img.convert(Image::FORMAT_RGBA);
+ }
+
+ int width,height;
+ if (img.get_width() > thumbnail_size && img.get_width() >= img.get_height()) {
+
+ width=thumbnail_size;
+ height = img.get_height() * thumbnail_size / img.get_width();
+ } else if (img.get_height() > thumbnail_size && img.get_height() >= img.get_width()) {
+
+ height=thumbnail_size;
+ width = img.get_width() * thumbnail_size / img.get_height();
+ } else {
+
+ width=img.get_width();
+ height=img.get_height();
+ }
+
+ img.resize(width,height);
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
+
+ ptex->create_from_image(img,0);
+ return ptex;
+
+}
+
+EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() {
+
+
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+
+Ref<Texture> EditorPackedScenePreviewPlugin::_gen_from_imd(Ref<ResourceImportMetadata> p_imd) {
+
+ if (p_imd.is_null())
+ return Ref<Texture>();
+
+ if (!p_imd->has_option("thumbnail"))
+ return Ref<Texture>();
+
+ Variant tn = p_imd->get_option("thumbnail");
+ print_line(Variant::get_type_name(tn.get_type()));
+ DVector<uint8_t> thumbnail = tn;
+
+ int len = thumbnail.size();
+ if (len==0)
+ return Ref<Texture>();
+
+
+ DVector<uint8_t>::Read r = thumbnail.read();
+
+ Image img(r.ptr(),len);
+ if (img.empty())
+ return Ref<Texture>();
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
+ ptex->create_from_image(img,0);
+ return ptex;
+
+}
+
+bool EditorPackedScenePreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"PackedScene");
+}
+Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES& p_from) {
+
+ Ref<ResourceImportMetadata> imd = p_from->get_import_metadata();
+ return _gen_from_imd(imd);
+}
+
+Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String& p_path) {
+
+ Ref<ResourceImportMetadata> imd = ResourceLoader::load_import_metadata(p_path);
+ return _gen_from_imd(imd);
+}
+
+EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
+
+}
+
+//////////////////////////////////////////////////////////////////
+
+bool EditorMaterialPreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Material"); //any material
+}
+
+Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES& p_from) {
+
+ Ref<Material> material = p_from;
+ ERR_FAIL_COND_V(material.is_null(),Ref<Texture>());
+
+ VS::get_singleton()->mesh_surface_set_material(sphere,0,material->get_rid());
+
+ VS::get_singleton()->viewport_queue_screen_capture(viewport);
+ VS::get_singleton()->viewport_set_render_target_update_mode(viewport,VS::RENDER_TARGET_UPDATE_ONCE); //once used for capture
+// print_line("queue capture!");
+ Image img;
+
+ int timeout=1000;
+ while(timeout) {
+ //print_line("try capture?");
+ OS::get_singleton()->delay_usec(10);
+ img = VS::get_singleton()->viewport_get_screen_capture(viewport);
+ if (!img.empty())
+ break;
+ timeout--;
+ }
+
+ //print_line("captured!");
+ VS::get_singleton()->mesh_surface_set_material(sphere,0,RID());
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ img.resize(thumbnail_size,thumbnail_size);
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
+ ptex->create_from_image(img,0);
+ return ptex;
+}
+
+EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
+
+ scenario = VS::get_singleton()->scenario_create();
+
+ viewport = VS::get_singleton()->viewport_create();
+ VS::get_singleton()->viewport_set_as_render_target(viewport,true);
+ VS::get_singleton()->viewport_set_render_target_update_mode(viewport,VS::RENDER_TARGET_UPDATE_DISABLED);
+ VS::get_singleton()->viewport_set_scenario(viewport,scenario);
+ VS::ViewportRect vr;
+ vr.x=0;
+ vr.y=0;
+ vr.width=128;
+ vr.height=128;
+ VS::get_singleton()->viewport_set_rect(viewport,vr);
+
+ camera = VS::get_singleton()->camera_create();
+ VS::get_singleton()->viewport_attach_camera(viewport,camera);
+ VS::get_singleton()->camera_set_transform(camera,Transform(Matrix3(),Vector3(0,0,3)));
+ VS::get_singleton()->camera_set_perspective(camera,45,0.1,10);
+
+ light = VS::get_singleton()->light_create(VS::LIGHT_DIRECTIONAL);
+ light_instance = VS::get_singleton()->instance_create2(light,scenario);
+ VS::get_singleton()->instance_set_transform(light_instance,Transform().looking_at(Vector3(-1,-1,-1),Vector3(0,1,0)));
+
+ light2 = VS::get_singleton()->light_create(VS::LIGHT_DIRECTIONAL);
+ VS::get_singleton()->light_set_color(light2,VS::LIGHT_COLOR_DIFFUSE,Color(0.7,0.7,0.7));
+ VS::get_singleton()->light_set_color(light2,VS::LIGHT_COLOR_SPECULAR,Color(0.0,0.0,0.0));
+ light_instance2 = VS::get_singleton()->instance_create2(light2,scenario);
+
+ VS::get_singleton()->instance_set_transform(light_instance2,Transform().looking_at(Vector3(0,1,0),Vector3(0,0,1)));
+
+ sphere = VS::get_singleton()->mesh_create();
+ sphere_instance = VS::get_singleton()->instance_create2(sphere,scenario);
+
+ int lats=32;
+ int lons=32;
+ float radius=1.0;
+
+ DVector<Vector3> vertices;
+ DVector<Vector3> normals;
+ DVector<Vector2> uvs;
+ DVector<float> tangents;
+ Matrix3 tt = Matrix3(Vector3(0,1,0),Math_PI*0.5);
+
+ for(int i = 1; i <= lats; i++) {
+ double lat0 = Math_PI * (-0.5 + (double) (i - 1) / lats);
+ double z0 = Math::sin(lat0);
+ double zr0 = Math::cos(lat0);
+
+ double lat1 = Math_PI * (-0.5 + (double) i / lats);
+ double z1 = Math::sin(lat1);
+ double zr1 = Math::cos(lat1);
+
+ for(int j = lons; j >= 1; j--) {
+
+ double lng0 = 2 * Math_PI * (double) (j - 1) / lons;
+ double x0 = Math::cos(lng0);
+ double y0 = Math::sin(lng0);
+
+ double lng1 = 2 * Math_PI * (double) (j) / lons;
+ double x1 = Math::cos(lng1);
+ double y1 = Math::sin(lng1);
+
+
+ Vector3 v[4]={
+ Vector3(x1 * zr0, z0, y1 *zr0),
+ Vector3(x1 * zr1, z1, y1 *zr1),
+ Vector3(x0 * zr1, z1, y0 *zr1),
+ Vector3(x0 * zr0, z0, y0 *zr0)
+ };
+
+#define ADD_POINT(m_idx) \
+ normals.push_back(v[m_idx]);\
+ vertices.push_back(v[m_idx]*radius);\
+ { Vector2 uv(Math::atan2(v[m_idx].x,v[m_idx].z),Math::atan2(-v[m_idx].y,v[m_idx].z));\
+ uv/=Math_PI;\
+ uv*=4.0;\
+ uv=uv*0.5+Vector2(0.5,0.5);\
+ uvs.push_back(uv);\
+ }\
+ { Vector3 t = tt.xform(v[m_idx]);\
+ tangents.push_back(t.x);\
+ tangents.push_back(t.y);\
+ tangents.push_back(t.z);\
+ tangents.push_back(1.0);\
+ }
+
+
+
+ ADD_POINT(0);
+ ADD_POINT(1);
+ ADD_POINT(2);
+
+ ADD_POINT(2);
+ ADD_POINT(3);
+ ADD_POINT(0);
+ }
+ }
+
+ Array arr;
+ arr.resize(VS::ARRAY_MAX);
+ arr[VS::ARRAY_VERTEX]=vertices;
+ arr[VS::ARRAY_NORMAL]=normals;
+ arr[VS::ARRAY_TANGENT]=tangents;
+ arr[VS::ARRAY_TEX_UV]=uvs;
+ VS::get_singleton()->mesh_add_surface(sphere,VS::PRIMITIVE_TRIANGLES,arr);
+
+}
+
+EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
+
+ VS::get_singleton()->free(sphere);
+ VS::get_singleton()->free(sphere_instance);
+ VS::get_singleton()->free(viewport);
+ VS::get_singleton()->free(light);
+ VS::get_singleton()->free(light_instance);
+ VS::get_singleton()->free(light2);
+ VS::get_singleton()->free(light_instance2);
+ VS::get_singleton()->free(camera);
+ VS::get_singleton()->free(scenario);
+
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static bool _is_text_char(CharType c) {
+
+ return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
+}
+
+bool EditorScriptPreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Script");
+}
+
+Ref<Texture> EditorScriptPreviewPlugin::generate(const RES& p_from) {
+
+
+ Ref<Script> scr = p_from;
+ if (scr.is_null())
+ return Ref<Texture>();
+
+ String code = scr->get_source_code().strip_edges();
+ if (code=="")
+ return Ref<Texture>();
+
+ List<String> kwors;
+ scr->get_language()->get_reserved_words(&kwors);
+
+ Set<String> keywords;
+
+ for(List<String>::Element *E=kwors.front();E;E=E->next()) {
+
+ keywords.insert(E->get());
+
+ }
+
+
+ int line = 0;
+ int col=0;
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ Image img(thumbnail_size,thumbnail_size,0,Image::FORMAT_RGBA);
+
+
+
+ Color bg_color = EditorSettings::get_singleton()->get("text_editor/background_color");
+ bg_color.a=1.0;
+ Color keyword_color = EditorSettings::get_singleton()->get("text_editor/keyword_color");
+ Color text_color = EditorSettings::get_singleton()->get("text_editor/text_color");
+ Color symbol_color = EditorSettings::get_singleton()->get("text_editor/symbol_color");
+ Color comment_color = EditorSettings::get_singleton()->get("text_editor/comment_color");
+
+
+ for(int i=0;i<thumbnail_size;i++) {
+ for(int j=0;j<thumbnail_size;j++) {
+ img.put_pixel(i,j,bg_color);
+ }
+
+ }
+
+ bool prev_is_text=false;
+ bool in_keyword=false;
+ for(int i=0;i<code.length();i++) {
+
+ CharType c = code[i];
+ if (c>32) {
+ if (col<thumbnail_size) {
+ Color color = text_color;
+
+ if (c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t')) {
+ //make symbol a little visible
+ color=symbol_color;
+ in_keyword=false;
+ } else if (!prev_is_text && _is_text_char(c)) {
+ int pos = i;
+
+ while(_is_text_char(code[pos])) {
+ pos++;
+ }
+ ///print_line("from "+itos(i)+" to "+itos(pos));
+ String word = code.substr(i,pos-i);
+ //print_line("found word: "+word);
+ if (keywords.has(word))
+ in_keyword=true;
+
+ } else if (!_is_text_char(c)) {
+ in_keyword=false;
+ }
+
+ if (in_keyword)
+ color=keyword_color;
+
+ Color ul=color;
+ ul.a*=0.5;
+ img.put_pixel(col,line*2,bg_color.blend(ul));
+ img.put_pixel(col,line*2+1,color);
+
+ prev_is_text=_is_text_char(c);
+ }
+ } else {
+
+ prev_is_text=false;
+ in_keyword=false;
+
+ if (c=='\n') {
+ col=0;
+ line++;
+ if (line>=thumbnail_size/2)
+ break;
+ } else if (c=='\t') {
+ col+=3;
+ }
+ }
+ col++;
+ }
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture));
+
+ ptex->create_from_image(img,0);
+ return ptex;
+
+}
+
+EditorScriptPreviewPlugin::EditorScriptPreviewPlugin() {
+
+
+}
+///////////////////////////////////////////////////////////////////
+
+bool EditorSamplePreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Sample");
+}
+
+Ref<Texture> EditorSamplePreviewPlugin::generate(const RES& p_from) {
+
+ Ref<Sample> smp =p_from;
+ ERR_FAIL_COND_V(smp.is_null(),Ref<Texture>());
+
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+
+ DVector<uint8_t> img;
+ int w = thumbnail_size;
+ int h = thumbnail_size;
+ img.resize(w*h*3);
+
+ DVector<uint8_t>::Write imgdata = img.write();
+ uint8_t * imgw = imgdata.ptr();
+ DVector<uint8_t> data = smp->get_data();
+ DVector<uint8_t>::Read sampledata = data.read();
+ const uint8_t *sdata=sampledata.ptr();
+
+ bool stereo = smp->is_stereo();
+ bool _16=smp->get_format()==Sample::FORMAT_PCM16;
+ int len = smp->get_length();
+
+ if (len<1)
+ return Ref<Texture>();
+
+ if (smp->get_format()==Sample::FORMAT_IMA_ADPCM) {
+
+ struct IMA_ADPCM_State {
+
+ int16_t step_index;
+ int32_t predictor;
+ /* values at loop point */
+ int16_t loop_step_index;
+ int32_t loop_predictor;
+ int32_t last_nibble;
+ int32_t loop_pos;
+ int32_t window_ofs;
+ const uint8_t *ptr;
+ } ima_adpcm;
+
+ ima_adpcm.step_index=0;
+ ima_adpcm.predictor=0;
+ ima_adpcm.loop_step_index=0;
+ ima_adpcm.loop_predictor=0;
+ ima_adpcm.last_nibble=-1;
+ ima_adpcm.loop_pos=0x7FFFFFFF;
+ ima_adpcm.window_ofs=0;
+ ima_adpcm.ptr=NULL;
+
+
+ for(int i=0;i<w;i++) {
+
+ float max[2]={-1e10,-1e10};
+ float min[2]={1e10,1e10};
+ int from = i*len/w;
+ int to = (i+1)*len/w;
+ if (to>=len)
+ to=len-1;
+
+ for(int j=from;j<to;j++) {
+
+ while(j>ima_adpcm.last_nibble) {
+
+ static const int16_t _ima_adpcm_step_table[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+ };
+
+ static const int8_t _ima_adpcm_index_table[16] = {
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+ };
+
+ int16_t nibble,signed_nibble,diff,step;
+
+ ima_adpcm.last_nibble++;
+ const uint8_t *src_ptr=sdata;
+
+ nibble = (ima_adpcm.last_nibble&1)?
+ (src_ptr[ima_adpcm.last_nibble>>1]>>4):(src_ptr[ima_adpcm.last_nibble>>1]&0xF);
+ step=_ima_adpcm_step_table[ima_adpcm.step_index];
+
+ ima_adpcm.step_index += _ima_adpcm_index_table[nibble];
+ if (ima_adpcm.step_index<0)
+ ima_adpcm.step_index=0;
+ if (ima_adpcm.step_index>88)
+ ima_adpcm.step_index=88;
+
+ /*
+ signed_nibble = (nibble&7) * ((nibble&8)?-1:1);
+ diff = (2 * signed_nibble + 1) * step / 4; */
+
+ diff = step >> 3 ;
+ if (nibble & 1)
+ diff += step >> 2 ;
+ if (nibble & 2)
+ diff += step >> 1 ;
+ if (nibble & 4)
+ diff += step ;
+ if (nibble & 8)
+ diff = -diff ;
+
+ ima_adpcm.predictor+=diff;
+ if (ima_adpcm.predictor<-0x8000)
+ ima_adpcm.predictor=-0x8000;
+ else if (ima_adpcm.predictor>0x7FFF)
+ ima_adpcm.predictor=0x7FFF;
+
+
+ /* store loop if there */
+ if (ima_adpcm.last_nibble==ima_adpcm.loop_pos) {
+
+ ima_adpcm.loop_step_index = ima_adpcm.step_index;
+ ima_adpcm.loop_predictor = ima_adpcm.predictor;
+ }
+
+ }
+
+ float v=ima_adpcm.predictor/32767.0;
+ if (v>max[0])
+ max[0]=v;
+ if (v<min[0])
+ min[0]=v;
+ }
+ max[0]*=0.8;
+ min[0]*=0.8;
+
+ for(int j=0;j<h;j++) {
+ float v = (j/(float)h) * 2.0 - 1.0;
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[0] && v<max[0]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+ }
+ } else {
+ for(int i=0;i<w;i++) {
+ // i trust gcc will optimize this loop
+ float max[2]={-1e10,-1e10};
+ float min[2]={1e10,1e10};
+ int c=stereo?2:1;
+ int from = i*len/w;
+ int to = (i+1)*len/w;
+ if (to>=len)
+ to=len-1;
+
+ if (_16) {
+ const int16_t*src =(const int16_t*)sdata;
+
+ for(int j=0;j<c;j++) {
+
+ for(int k=from;k<=to;k++) {
+
+ float v = src[k*c+j]/32768.0;
+ if (v>max[j])
+ max[j]=v;
+ if (v<min[j])
+ min[j]=v;
+ }
+
+ }
+ } else {
+
+ const int8_t*src =(const int8_t*)sdata;
+
+ for(int j=0;j<c;j++) {
+
+ for(int k=from;k<=to;k++) {
+
+ float v = src[k*c+j]/128.0;
+ if (v>max[j])
+ max[j]=v;
+ if (v<min[j])
+ min[j]=v;
+ }
+
+ }
+ }
+
+ max[0]*=0.8;
+ max[1]*=0.8;
+ min[0]*=0.8;
+ min[1]*=0.8;
+
+ if (!stereo) {
+ for(int j=0;j<h;j++) {
+ float v = (j/(float)h) * 2.0 - 1.0;
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[0] && v<max[0]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+ } else {
+
+ for(int j=0;j<h;j++) {
+
+ int half,ofs;
+ float v;
+ if (j<(h/2)) {
+ half=0;
+ ofs=0;
+ v = (j/(float)(h/2)) * 2.0 - 1.0;
+ } else {
+ half=1;
+ ofs=h/2;
+ v = ((j-(h/2))/(float)(h/2)) * 2.0 - 1.0;
+ }
+
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[half] && v<max[half]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+
+ }
+
+ }
+ }
+
+ imgdata = DVector<uint8_t>::Write();
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture));
+ ptex->create_from_image(Image(w,h,0,Image::FORMAT_RGB,img),0);
+ return ptex;
+
+}
+
+EditorSamplePreviewPlugin::EditorSamplePreviewPlugin() {
+
+
+}
+
+///////////////////////////////////////////////////////////////////////////
diff --git a/tools/editor/plugins/editor_preview_plugins.h b/tools/editor/plugins/editor_preview_plugins.h
new file mode 100644
index 0000000000..fc42ebfc0e
--- /dev/null
+++ b/tools/editor/plugins/editor_preview_plugins.h
@@ -0,0 +1,69 @@
+#ifndef EDITORPREVIEWPLUGINS_H
+#define EDITORPREVIEWPLUGINS_H
+
+#include "tools/editor/editor_resource_preview.h"
+
+class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorTexturePreviewPlugin();
+};
+
+
+class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator {
+
+ Ref<Texture> _gen_from_imd(Ref<ResourceImportMetadata> p_imd);
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+ virtual Ref<Texture> generate_from_path(const String& p_path);
+
+ EditorPackedScenePreviewPlugin();
+};
+
+class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
+
+ RID scenario;
+ RID sphere;
+ RID sphere_instance;
+ RID viewport;
+ RID light;
+ RID light_instance;
+ RID light2;
+ RID light_instance2;
+ RID camera;
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorMaterialPreviewPlugin();
+ ~EditorMaterialPreviewPlugin();
+};
+
+class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator {
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorScriptPreviewPlugin();
+};
+
+
+class EditorSamplePreviewPlugin : public EditorResourcePreviewGenerator {
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorSamplePreviewPlugin();
+};
+
+
+
+#endif // EDITORPREVIEWPLUGINS_H
diff --git a/tools/editor/plugins/sample_editor_plugin.cpp b/tools/editor/plugins/sample_editor_plugin.cpp
index 3219935688..31fa7246ae 100644
--- a/tools/editor/plugins/sample_editor_plugin.cpp
+++ b/tools/editor/plugins/sample_editor_plugin.cpp
@@ -98,6 +98,125 @@ void SampleEditor::generate_preview_texture(const Ref<Sample>& p_sample,Ref<Imag
if (p_sample->get_format()==Sample::FORMAT_IMA_ADPCM) {
+ struct IMA_ADPCM_State {
+
+ int16_t step_index;
+ int32_t predictor;
+ /* values at loop point */
+ int16_t loop_step_index;
+ int32_t loop_predictor;
+ int32_t last_nibble;
+ int32_t loop_pos;
+ int32_t window_ofs;
+ const uint8_t *ptr;
+ } ima_adpcm;
+
+ ima_adpcm.step_index=0;
+ ima_adpcm.predictor=0;
+ ima_adpcm.loop_step_index=0;
+ ima_adpcm.loop_predictor=0;
+ ima_adpcm.last_nibble=-1;
+ ima_adpcm.loop_pos=0x7FFFFFFF;
+ ima_adpcm.window_ofs=0;
+ ima_adpcm.ptr=NULL;
+
+
+ for(int i=0;i<w;i++) {
+
+ float max[2]={-1e10,-1e10};
+ float min[2]={1e10,1e10};
+ int from = i*len/w;
+ int to = (i+1)*len/w;
+ if (to>=len)
+ to=len-1;
+
+ for(int j=from;j<to;j++) {
+
+ while(j>ima_adpcm.last_nibble) {
+
+ static const int16_t _ima_adpcm_step_table[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+ };
+
+ static const int8_t _ima_adpcm_index_table[16] = {
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+ };
+
+ int16_t nibble,signed_nibble,diff,step;
+
+ ima_adpcm.last_nibble++;
+ const uint8_t *src_ptr=sdata;
+
+ nibble = (ima_adpcm.last_nibble&1)?
+ (src_ptr[ima_adpcm.last_nibble>>1]>>4):(src_ptr[ima_adpcm.last_nibble>>1]&0xF);
+ step=_ima_adpcm_step_table[ima_adpcm.step_index];
+
+ ima_adpcm.step_index += _ima_adpcm_index_table[nibble];
+ if (ima_adpcm.step_index<0)
+ ima_adpcm.step_index=0;
+ if (ima_adpcm.step_index>88)
+ ima_adpcm.step_index=88;
+
+ /*
+ signed_nibble = (nibble&7) * ((nibble&8)?-1:1);
+ diff = (2 * signed_nibble + 1) * step / 4; */
+
+ diff = step >> 3 ;
+ if (nibble & 1)
+ diff += step >> 2 ;
+ if (nibble & 2)
+ diff += step >> 1 ;
+ if (nibble & 4)
+ diff += step ;
+ if (nibble & 8)
+ diff = -diff ;
+
+ ima_adpcm.predictor+=diff;
+ if (ima_adpcm.predictor<-0x8000)
+ ima_adpcm.predictor=-0x8000;
+ else if (ima_adpcm.predictor>0x7FFF)
+ ima_adpcm.predictor=0x7FFF;
+
+
+ /* store loop if there */
+ if (ima_adpcm.last_nibble==ima_adpcm.loop_pos) {
+
+ ima_adpcm.loop_step_index = ima_adpcm.step_index;
+ ima_adpcm.loop_predictor = ima_adpcm.predictor;
+ }
+
+ }
+
+ float v=ima_adpcm.predictor/32767.0;
+ if (v>max[0])
+ max[0]=v;
+ if (v<min[0])
+ min[0]=v;
+ }
+
+ for(int j=0;j<h;j++) {
+ float v = (j/(float)h) * 2.0 - 1.0;
+ uint8_t* imgofs = &imgw[(j*w+i)*3];
+ if (v>min[0] && v<max[0]) {
+ imgofs[0]=255;
+ imgofs[1]=150;
+ imgofs[2]=80;
+ } else {
+ imgofs[0]=0;
+ imgofs[1]=0;
+ imgofs[2]=0;
+ }
+ }
+ }
} else {
for(int i=0;i<w;i++) {
// i trust gcc will optimize this loop
diff --git a/tools/editor/plugins/spatial_editor_plugin.h b/tools/editor/plugins/spatial_editor_plugin.h
index b890f285ee..ff8912fca8 100644
--- a/tools/editor/plugins/spatial_editor_plugin.h
+++ b/tools/editor/plugins/spatial_editor_plugin.h
@@ -239,7 +239,7 @@ public:
void set_state(const Dictionary& p_state);
Dictionary get_state() const;
void reset();
-
+ Viewport *get_viewport_node() { return viewport; }
SpatialEditorViewport(SpatialEditor *p_spatial_editor,EditorNode *p_editor,int p_index);
@@ -422,6 +422,7 @@ private:
HBoxContainer *hbc_menu;
+
//
//
void _generate_selection_box();
@@ -514,6 +515,11 @@ public:
void set_can_preview(Camera* p_preview);
+ SpatialEditorViewport *get_editor_viewport(int p_idx) {
+ ERR_FAIL_INDEX_V(p_idx,4,NULL);
+ return viewports[p_idx];
+ }
+
Camera *get_camera() { return NULL; }
void edit(Spatial *p_spatial);
void clear();
diff --git a/tools/editor/resources_dock.cpp b/tools/editor/resources_dock.cpp
index 33ec1f2054..b69eec4a51 100644
--- a/tools/editor/resources_dock.cpp
+++ b/tools/editor/resources_dock.cpp
@@ -152,7 +152,7 @@ void ResourcesDock::save_resource_as(const Ref<Resource>& p_resource) {
List<String> extensions;
ResourceSaver::get_recognized_extensions(res,&extensions);
- file->set_mode(FileDialog::MODE_SAVE_FILE);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
if (p_resource->get_path()!="" && p_resource->get_path().find("::")==-1) {
@@ -396,7 +396,7 @@ ResourcesDock::ResourcesDock(EditorNode *p_editor) {
accept = memnew (AcceptDialog);
add_child(accept);
- file = memnew( FileDialog );
+ file = memnew( EditorFileDialog );
add_child(file);
file->connect("file_selected",this,"_file_action");
diff --git a/tools/editor/resources_dock.h b/tools/editor/resources_dock.h
index a94579240e..933b457b29 100644
--- a/tools/editor/resources_dock.h
+++ b/tools/editor/resources_dock.h
@@ -38,6 +38,7 @@
#include "scene/gui/menu_button.h"
#include "scene/gui/file_dialog.h"
#include "create_dialog.h"
+#include "editor_file_dialog.h"
class EditorNode;
@@ -68,7 +69,7 @@ class ResourcesDock : public VBoxContainer {
CreateDialog *create_dialog;
AcceptDialog *accept;
- FileDialog *file;
+ EditorFileDialog *file;
Tree *resources;
bool block_add;
int current_action;