diff options
Diffstat (limited to 'tools')
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 Binary files differnew file mode 100644 index 0000000000..5d20cd99ec --- /dev/null +++ b/tools/editor/icons/icon_wait_no_preview.png diff --git a/tools/editor/icons/icon_wait_preview_1.png b/tools/editor/icons/icon_wait_preview_1.png Binary files differnew file mode 100644 index 0000000000..0aab42e04a --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_1.png diff --git a/tools/editor/icons/icon_wait_preview_2.png b/tools/editor/icons/icon_wait_preview_2.png Binary files differnew file mode 100644 index 0000000000..f476b9ce1f --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_2.png diff --git a/tools/editor/icons/icon_wait_preview_3.png b/tools/editor/icons/icon_wait_preview_3.png Binary files differnew file mode 100644 index 0000000000..2775d1ef43 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_3.png diff --git a/tools/editor/icons/icon_wait_preview_4.png b/tools/editor/icons/icon_wait_preview_4.png Binary files differnew file mode 100644 index 0000000000..2eaa86fec9 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_4.png diff --git a/tools/editor/icons/icon_wait_preview_5.png b/tools/editor/icons/icon_wait_preview_5.png Binary files differnew file mode 100644 index 0000000000..6590644bc1 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_5.png diff --git a/tools/editor/icons/icon_wait_preview_6.png b/tools/editor/icons/icon_wait_preview_6.png Binary files differnew file mode 100644 index 0000000000..307e412310 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_6.png diff --git a/tools/editor/icons/icon_wait_preview_7.png b/tools/editor/icons/icon_wait_preview_7.png Binary files differnew file mode 100644 index 0000000000..b0edc94d93 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_7.png diff --git a/tools/editor/icons/icon_wait_preview_8.png b/tools/editor/icons/icon_wait_preview_8.png Binary files differnew file mode 100644 index 0000000000..67a2f48ec3 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_8.png 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; |