summaryrefslogtreecommitdiff
path: root/tools/editor
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2015-06-06 11:09:00 -0300
committerJuan Linietsky <reduzio@gmail.com>2015-06-06 11:09:00 -0300
commit954256268afe89b648d356ee0b296a9e97a07373 (patch)
tree36c42fb01f05d26bbae438d470676c9487b47a04 /tools/editor
parent0e1510214a7585d5446f06344468ab52298cfa81 (diff)
parentab99671bb835a5fe24a092ec34afe1ad862ac254 (diff)
Merge branch 'master' of https://github.com/okamstudio/godot
Conflicts: demos/2d/motion/engine.cfg
Diffstat (limited to 'tools/editor')
-rw-r--r--tools/editor/animation_editor.cpp535
-rw-r--r--tools/editor/animation_editor.h29
-rw-r--r--tools/editor/editor_file_dialog.cpp874
-rw-r--r--tools/editor/editor_file_dialog.h198
-rw-r--r--tools/editor/editor_file_system.cpp1
-rw-r--r--tools/editor/editor_node.cpp161
-rw-r--r--tools/editor/editor_node.h14
-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_curve_constant.pngbin0 -> 222 bytes
-rw-r--r--tools/editor/icons/icon_curve_in.pngbin0 -> 319 bytes
-rw-r--r--tools/editor/icons/icon_curve_in_out.pngbin0 -> 326 bytes
-rw-r--r--tools/editor/icons/icon_curve_linear.pngbin0 -> 275 bytes
-rw-r--r--tools/editor/icons/icon_curve_out.pngbin0 -> 319 bytes
-rw-r--r--tools/editor/icons/icon_curve_out_in.pngbin0 -> 318 bytes
-rw-r--r--tools/editor/icons/icon_key_next.pngbin0 -> 499 bytes
-rw-r--r--tools/editor/icons/icon_pause.pngbin367 -> 228 bytes
-rw-r--r--tools/editor/icons/icon_play.pngbin256 -> 260 bytes
-rw-r--r--tools/editor/icons/icon_play_backwards.pngbin0 -> 256 bytes
-rw-r--r--tools/editor/icons/icon_play_start.pngbin0 -> 282 bytes
-rw-r--r--tools/editor/icons/icon_play_start_backwards.pngbin0 -> 289 bytes
-rw-r--r--tools/editor/icons/icon_stop.pngbin138 -> 236 bytes
-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/io_plugins/editor_sample_import_plugin.cpp5
-rw-r--r--tools/editor/io_plugins/editor_scene_import_plugin.cpp5
-rw-r--r--tools/editor/io_plugins/editor_texture_import_plugin.cpp367
-rw-r--r--tools/editor/io_plugins/editor_texture_import_plugin.h8
-rw-r--r--tools/editor/plugins/animation_player_editor_plugin.cpp259
-rw-r--r--tools/editor/plugins/animation_player_editor_plugin.h15
-rw-r--r--tools/editor/plugins/editor_preview_plugins.cpp776
-rw-r--r--tools/editor/plugins/editor_preview_plugins.h88
-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/property_editor.cpp28
-rw-r--r--tools/editor/property_editor.h1
-rw-r--r--tools/editor/resources_dock.cpp4
-rw-r--r--tools/editor/resources_dock.h3
46 files changed, 3705 insertions, 150 deletions
diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp
index 63ab186a38..bb6f7e9a6f 100644
--- a/tools/editor/animation_editor.cpp
+++ b/tools/editor/animation_editor.cpp
@@ -44,11 +44,207 @@
*/
+class AnimationCurveEdit : public Control {
+ OBJ_TYPE( AnimationCurveEdit, Control );
+public:
+ enum Mode {
+ MODE_DISABLED,
+ MODE_SINGLE,
+ MODE_MULTIPLE
+ };
+private:
+
+ Set<float> multiples;
+ float transition;
+ Mode mode;
+
+ void _notification(int p_what) {
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+
+ RID ci = get_canvas_item();
+
+ Size2 s = get_size();
+ Rect2 r(Point2(),s);
+
+ //r=r.grow(3);
+ Ref<StyleBox> sb = get_stylebox("normal","LineEdit");
+ sb->draw(ci,r);
+ r.size-=sb->get_minimum_size();
+ r.pos+=sb->get_offset();
+ //VisualServer::get_singleton()->canvas_item_add
+
+ Ref<Font> f = get_font("font","Label");
+ r=r.grow(-2);
+ Color color = get_color("font_color","Label");
+
+ int points = 48;
+ if (mode==MODE_MULTIPLE) {
+
+ int max_draw = 16;
+ Color mcolor=color;
+ mcolor.a*=0.3;
+
+ Set<float>::Element *E=multiples.front();
+ for(int j=0;j<16;j++) {
+
+ if (!E)
+ break;
+
+ float prev=1.0;
+ float exp=E->get();
+ bool flip=false;//hint_text=="attenuation";
+
+
+ for(int i=1;i<=points;i++) {
+
+ float ifl = i/float(points);
+ float iflp = (i-1)/float(points);
+
+ float h = 1.0-Math::ease(ifl,exp);
+
+ if (flip) {
+ ifl=1.0-ifl;
+ iflp=1.0-iflp;
+ }
+
+ VisualServer::get_singleton()->canvas_item_add_line(ci,r.pos+Point2(iflp*r.size.width,prev*r.size.height),r.pos+Point2(ifl*r.size.width,h*r.size.height),mcolor);
+ prev=h;
+ }
+
+ E=E->next();
+ }
+ }
+
+ float exp=transition;
+ if (mode!=MODE_DISABLED) {
+
+
+ float prev=1.0;
+
+ bool flip=false;//hint_text=="attenuation";
+
+
+ for(int i=1;i<=points;i++) {
+
+ float ifl = i/float(points);
+ float iflp = (i-1)/float(points);
+
+ float h = 1.0-Math::ease(ifl,exp);
+
+ if (flip) {
+ ifl=1.0-ifl;
+ iflp=1.0-iflp;
+ }
+
+ VisualServer::get_singleton()->canvas_item_add_line(ci,r.pos+Point2(iflp*r.size.width,prev*r.size.height),r.pos+Point2(ifl*r.size.width,h*r.size.height),color);
+ prev=h;
+ }
+ }
+
+ String txt=String::num(exp,2);
+ if (mode==MODE_DISABLED) {
+ txt="Disabled";
+ } else if (mode==MODE_MULTIPLE) {
+ txt+=" - All Selection";
+ }
+
+ f->draw(ci,Point2(10,10+f->get_ascent()),txt,color);
+
+ }
+ }
+
+ void _input_event(const InputEvent& p_ev) {
+ if (p_ev.type==InputEvent::MOUSE_MOTION && p_ev.mouse_motion.button_mask&BUTTON_MASK_LEFT) {
+
+ if (mode==MODE_DISABLED)
+ return;
+
+ float rel = p_ev.mouse_motion.relative_x;
+ if (rel==0)
+ return;
+
+ bool flip=false;
+
+ if (flip)
+ rel=-rel;
+
+ float val = transition;
+ if (val==0)
+ return;
+ bool sg = val < 0;
+ val = Math::absf(val);
+
+ val = Math::log(val)/Math::log(2);
+ //logspace
+ val+=rel*0.05;
+ //
+
+ val = Math::pow(2,val);
+ if (sg)
+ val=-val;
+
+ transition=val;
+ update();
+ //emit_signal("variant_changed");
+ emit_signal("transition_changed",transition);
+ }
+ }
+
+public:
+
+ static void _bind_methods() {
+
+ // ObjectTypeDB::bind_method("_update_obj",&AnimationKeyEdit::_update_obj);
+ ObjectTypeDB::bind_method("_input_event",&AnimationCurveEdit::_input_event);
+ ADD_SIGNAL(MethodInfo("transition_changed"));
+ }
+
+ void set_mode(Mode p_mode) {
+
+ mode=p_mode;
+ update();
+ }
+
+ void clear_multiples() { multiples.clear(); update();}
+ void set_multiple(float p_transition) {
+
+ multiples.insert(p_transition);
+ }
+
+ void set_transition(float p_transition) {
+ transition=p_transition;
+ update();
+ }
+
+ float get_transition() const {
+ return transition;
+ }
+
+ void force_transition(float p_value) {
+ if (mode==MODE_DISABLED)
+ return;
+ transition=p_value;
+ emit_signal("transition_changed",p_value);
+ update();
+ }
+
+ AnimationCurveEdit() {
+
+ transition=1.0;
+ set_default_cursor_shape(CURSOR_HSPLIT);
+ mode=MODE_DISABLED;
+ }
+
+};
+
class AnimationKeyEdit : public Object {
OBJ_TYPE(AnimationKeyEdit,Object);
public:
bool setting;
+ bool hidden;
static void _bind_methods() {
@@ -56,12 +252,12 @@ public:
ObjectTypeDB::bind_method("_key_ofs_changed",&AnimationKeyEdit::_key_ofs_changed);
}
- PopupDialog *ke_dialog;
+ //PopupDialog *ke_dialog;
void _update_obj(const Ref<Animation> &p_anim) {
if (setting)
return;
- if (!ke_dialog->is_visible())
+ if (hidden)
return;
if (!(animation==p_anim))
return;
@@ -69,7 +265,7 @@ public:
}
void _key_ofs_changed(const Ref<Animation> &p_anim,float from, float to) {
- if (!ke_dialog->is_visible())
+ if (hidden)
return;
if (!(animation==p_anim))
return;
@@ -408,8 +604,8 @@ public:
} break;
}
- if (animation->track_get_type(track)!=Animation::TYPE_METHOD)
- p_list->push_back( PropertyInfo( Variant::REAL, "easing", PROPERTY_HINT_EXP_EASING));
+ //if (animation->track_get_type(track)!=Animation::TYPE_METHOD)
+ // p_list->push_back( PropertyInfo( Variant::REAL, "easing", PROPERTY_HINT_EXP_EASING));
}
UndoRedo *undo_redo;
@@ -425,7 +621,7 @@ public:
_change_notify();
}
- AnimationKeyEdit() { key_ofs=0; track=-1; setting=false; }
+ AnimationKeyEdit() { hidden=true; key_ofs=0; track=-1; setting=false; }
};
@@ -610,6 +806,8 @@ void AnimationKeyEditor::_menu_track(int p_type) {
selection=new_selection;
track_editor->update();
+ _edit_if_single_selection();
+
}
@@ -689,8 +887,31 @@ void AnimationKeyEditor::_menu_track(int p_type) {
optimize_dialog->popup_centered(Size2(250,180));
} break;
+ case CURVE_SET_LINEAR: {
+ curve_edit->force_transition(1.0);
+ } break;
+ case CURVE_SET_IN: {
+
+ curve_edit->force_transition(4.0);
+
+ } break;
+ case CURVE_SET_OUT: {
+
+ curve_edit->force_transition(0.25);
+ } break;
+ case CURVE_SET_INOUT: {
+ curve_edit->force_transition(-4);
+
+ } break;
+ case CURVE_SET_OUTIN: {
+
+ curve_edit->force_transition(-0.25);
+ } break;
+ case CURVE_SET_CONSTANT: {
+ curve_edit->force_transition(0);
+ } break;
}
@@ -774,6 +995,7 @@ void AnimationKeyEditor::_track_editor_draw() {
h_scroll->hide();
menu_track->set_disabled(true);
edit_button->set_disabled(true);
+ key_editor_tab->hide();
move_up_button->set_disabled(true);
move_down_button->set_disabled(true);
remove_button->set_disabled(true);
@@ -785,6 +1007,8 @@ void AnimationKeyEditor::_track_editor_draw() {
move_up_button->set_disabled(false);
move_down_button->set_disabled(false);
remove_button->set_disabled(false);
+ if (edit_button->is_pressed())
+ key_editor_tab->show();
te_drawing=true;
@@ -1000,8 +1224,13 @@ void AnimationKeyEditor::_track_editor_draw() {
}
}
+ Color sep_color=color;
+ color.a*=0.5;
+
for(int i=0;i<fit;i++) {
+ //this code sucks, i always forget how it works
+
int idx = v_scroll->get_val() + i;
if (idx>=animation->get_track_count())
break;
@@ -1090,6 +1319,7 @@ void AnimationKeyEditor::_track_editor_draw() {
float key_hofs = -Math::floor(type_icon[tt]->get_height()/2);
int kc=animation->track_get_key_count(idx);
+ bool first=true;
for(int i=0;i<kc;i++) {
@@ -1097,8 +1327,16 @@ void AnimationKeyEditor::_track_editor_draw() {
float time = animation->track_get_key_time(idx,i);
if (time<keys_from)
continue;
- if (time>keys_to)
+ if (time>keys_to) {
+
+ if (first && i>0 && animation->track_get_key_value(idx,i)==animation->track_get_key_value(idx,i-1)) {
+ //draw whole line
+ te->draw_line(ofs+Vector2(name_limit,y+h/2),ofs+Point2(settings_limit,y+h/2),color);
+ }
+
break;
+ }
+
float x = key_hofs + name_limit + (time-keys_from)*zoom_scale;
Ref<Texture> tex = type_icon[tt];
@@ -1116,7 +1354,22 @@ void AnimationKeyEditor::_track_editor_draw() {
if (mouse_over.over==MouseOver::OVER_KEY && mouse_over.track==idx && mouse_over.over_key==i)
tex=type_hover;
+ Variant value = animation->track_get_key_value(idx,i);
+ if (first && i>0 && value==animation->track_get_key_value(idx,i-1)) {
+
+ te->draw_line(ofs+Vector2(name_limit,y+h/2),ofs+Point2(x,y+h/2),color);
+ }
+
+ if (i<kc-1 && value==animation->track_get_key_value(idx,i+1)) {
+ float x_n = key_hofs + name_limit + (animation->track_get_key_time(idx,i+1)-keys_from)*zoom_scale;
+
+ x_n = MIN( x_n, settings_limit);
+ te->draw_line(ofs+Point2(x_n,y+h/2),ofs+Point2(x,y+h/2),color);
+
+ }
+
te->draw_texture(tex,ofs+Point2(x,y+key_vofs).floor());
+ first=false;
}
}
@@ -1226,7 +1479,9 @@ void AnimationKeyEditor::_clear_selection_for_anim(const Ref<Animation>& p_anim)
if (!(animation==p_anim))
return;
- selection.clear();
+ //selection.clear();
+ _clear_selection();
+
}
void AnimationKeyEditor::_select_at_anim(const Ref<Animation>& p_anim,int p_track,float p_pos){
@@ -1244,6 +1499,7 @@ void AnimationKeyEditor::_select_at_anim(const Ref<Animation>& p_anim,int p_trac
ki.pos=p_pos;
selection.insert(sk,ki);
+
}
@@ -1283,6 +1539,83 @@ PropertyInfo AnimationKeyEditor::_find_hint_for_track(int p_idx) {
}
+void AnimationKeyEditor::_curve_transition_changed(float p_what) {
+
+ if (selection.size()==0)
+ return;
+ if (selection.size()==1)
+ undo_redo->create_action("Edit Node Curve",true);
+ else
+ undo_redo->create_action("Edit Selection Curve",true);
+
+ for(Map<SelectedKey,KeyInfo>::Element *E=selection.front();E;E=E->next()) {
+
+ int track = E->key().track;
+ int key = E->key().key;
+ float prev_val = animation->track_get_key_transition(track,key);
+ undo_redo->add_do_method(animation.ptr(),"track_set_key_transition",track,key,p_what);
+ undo_redo->add_undo_method(animation.ptr(),"track_set_key_transition",track,key,prev_val);
+ }
+
+ undo_redo->commit_action();
+
+}
+
+void AnimationKeyEditor::_toggle_edit_curves() {
+
+ if (edit_button->is_pressed())
+ key_editor_tab->show();
+ else
+ key_editor_tab->hide();
+}
+
+
+bool AnimationKeyEditor::_edit_if_single_selection() {
+
+ if (selection.size()!=1) {
+
+ if (selection.size()==0) {
+ curve_edit->set_mode(AnimationCurveEdit::MODE_DISABLED);
+ print_line("disable");
+ } else {
+
+ curve_edit->set_mode(AnimationCurveEdit::MODE_MULTIPLE);
+ curve_edit->set_transition(1.0);
+ curve_edit->clear_multiples();
+ //add all
+ for(Map<SelectedKey,KeyInfo>::Element *E=selection.front();E;E=E->next()) {
+
+ curve_edit->set_multiple(animation->track_get_key_transition(E->key().track,E->key().key));
+ }
+ print_line("multiple");
+
+ }
+ return false;
+ }
+ curve_edit->set_mode(AnimationCurveEdit::MODE_SINGLE);
+ print_line("regular");
+
+ int idx = selection.front()->key().track;
+ int key = selection.front()->key().key;
+ {
+
+ key_edit->animation=animation;
+ key_edit->track=idx;
+ key_edit->key_ofs=animation->track_get_key_time(idx,key);
+ key_edit->hint=_find_hint_for_track(idx);
+ key_edit->notify_change();
+
+ curve_edit->set_transition(animation->track_get_key_transition(idx,key));
+
+ /*key_edit_dialog->set_size( Size2( 200,200) );
+ key_edit_dialog->set_pos( track_editor->get_global_pos() + ofs + mpos +Point2(-100,20));
+ key_edit_dialog->popup();*/
+
+ }
+
+ return true;
+
+}
void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
@@ -1364,9 +1697,12 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
undo_redo->add_undo_method(animation.ptr(),"track_insert_key",E->key().track,E->get().pos,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key));
}
+ undo_redo->add_do_method(this,"_clear_selection_for_anim",animation);
+ undo_redo->add_undo_method(this,"_clear_selection_for_anim",animation);
undo_redo->commit_action();
- selection.clear();
+ //selection.clear();
accept_event();
+ _edit_if_single_selection();
}
} else if (animation.is_valid() && animation->get_track_count()>0) {
@@ -1552,20 +1888,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
}
- if (mb.mod.command || edit_button->is_pressed()) {
-
- key_edit->animation=animation;
- key_edit->track=idx;
- key_edit->key_ofs=animation->track_get_key_time(idx,key);
- key_edit->hint=_find_hint_for_track(idx);
- key_edit->notify_change();
-
- key_edit_dialog->set_size( Size2( 200,200) );
- key_edit_dialog->set_pos( track_editor->get_global_pos() + ofs + mpos +Point2(-100,20));
- key_edit_dialog->popup();
-
- }
SelectedKey sk;
sk.track=idx;
@@ -1577,7 +1900,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
if (!mb.mod.shift && !selection.has(sk))
- selection.clear();
+ _clear_selection();
selection.insert(sk,ki);
@@ -1588,7 +1911,10 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
selected_track=idx;
track_editor->update();
-
+ if (_edit_if_single_selection() && mb.mod.command) {
+ edit_button->set_pressed(true);
+ key_editor_tab->show();
+ }
} else {
//button column
int ofsx = size.width - mpos.x;
@@ -1824,7 +2150,8 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
if (from_track>to_track) {
if (!click.shift)
- selection.clear();
+ _clear_selection();
+ _edit_if_single_selection();
break;
}
@@ -1842,12 +2169,13 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
if (from_track > tracks_to || to_track < tracks_from) {
if (!click.shift)
- selection.clear();
+ _clear_selection();
+ _edit_if_single_selection();
break;
}
if (!click.shift)
- selection.clear();
+ _clear_selection();
int higher_track=0x7FFFFFFF;
@@ -1880,6 +2208,8 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
}
+ _edit_if_single_selection();
+
} break;
case ClickOver::CLICK_MOVE_KEYS: {
@@ -1891,8 +2221,9 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
if (!click.shift) {
KeyInfo ki=selection[click.selk];
- selection.clear();
+ _clear_selection();
selection[click.selk]=ki;
+ _edit_if_single_selection();
}
break;
@@ -2007,6 +2338,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
}
undo_redo->commit_action();
+ _edit_if_single_selection();
} break;
default: {}
@@ -2348,20 +2680,33 @@ void AnimationKeyEditor::_notification(int p_what) {
optimize_dialog->connect("confirmed",this,"_animation_optimize");
menu_track->get_popup()->add_child(tpp);
- menu_track->get_popup()->add_submenu_item("Set Transitions..","Transitions");
- menu_track->get_popup()->add_separator();
+ //menu_track->get_popup()->add_submenu_item("Set Transitions..","Transitions");
+ //menu_track->get_popup()->add_separator();
menu_track->get_popup()->add_item("Optimize Animation",TRACK_MENU_OPTIMIZE);
+ curve_linear->set_icon(get_icon("CurveLinear","EditorIcons"));
+ curve_in->set_icon(get_icon("CurveIn","EditorIcons"));
+ curve_out->set_icon(get_icon("CurveOut","EditorIcons"));
+ curve_inout->set_icon(get_icon("CurveInOut","EditorIcons"));
+ curve_outin->set_icon(get_icon("CurveOutIn","EditorIcons"));
+ curve_constant->set_icon(get_icon("CurveConstant","EditorIcons"));
-
+ curve_linear->connect("pressed",this,"_menu_track",varray(CURVE_SET_LINEAR));
+ curve_in->connect("pressed",this,"_menu_track",varray(CURVE_SET_IN));
+ curve_out->connect("pressed",this,"_menu_track",varray(CURVE_SET_OUT));
+ curve_inout->connect("pressed",this,"_menu_track",varray(CURVE_SET_INOUT));
+ curve_outin->connect("pressed",this,"_menu_track",varray(CURVE_SET_OUTIN));
+ curve_constant->connect("pressed",this,"_menu_track",varray(CURVE_SET_CONSTANT));
move_up_button->set_icon(get_icon("MoveUp","EditorIcons"));
move_down_button->set_icon(get_icon("MoveDown","EditorIcons"));
remove_button->set_icon(get_icon("Remove","EditorIcons"));
edit_button->set_icon(get_icon("EditKey","EditorIcons"));
+ edit_button->connect("pressed",this,"_toggle_edit_curves");
loop->set_icon(get_icon("Loop","EditorIcons"));
+ curve_edit->connect("transition_changed",this,"_curve_transition_changed");
//edit_button->add_color_override("font_color",get_color("font_color","Tree"));
//edit_button->add_color_override("font_color_hover",get_color("font_color","Tree"));
@@ -2456,6 +2801,17 @@ void AnimationKeyEditor::_update_menu() {
updating=false;
}
+void AnimationKeyEditor::_clear_selection() {
+
+ selection.clear();
+ key_edit->animation=Ref<Animation>();
+ key_edit->track=0;
+ key_edit->key_ofs=0;
+ key_edit->hint=PropertyInfo();
+ key_edit->notify_change();
+
+}
+
void AnimationKeyEditor::set_animation(const Ref<Animation>& p_anim) {
@@ -2466,11 +2822,12 @@ void AnimationKeyEditor::set_animation(const Ref<Animation>& p_anim) {
animation->connect("changed",this,"_update_paths");
timeline_pos=0;
- selection.clear();
+ _clear_selection();
_update_paths();
_update_menu();
selected_track=-1;
+ _edit_if_single_selection();
}
void AnimationKeyEditor::set_root(Node *p_root) {
@@ -2591,6 +2948,7 @@ void AnimationKeyEditor::insert_transform_key(Spatial *p_node,const String& p_su
id.value=p_xform;
id.type=Animation::TYPE_TRANSFORM;
id.query="node '"+p_node->get_name()+"'";
+ id.advance=false;
//dialog insert
@@ -2643,6 +3001,7 @@ void AnimationKeyEditor::insert_node_value_key(Node* p_node, const String& p_pro
id.value=p_value;
id.type=Animation::TYPE_VALUE;
id.query="property '"+p_property+"'";
+ id.advance=false;
//dialog insert
_query_insert(id);
@@ -2650,7 +3009,7 @@ void AnimationKeyEditor::insert_node_value_key(Node* p_node, const String& p_pro
}
-void AnimationKeyEditor::insert_value_key(const String& p_property,const Variant& p_value) {
+void AnimationKeyEditor::insert_value_key(const String& p_property,const Variant& p_value,bool p_advance) {
ERR_FAIL_COND(!root);
//let's build a node path
@@ -2696,6 +3055,7 @@ void AnimationKeyEditor::insert_value_key(const String& p_property,const Variant
id.value=p_value;
id.type=Animation::TYPE_VALUE;
id.query="property '"+p_property+"'";
+ id.advance=p_advance;
//dialog insert
_query_insert(id);
@@ -2928,13 +3288,31 @@ void AnimationKeyEditor::_insert_delay() {
undo_redo->create_action("Anim Insert");
int last_track = animation->get_track_count();
+ bool advance=false;
while(insert_data.size()) {
+ if (insert_data.front()->get().advance)
+ advance=true;
last_track=_confirm_insert(insert_data.front()->get(),last_track);
insert_data.pop_front();
}
undo_redo->commit_action();
+
+ if (advance) {
+ float step = animation->get_step();
+ if (step==0)
+ step=1;
+
+ float pos=timeline_pos;
+
+ pos=Math::stepify(pos+step,step);
+ if (pos>animation->get_length())
+ pos=animation->get_length();
+ timeline_pos=pos;
+ track_pos->update();
+ emit_signal("timeline_changed",pos);
+ }
insert_queue=false;
}
@@ -3122,12 +3500,15 @@ void AnimationKeyEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_animation"),&AnimationKeyEditor::set_animation);
ObjectTypeDB::bind_method(_MD("_animation_optimize"),&AnimationKeyEditor::_animation_optimize);
+ ObjectTypeDB::bind_method(_MD("_curve_transition_changed"),&AnimationKeyEditor::_curve_transition_changed);
+ ObjectTypeDB::bind_method(_MD("_toggle_edit_curves"),&AnimationKeyEditor::_toggle_edit_curves);
ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) );
ADD_SIGNAL( MethodInfo("keying_changed" ) );
ADD_SIGNAL( MethodInfo("timeline_changed", PropertyInfo(Variant::REAL,"pos") ) );
ADD_SIGNAL( MethodInfo("animation_len_changed", PropertyInfo(Variant::REAL,"len") ) );
+ ADD_SIGNAL( MethodInfo("key_edited", PropertyInfo(Variant::INT,"track"), PropertyInfo(Variant::INT,"key") ) );
}
@@ -3219,12 +3600,6 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
hb->add_child( memnew( VSeparator ) );
- edit_button = memnew( ToolButton );
- edit_button->set_toggle_mode(true);
- edit_button->set_focus_mode(FOCUS_NONE);
- edit_button->set_disabled(true);
- hb->add_child(edit_button);
- edit_button->set_tooltip("Enable editing of individual keys by clicking them.");
move_up_button = memnew( ToolButton );
hb->add_child(move_up_button);
@@ -3247,6 +3622,15 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
remove_button->set_disabled(true);
remove_button->set_tooltip("Remove selected track.");
+ hb->add_child(memnew( VSeparator ));
+
+ edit_button = memnew( ToolButton );
+ edit_button->set_toggle_mode(true);
+ edit_button->set_focus_mode(FOCUS_NONE);
+ edit_button->set_disabled(true);
+
+ hb->add_child(edit_button);
+ edit_button->set_tooltip("Enable editing of individual keys by clicking them.");
optimize_dialog = memnew( ConfirmationDialog );
add_child(optimize_dialog);
@@ -3297,7 +3681,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
// menu->get_popup()->connect("item_pressed",this,"_menu_callback");
ec = memnew (Control);
- ec->set_custom_minimum_size(Size2(0,50));
+ ec->set_custom_minimum_size(Size2(0,150));
add_child(ec);
ec->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -3313,6 +3697,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
track_editor->set_focus_mode(Control::FOCUS_ALL);
track_editor->set_h_size_flags(SIZE_EXPAND_FILL);
+
track_pos = memnew( Control );
track_pos->set_area_as_parent_rect();
track_pos->set_ignore_mouse(true);
@@ -3325,6 +3710,56 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
v_scroll->connect("value_changed",this,"_scroll_changed");
v_scroll->set_val(0);
+ key_editor_tab = memnew(TabContainer);
+ hb->add_child(key_editor_tab);
+ key_editor_tab->set_custom_minimum_size(Size2(200,0));
+
+ key_editor = memnew( PropertyEditor );
+ key_editor->set_area_as_parent_rect();
+ key_editor->hide_top_label();
+ key_editor->set_name("Key");
+ key_editor_tab->add_child(key_editor);
+
+ key_edit = memnew( AnimationKeyEdit );
+ key_edit->undo_redo=undo_redo;
+ //key_edit->ke_dialog=key_edit_dialog;
+ key_editor->edit(key_edit);
+ type_menu = memnew( PopupMenu );
+ add_child(type_menu);
+ for(int i=0;i<Variant::VARIANT_MAX;i++)
+ type_menu->add_item(Variant::get_type_name(Variant::Type(i)),i);
+ type_menu->connect("item_pressed",this,"_create_value_item");
+
+ VBoxContainer *curve_vb = memnew( VBoxContainer );
+ curve_vb->set_name("Transition");
+ HBoxContainer *curve_hb = memnew( HBoxContainer );
+ curve_vb->add_child(curve_hb);
+
+ curve_linear = memnew( ToolButton );
+ curve_linear->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_linear);
+ curve_in = memnew( ToolButton );
+ curve_in->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_in);
+ curve_out = memnew( ToolButton );
+ curve_out->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_out);
+ curve_inout = memnew( ToolButton );
+ curve_inout->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_inout);
+ curve_outin = memnew( ToolButton );
+ curve_outin->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_outin);
+ curve_constant = memnew( ToolButton );
+ curve_constant->set_focus_mode(FOCUS_NONE);
+ curve_hb->add_child(curve_constant);
+
+
+ curve_edit = memnew( AnimationCurveEdit );
+ curve_vb->add_child(curve_edit);
+ curve_edit->set_v_size_flags(SIZE_EXPAND_FILL);
+ key_editor_tab->add_child(curve_vb);
+
h_scroll = memnew( HScrollBar );
h_scroll->connect("value_changed",this,"_scroll_changed");
add_child(h_scroll);
@@ -3340,7 +3775,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
add_child(track_menu);
track_menu->connect("item_pressed",this,"_track_menu_selected");
-
+ key_editor_tab->hide();
last_idx =1;
@@ -3359,24 +3794,6 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
timeline_pos=0;
- key_edit_dialog = memnew( PopupDialog );
- key_editor = memnew( PropertyEditor );
- add_child(key_edit_dialog);
- key_editor->set_area_as_parent_rect();
- key_editor->hide_top_label();
- for(int i=0;i<4;i++)
- key_editor->set_margin(Margin(i),5);
- key_edit_dialog->add_child(key_editor);
-
- key_edit = memnew( AnimationKeyEdit );
- key_edit->undo_redo=undo_redo;
- key_edit->ke_dialog=key_edit_dialog;
- key_editor->edit(key_edit);
- type_menu = memnew( PopupMenu );
- add_child(type_menu);
- for(int i=0;i<Variant::VARIANT_MAX;i++)
- type_menu->add_item(Variant::get_type_name(Variant::Type(i)),i);
- type_menu->connect("item_pressed",this,"_create_value_item");
keying=false;
insert_frame=0;
insert_query=false;
diff --git a/tools/editor/animation_editor.h b/tools/editor/animation_editor.h
index 885d46cf6c..35053fb6a3 100644
--- a/tools/editor/animation_editor.h
+++ b/tools/editor/animation_editor.h
@@ -37,6 +37,7 @@
#include "scene/gui/scroll_bar.h"
#include "scene/gui/tool_button.h"
#include "scene/gui/file_dialog.h"
+#include "scene/gui/tab_container.h"
#include "scene/resources/animation.h"
#include "scene/animation/animation_cache.h"
@@ -46,6 +47,7 @@
class AnimationKeyEdit;
+class AnimationCurveEdit;
class AnimationKeyEditor : public VBoxContainer {
@@ -86,7 +88,13 @@ class AnimationKeyEditor : public VBoxContainer {
TRACK_MENU_SET_ALL_TRANS_OUTIN,
TRACK_MENU_NEXT_STEP,
TRACK_MENU_PREV_STEP,
- TRACK_MENU_OPTIMIZE
+ TRACK_MENU_OPTIMIZE,
+ CURVE_SET_LINEAR,
+ CURVE_SET_IN,
+ CURVE_SET_OUT,
+ CURVE_SET_INOUT,
+ CURVE_SET_OUTIN,
+ CURVE_SET_CONSTANT
};
struct MouseOver {
@@ -169,6 +177,14 @@ class AnimationKeyEditor : public VBoxContainer {
ToolButton *move_down_button;
ToolButton *remove_button;
+ ToolButton *curve_linear;
+ ToolButton *curve_in;
+ ToolButton *curve_out;
+ ToolButton *curve_inout;
+ ToolButton *curve_outin;
+ ToolButton *curve_constant;
+
+
ConfirmationDialog *optimize_dialog;
SpinBox *optimize_linear_error;
SpinBox *optimize_angular_error;
@@ -183,11 +199,11 @@ class AnimationKeyEditor : public VBoxContainer {
Control *track_editor;
Control *track_pos;
+ TabContainer *key_editor_tab;
ConfirmationDialog *scale_dialog;
SpinBox *scale;
- PopupDialog *key_edit_dialog;
PropertyEditor *key_editor;
Ref<Animation> animation;
@@ -203,6 +219,7 @@ class AnimationKeyEditor : public VBoxContainer {
AnimationKeyEdit *key_edit;
+ AnimationCurveEdit *curve_edit;
bool inserting;
@@ -220,6 +237,7 @@ class AnimationKeyEditor : public VBoxContainer {
int track_idx;
Variant value;
String query;
+ bool advance;
};/* insert_data;*/
bool insert_query;
@@ -254,7 +272,7 @@ class AnimationKeyEditor : public VBoxContainer {
void _scale();
-
+ void _clear_selection();
//void _browse_path();
@@ -270,12 +288,15 @@ class AnimationKeyEditor : public VBoxContainer {
void _clear_selection_for_anim(const Ref<Animation>& p_anim);
void _select_at_anim(const Ref<Animation>& p_anim,int p_track,float p_pos);
+ void _curve_transition_changed(float p_what);
PropertyInfo _find_hint_for_track(int p_idx);
void _create_value_item(int p_type);
void _pane_drag(const Point2& p_delta);
+ bool _edit_if_single_selection();
+ void _toggle_edit_curves();
void _animation_len_update();
void _root_removed();
@@ -296,7 +317,7 @@ public:
void set_anim_pos(float p_pos);
void insert_node_value_key(Node* p_node, const String& p_property,const Variant& p_value,bool p_only_if_exists=false);
- void insert_value_key(const String& p_property,const Variant& p_value);
+ void insert_value_key(const String& p_property, const Variant& p_value, bool p_advance);
void insert_transform_key(Spatial *p_node,const String& p_sub,const Transform& p_xform);
AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_history, EditorSelection *p_selection);
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_file_system.cpp b/tools/editor/editor_file_system.cpp
index 8e96123c36..ae083db0ff 100644
--- a/tools/editor/editor_file_system.cpp
+++ b/tools/editor/editor_file_system.cpp
@@ -989,6 +989,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) {
void EditorFileSystem::_resource_saved(const String& p_path){
+ print_line("resource saved: "+p_path);
EditorFileSystem::get_singleton()->update_file(p_path);
}
diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp
index 56b813344a..0ab50147b9 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 );
@@ -2838,9 +2940,9 @@ void EditorNode::_instance_request(const String& p_path){
request_instance_scene(p_path);
}
-void EditorNode::_property_keyed(const String& p_keyed,const Variant& p_value) {
+void EditorNode::_property_keyed(const String& p_keyed,const Variant& p_value,bool p_advance) {
- animation_editor->insert_value_key(p_keyed,p_value);
+ animation_editor->insert_value_key(p_keyed,p_value,p_advance);
}
void EditorNode::_transform_keyed(Object *sp,const String& p_sub,const Transform& p_key) {
@@ -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://");
@@ -4105,8 +4229,9 @@ EditorNode::EditorNode() {
editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_TEXTURE_2D) )));
- editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_TEXTURE_3D) )));
editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_ATLAS) )));
+ editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_LARGE) )));
+ editor_import_export->add_import_plugin( Ref<EditorTextureImportPlugin>( memnew(EditorTextureImportPlugin(this,EditorTextureImportPlugin::MODE_TEXTURE_3D) )));
Ref<EditorSceneImportPlugin> _scene_import = memnew(EditorSceneImportPlugin(this) );
Ref<EditorSceneImporterCollada> _collada_import = memnew( EditorSceneImporterCollada);
_scene_import->add_importer(_collada_import);
@@ -4161,6 +4286,14 @@ 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 )));
+ resource_preview->add_preview_generator( Ref<EditorMeshPreviewPlugin>( memnew(EditorMeshPreviewPlugin )));
+
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 76e82b5a6b..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;
@@ -348,7 +349,7 @@ class EditorNode : public Node {
void _instance_request(const String& p_path);
- void _property_keyed(const String& p_keyed,const Variant& p_value);
+ void _property_keyed(const String& p_keyed, const Variant& p_value, bool p_advance);
void _transform_keyed(Object *sp,const String& p_sub,const Transform& p_key);
void _update_keying();
@@ -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_curve_constant.png b/tools/editor/icons/icon_curve_constant.png
new file mode 100644
index 0000000000..cdeac1785e
--- /dev/null
+++ b/tools/editor/icons/icon_curve_constant.png
Binary files differ
diff --git a/tools/editor/icons/icon_curve_in.png b/tools/editor/icons/icon_curve_in.png
new file mode 100644
index 0000000000..2db202632e
--- /dev/null
+++ b/tools/editor/icons/icon_curve_in.png
Binary files differ
diff --git a/tools/editor/icons/icon_curve_in_out.png b/tools/editor/icons/icon_curve_in_out.png
new file mode 100644
index 0000000000..f4cb593496
--- /dev/null
+++ b/tools/editor/icons/icon_curve_in_out.png
Binary files differ
diff --git a/tools/editor/icons/icon_curve_linear.png b/tools/editor/icons/icon_curve_linear.png
new file mode 100644
index 0000000000..9467dc97a3
--- /dev/null
+++ b/tools/editor/icons/icon_curve_linear.png
Binary files differ
diff --git a/tools/editor/icons/icon_curve_out.png b/tools/editor/icons/icon_curve_out.png
new file mode 100644
index 0000000000..c91ade6f4a
--- /dev/null
+++ b/tools/editor/icons/icon_curve_out.png
Binary files differ
diff --git a/tools/editor/icons/icon_curve_out_in.png b/tools/editor/icons/icon_curve_out_in.png
new file mode 100644
index 0000000000..6499fa753e
--- /dev/null
+++ b/tools/editor/icons/icon_curve_out_in.png
Binary files differ
diff --git a/tools/editor/icons/icon_key_next.png b/tools/editor/icons/icon_key_next.png
new file mode 100644
index 0000000000..759008d064
--- /dev/null
+++ b/tools/editor/icons/icon_key_next.png
Binary files differ
diff --git a/tools/editor/icons/icon_pause.png b/tools/editor/icons/icon_pause.png
index e63661353c..7c0a57003e 100644
--- a/tools/editor/icons/icon_pause.png
+++ b/tools/editor/icons/icon_pause.png
Binary files differ
diff --git a/tools/editor/icons/icon_play.png b/tools/editor/icons/icon_play.png
index 08cce495a9..d2bd9d310c 100644
--- a/tools/editor/icons/icon_play.png
+++ b/tools/editor/icons/icon_play.png
Binary files differ
diff --git a/tools/editor/icons/icon_play_backwards.png b/tools/editor/icons/icon_play_backwards.png
new file mode 100644
index 0000000000..8dff5f20e3
--- /dev/null
+++ b/tools/editor/icons/icon_play_backwards.png
Binary files differ
diff --git a/tools/editor/icons/icon_play_start.png b/tools/editor/icons/icon_play_start.png
new file mode 100644
index 0000000000..5b085aa1ed
--- /dev/null
+++ b/tools/editor/icons/icon_play_start.png
Binary files differ
diff --git a/tools/editor/icons/icon_play_start_backwards.png b/tools/editor/icons/icon_play_start_backwards.png
new file mode 100644
index 0000000000..09afac637c
--- /dev/null
+++ b/tools/editor/icons/icon_play_start_backwards.png
Binary files differ
diff --git a/tools/editor/icons/icon_stop.png b/tools/editor/icons/icon_stop.png
index fd568b61a8..0fd43b403a 100644
--- a/tools/editor/icons/icon_stop.png
+++ b/tools/editor/icons/icon_stop.png
Binary files differ
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/io_plugins/editor_sample_import_plugin.cpp b/tools/editor/io_plugins/editor_sample_import_plugin.cpp
index d1fe10df03..fa472ed033 100644
--- a/tools/editor/io_plugins/editor_sample_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_sample_import_plugin.cpp
@@ -610,6 +610,7 @@ Error EditorSampleImportPlugin::import(const String& p_path, const Ref<ResourceI
dst_format=Sample::FORMAT_IMA_ADPCM;
_compress_ima_adpcm(data,dst_data);
+ print_line("compressing ima-adpcm, resulting buffersize is "+itos(dst_data.size())+" from "+itos(data.size()));
} else {
@@ -755,10 +756,10 @@ void EditorSampleImportPlugin::_compress_ima_adpcm(const Vector<float>& p_data,D
prev+=vpdiff ;
if (prev > 32767) {
- printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip up %i\n",i,xm_sample,prev,diff,vpdiff,prev);
+ //printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip up %i\n",i,xm_sample,prev,diff,vpdiff,prev);
prev=32767;
} else if (prev < -32768) {
- printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip down %i\n",i,xm_sample,prev,diff,vpdiff,prev);
+ //printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip down %i\n",i,xm_sample,prev,diff,vpdiff,prev);
prev = -32768 ;
}
diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.cpp b/tools/editor/io_plugins/editor_scene_import_plugin.cpp
index 3fb4b06f3c..2ce5f3a5a7 100644
--- a/tools/editor/io_plugins/editor_scene_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_scene_import_plugin.cpp
@@ -2638,8 +2638,11 @@ void EditorSceneImportPlugin::_filter_tracks(Node *scene, const String& p_text)
for(Set<String>::Element *F=keep_local.front();F;F=F->next()) {
keep.insert(F->get());
}
-
+ print_line("FILTERING ANIM: "+String(E->get()));
_filter_anim_tracks(anim->get_animation(name),keep);
+ } else {
+ print_line("NOT FILTERING ANIM: "+String(E->get()));
+
}
}
diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp
index 3add30d81e..e491938d41 100644
--- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp
@@ -144,6 +144,8 @@ void EditorImportTextureOptions::_changed() {
void EditorImportTextureOptions::_bind_methods() {
+ print_line("bind toptions");
+
ObjectTypeDB::bind_method("_changed",&EditorImportTextureOptions::_changed);
ObjectTypeDB::bind_method("_changedp",&EditorImportTextureOptions::_changedp);
@@ -219,7 +221,6 @@ EditorImportTextureOptions::EditorImportTextureOptions() {
fname++;
}
-
add_margin_child("Texture Options",flags,true);
notice_for_2d = memnew( Label );
@@ -253,11 +254,14 @@ class EditorTextureImportDialog : public ConfirmationDialog {
OptionButton *texture_action;
ConfirmationDialog *error_dialog;
CheckButton *crop_source;
+ SpinBox *size;
bool atlas;
+ bool large;
EditorTextureImportPlugin *plugin;
void _choose_files(const Vector<String>& p_path);
+ void _choose_file(const String& p_path);
void _choose_save_dir(const String& p_path);
void _browse();
void _browse_target();
@@ -272,7 +276,7 @@ public:
Error import(const String& p_from, const String& p_to, const String& p_preset);
void popup_import(const String &p_from=String());
- EditorTextureImportDialog(EditorTextureImportPlugin *p_plugin=NULL,bool p_2d=false,bool p_atlas=false);
+ EditorTextureImportDialog(EditorTextureImportPlugin *p_plugin=NULL,bool p_2d=false,bool p_atlas=false,bool p_large=false);
};
@@ -301,6 +305,15 @@ void EditorTextureImportDialog::_choose_files(const Vector<String>& p_path) {
import_path->set_text(files);
}
+
+
+
+void EditorTextureImportDialog::_choose_file(const String& p_path) {
+
+
+ import_path->set_text(p_path);
+
+}
void EditorTextureImportDialog::_choose_save_dir(const String& p_path) {
save_path->set_text(p_path);
@@ -336,7 +349,7 @@ void EditorTextureImportDialog::_import() {
}
- if (!atlas && !DirAccess::exists(save_path->get_text())) {
+ if (!atlas && !large && !DirAccess::exists(save_path->get_text())) {
error_dialog->set_text("Target path must exist.");
error_dialog->popup_centered_minsize();
return;
@@ -362,6 +375,8 @@ void EditorTextureImportDialog::_import() {
imd->set_option("flags",texture_options->get_flags());
imd->set_option("quality",texture_options->get_quality());
imd->set_option("atlas",true);
+ imd->set_option("atlas_size",int(size->get_val()));
+ imd->set_option("large",false);
imd->set_option("crop",crop_source->is_pressed());
Error err = plugin->import(dst_file,imd);
@@ -372,7 +387,38 @@ void EditorTextureImportDialog::_import() {
return;
}
+ } else if (large) { //atlas
+
+ if (files.size()!=1) {
+
+ error_dialog->set_text("Only one file is required for large texture");
+ error_dialog->popup_centered(Size2(200,100));
+ return;
+
+ }
+ String dst_file = dst_path;
+ //dst_file=dst_file.basename()+".tex";
+ Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
+ //imd->set_editor();
+ for(int i=0;i<files.size();i++) {
+ imd->add_source(EditorImportPlugin::validate_source_path(files[i]));
+ }
+ imd->set_option("format",texture_options->get_format());
+ imd->set_option("flags",texture_options->get_flags());
+ imd->set_option("quality",texture_options->get_quality());
+ imd->set_option("atlas",false);
+ imd->set_option("large",true);
+ imd->set_option("large_cell_size",int(size->get_val()));
+ imd->set_option("crop",crop_source->is_pressed());
+ Error err = plugin->import(dst_file,imd);
+ if (err) {
+
+ error_dialog->set_text("Error importing: "+dst_file.get_file());
+ error_dialog->popup_centered(Size2(200,100));
+ return;
+
+ }
} else {
@@ -387,6 +433,8 @@ void EditorTextureImportDialog::_import() {
imd->set_option("flags",texture_options->get_flags());
imd->set_option("quality",texture_options->get_quality());
imd->set_option("atlas",false);
+ imd->set_option("large",false);
+
Error err = plugin->import(dst_file,imd);
if (err) {
@@ -408,7 +456,7 @@ void EditorTextureImportDialog::_browse() {
void EditorTextureImportDialog::_browse_target() {
- if (atlas) {
+ if (atlas || large) {
save_file_select->popup_centered_ratio();
} else {
save_select->popup_centered_ratio();
@@ -424,7 +472,7 @@ void EditorTextureImportDialog::popup_import(const String& p_from) {
Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(p_from);
ERR_FAIL_COND(!rimd.is_valid());
- if (plugin->get_mode()==EditorTextureImportPlugin::MODE_ATLAS)
+ if (plugin->get_mode()==EditorTextureImportPlugin::MODE_ATLAS || plugin->get_mode()==EditorTextureImportPlugin::MODE_LARGE)
save_path->set_text(p_from);
else
save_path->set_text(p_from.get_base_dir());
@@ -474,6 +522,7 @@ void EditorTextureImportDialog::_bind_methods() {
ObjectTypeDB::bind_method("_choose_files",&EditorTextureImportDialog::_choose_files);
+ ObjectTypeDB::bind_method("_choose_file",&EditorTextureImportDialog::_choose_file);
ObjectTypeDB::bind_method("_choose_save_dir",&EditorTextureImportDialog::_choose_save_dir);
ObjectTypeDB::bind_method("_import",&EditorTextureImportDialog::_import);
ObjectTypeDB::bind_method("_browse",&EditorTextureImportDialog::_browse);
@@ -481,21 +530,25 @@ void EditorTextureImportDialog::_bind_methods() {
// ADD_SIGNAL( MethodInfo("imported",PropertyInfo(Variant::OBJECT,"scene")) );
}
-EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin* p_plugin, bool p_2d, bool p_atlas) {
+EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin* p_plugin, bool p_2d, bool p_atlas,bool p_large) {
atlas=p_atlas;
+ large=p_large;
plugin=p_plugin;
set_title("Import Textures");
- texture_options = memnew( EditorImportTextureOptions );;
- VBoxContainer *vbc = texture_options;
+
+ VBoxContainer *vbc = memnew(VBoxContainer);
add_child(vbc);
set_child_rect(vbc);
VBoxContainer *source_vb=memnew(VBoxContainer);
- vbc->add_margin_child("Source Texture(s):",source_vb);
+ if (large)
+ vbc->add_margin_child("Source Texture:",source_vb);
+ else
+ vbc->add_margin_child("Source Texture(s):",source_vb);
HBoxContainer *hbc = memnew( HBoxContainer );
source_vb->add_child(hbc);
@@ -510,6 +563,7 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
if (!p_atlas)
crop_source->hide();
+
Button * import_choose = memnew( Button );
import_choose->set_text(" .. ");
hbc->add_child(import_choose);
@@ -519,6 +573,19 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
hbc = memnew( HBoxContainer );
vbc->add_margin_child("Target Path:",hbc);
+ size = memnew( SpinBox );
+ size->set_min(128);
+ size->set_max(16384);
+
+ if (p_atlas) {
+ size->set_val(2048);
+ vbc->add_margin_child("Max Texture size:",size);
+ } else {
+ size->set_val(256);
+ vbc->add_margin_child("Cell Size:",size);
+ }
+
+
save_path = memnew( LineEdit );
save_path->set_h_size_flags(SIZE_EXPAND_FILL);
hbc->add_child(save_path);
@@ -532,15 +599,22 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
file_select = memnew(FileDialog);
file_select->set_access(FileDialog::ACCESS_FILESYSTEM);
add_child(file_select);
- file_select->set_mode(FileDialog::MODE_OPEN_FILES);
+ if (!large)
+ file_select->set_mode(FileDialog::MODE_OPEN_FILES);
+ else
+ file_select->set_mode(FileDialog::MODE_OPEN_FILE);
file_select->connect("files_selected", this,"_choose_files");
+ file_select->connect("file_selected", this,"_choose_file");
save_file_select = memnew(FileDialog);
save_file_select->set_access(FileDialog::ACCESS_RESOURCES);
add_child(save_file_select);
save_file_select->set_mode(FileDialog::MODE_SAVE_FILE);
save_file_select->clear_filters();
- save_file_select->add_filter("*.tex;Base Atlas Texture");
+ if (large)
+ save_file_select->add_filter("*.ltex;Large Texture");
+ else
+ save_file_select->add_filter("*.tex;Base Atlas Texture");
save_file_select->connect("file_selected", this,"_choose_save_dir");
save_select = memnew( EditorDirDialog );
@@ -553,8 +627,8 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
get_ok()->set_text("Import");
//move stuff up
- for(int i=0;i<4;i++)
- vbc->move_child( vbc->get_child( vbc->get_child_count() -1), 0);
+ //for(int i=0;i<4;i++)
+ // vbc->move_child( vbc->get_child( vbc->get_child_count() -1), 0);
error_dialog = memnew ( ConfirmationDialog );
add_child(error_dialog);
@@ -563,13 +637,24 @@ EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin*
set_hide_on_ok(false);
+ texture_options = memnew( EditorImportTextureOptions );;
+ vbc->add_child(texture_options);
+ texture_options->set_v_size_flags(SIZE_EXPAND_FILL);
+
if (atlas) {
texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA|EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS|EditorTextureImportPlugin::IMAGE_FLAG_FILTER);
texture_options->set_quality(0.7);
texture_options->set_format(EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSY);
- texture_options->show_2d_notice();
+ //texture_options->show_2d_notice();
set_title("Import Textures for Atlas (2D)");
+ } else if (large) {
+
+ texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA|EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS|EditorTextureImportPlugin::IMAGE_FLAG_FILTER);
+ texture_options->set_quality(0.7);
+ texture_options->set_format(EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS);
+ texture_options->show_2d_notice();
+ set_title("Import Large Textures (2D)");
} else if (p_2d) {
@@ -615,12 +700,17 @@ String EditorTextureImportPlugin::get_name() const {
return "texture_atlas";
} break;
+ case MODE_LARGE: {
+
+ return "texture_large";
+ } break;
}
return "";
}
+
String EditorTextureImportPlugin::get_visible_name() const {
switch(mode) {
@@ -635,7 +725,11 @@ String EditorTextureImportPlugin::get_visible_name() const {
} break;
case MODE_ATLAS: {
- return "Atlas Texture";
+ return "2D Atlas Texture";
+ } break;
+ case MODE_LARGE: {
+
+ return "2D Large Texture";
} break;
}
@@ -733,6 +827,135 @@ Error EditorTextureImportPlugin::import(const String& p_path, const Ref<Resource
return import2(p_path,p_from,EditorExportPlatform::IMAGE_COMPRESSION_BC,false);
}
+
+Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &texture,int format, float quality,int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,int shrink) {
+
+
+ if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) {
+
+ Image image=texture->get_data();
+ ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA);
+
+ bool has_alpha=image.detect_alpha();
+ if (!has_alpha && image.get_format()==Image::FORMAT_RGBA) {
+
+ image.convert(Image::FORMAT_RGB);
+
+ }
+
+ if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_FIX_BORDER_ALPHA) {
+
+ image.fix_alpha_edges();
+ }
+
+ if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {
+
+ image.premultiply_alpha();
+ }
+
+ if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) {
+ image.normalmap_to_xy();
+ }
+
+ //if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
+
+ // image.srgb_to_linear();
+ //}
+
+ if (shrink>1) {
+
+ int orig_w=image.get_width();
+ int orig_h=image.get_height();
+ image.resize(orig_w/shrink,orig_h/shrink);
+ texture->create_from_image(image,tex_flags);
+ texture->set_size_override(Size2(orig_w,orig_h));
+
+
+ } else {
+
+ texture->create_from_image(image,tex_flags);
+ }
+
+
+ if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS) {
+ texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSLESS);
+ } else {
+ texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
+ }
+
+
+
+ texture->set_lossy_storage_quality(quality);
+
+
+ } else {
+
+
+ Image image=texture->get_data();
+ ERR_FAIL_COND_V(image.empty(),ERR_INVALID_DATA);
+
+
+ bool has_alpha=image.detect_alpha();
+ if (!has_alpha && image.get_format()==Image::FORMAT_RGBA) {
+
+ image.convert(Image::FORMAT_RGB);
+
+ }
+
+ if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_FIX_BORDER_ALPHA) {
+
+ image.fix_alpha_edges();
+ }
+
+ if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {
+
+ image.premultiply_alpha();
+ }
+
+ if (flags&IMAGE_FLAG_CONVERT_NORMAL_TO_XY) {
+ image.normalmap_to_xy();
+ }
+
+ //if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
+//
+ // print_line("CONVERT BECAUSE: "+itos(flags));
+ // image.srgb_to_linear();
+ //}
+
+ int orig_w=image.get_width();
+ int orig_h=image.get_height();
+
+ if (shrink>1) {
+ image.resize(orig_w/shrink,orig_h/shrink);
+ texture->create_from_image(image,tex_flags);
+ texture->set_size_override(Size2(orig_w,orig_h));
+ }
+
+ if (!(flags&IMAGE_FLAG_NO_MIPMAPS)) {
+ image.generate_mipmaps();
+
+ }
+
+ if (format!=IMAGE_FORMAT_UNCOMPRESSED) {
+
+ compress_image(p_compr,image,flags&IMAGE_FLAG_COMPRESS_EXTRA);
+ }
+
+
+ texture->create_from_image(image,tex_flags);
+
+
+ if (shrink>1 || (format!=IMAGE_FORMAT_UNCOMPRESSED && (image.get_width()!=orig_w || image.get_height()!=orig_h))) {
+ texture->set_size_override(Size2(orig_w,orig_h));
+ }
+
+ //uint32_t save_flags=ResourceSaver::FLAG_COMPRESS;
+ }
+
+ return OK;
+}
+
+
Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<ResourceImportMetadata>& p_from,EditorExportPlatform::ImageCompression p_compr, bool p_external){
@@ -744,8 +967,11 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
Ref<ImageTexture> texture;
Vector<Ref<AtlasTexture> > atlases;
bool atlas = from->get_option("atlas");
+ bool large = from->get_option("large");
int flags=from->get_option("flags");
+ int format=from->get_option("format");
+ float quality=from->get_option("quality");
uint32_t tex_flags=0;
@@ -765,7 +991,80 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
if (from->has_option("shrink"))
shrink=from->get_option("shrink");
- if (atlas) {
+ if (large) {
+ ERR_FAIL_COND_V(from->get_source_count()!=1,ERR_INVALID_PARAMETER);
+
+ String src_path = EditorImportPlugin::expand_source_path(from->get_source_path(0));
+
+
+ int cell_size=from->get_option("large_cell_size");
+ ERR_FAIL_COND_V(cell_size<128 || cell_size>16384,ERR_CANT_OPEN);
+
+ EditorProgress pg("ltex","Import Large Texture",3);
+
+ pg.step("Load Source Image",0);
+ Image img;
+ Error err = ImageLoader::load_image(src_path,&img);
+ if (err) {
+ return err;
+ }
+
+ pg.step("Slicing",1);
+
+ Map<Vector2,Image> pieces;
+ for(int i=0;i<img.get_width();i+=cell_size) {
+ int w = MIN(img.get_width()-i,cell_size);
+ for(int j=0;j<img.get_height();j+=cell_size) {
+ int h = MIN(img.get_height()-j,cell_size);
+
+ Image piece(w,h,0,img.get_format());
+ piece.blit_rect(img,Rect2(i,j,w,h),Point2(0,0));
+ if (!piece.is_invisible()) {
+ pieces[Vector2(i,j)]=piece;
+ //print_line("ADDING PIECE AT "+Vector2(i,j));
+ }
+ }
+ }
+
+ Ref<LargeTexture> existing;
+ if (ResourceCache::has(p_path)) {
+ existing = ResourceCache::get(p_path);
+ }
+
+ if (existing.is_valid()) {
+ existing->clear();
+ } else {
+ existing = Ref<LargeTexture>(memnew( LargeTexture ));
+ }
+
+ existing->set_size(Size2(img.get_width(),img.get_height()));
+ pg.step("Inserting",2);
+
+ for (Map<Vector2,Image>::Element *E=pieces.front();E;E=E->next()) {
+
+ Ref<ImageTexture> imgtex = Ref<ImageTexture>( memnew( ImageTexture ) );
+ imgtex->create_from_image(E->get(),tex_flags);
+ _process_texture_data(imgtex,format,quality,flags,p_compr,tex_flags,shrink);
+ existing->add_piece(E->key(),imgtex);
+ }
+
+ if (!p_external) {
+ from->set_editor(get_name());
+ existing->set_path(p_path);
+ existing->set_import_metadata(from);
+ }
+ pg.step("Saving",3);
+
+ err = ResourceSaver::save(p_path,existing);
+ if (err!=OK) {
+ EditorNode::add_io_error("Couldn't save large texture: "+p_path);
+ return err;
+ }
+
+ return OK;
+
+
+ } else if (atlas) {
//prepare atlas!
Vector< Image > sources;
@@ -897,8 +1196,6 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
}
- int format=from->get_option("format");
- float quality=from->get_option("quality");
if (!p_external) {
from->set_editor(get_name());
@@ -932,7 +1229,11 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
}
}
+ bool compress=false;
+#if 1
+ _process_texture_data(texture,format,quality,flags,p_compr,tex_flags,shrink);
+#else
if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) {
Image image=texture->get_data();
@@ -989,13 +1290,6 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
texture->set_lossy_storage_quality(quality);
- Error err = ResourceSaver::save(p_path,texture);
-
- if (err!=OK) {
- EditorNode::add_io_error("Couldn't save converted texture: "+p_path);
- return err;
- }
-
} else {
@@ -1058,15 +1352,20 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
texture->set_size_override(Size2(orig_w,orig_h));
}
- uint32_t save_flags=ResourceSaver::FLAG_COMPRESS;
+ compress=true;
- Error err = ResourceSaver::save(p_path,texture,save_flags);
- if (err!=OK) {
- EditorNode::add_io_error("Couldn't save converted texture: "+p_path);
- return err;
- }
}
+#endif
+ uint32_t save_flags=0;
+ if (compress)
+ save_flags=ResourceSaver::FLAG_COMPRESS;
+
+ Error err = ResourceSaver::save(p_path,texture,save_flags);
+ if (err!=OK) {
+ EditorNode::add_io_error("Couldn't save converted texture: "+p_path);
+ return err;
+ }
return OK;
}
@@ -1255,14 +1554,14 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c
}
-EditorTextureImportPlugin *EditorTextureImportPlugin::singleton[3]={NULL,NULL,NULL};
+EditorTextureImportPlugin *EditorTextureImportPlugin::singleton[EditorTextureImportPlugin::MODE_MAX]={NULL,NULL,NULL,NULL};
EditorTextureImportPlugin::EditorTextureImportPlugin(EditorNode *p_editor, Mode p_mode) {
singleton[p_mode]=this;
editor=p_editor;
- mode=p_mode;
- dialog = memnew( EditorTextureImportDialog(this,p_mode==MODE_TEXTURE_2D || p_mode==MODE_ATLAS,p_mode==MODE_ATLAS) );
+ mode=p_mode;
+ dialog = memnew( EditorTextureImportDialog(this,p_mode==MODE_TEXTURE_2D || p_mode==MODE_ATLAS || p_mode==MODE_LARGE,p_mode==MODE_ATLAS,p_mode==MODE_LARGE) );
editor->get_gui_base()->add_child(dialog);
}
diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.h b/tools/editor/io_plugins/editor_texture_import_plugin.h
index 5cd36e838e..02d09d9e17 100644
--- a/tools/editor/io_plugins/editor_texture_import_plugin.h
+++ b/tools/editor/io_plugins/editor_texture_import_plugin.h
@@ -56,7 +56,9 @@ public:
enum Mode {
MODE_TEXTURE_2D,
MODE_TEXTURE_3D,
- MODE_ATLAS
+ MODE_ATLAS,
+ MODE_LARGE,
+ MODE_MAX
};
@@ -65,10 +67,10 @@ private:
Mode mode;
EditorNode *editor;
EditorTextureImportDialog *dialog;
- static EditorTextureImportPlugin *singleton[3];
+ static EditorTextureImportPlugin *singleton[MODE_MAX];
//used by other importers such as mesh
-
+ Error _process_texture_data(Ref<ImageTexture> &texture, int format, float quality, int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,int shrink);
void compress_image(EditorExportPlatform::ImageCompression p_mode,Image& image,bool p_smaller);
public:
diff --git a/tools/editor/plugins/animation_player_editor_plugin.cpp b/tools/editor/plugins/animation_player_editor_plugin.cpp
index fee2f4f977..9a93eed969 100644
--- a/tools/editor/plugins/animation_player_editor_plugin.cpp
+++ b/tools/editor/plugins/animation_player_editor_plugin.cpp
@@ -28,7 +28,8 @@
/*************************************************************************/
#include "animation_player_editor_plugin.h"
#include "io/resource_loader.h"
-
+#include "os/keyboard.h"
+#include "tools/editor/editor_settings.h"
void AnimationPlayerEditor::_node_removed(Node *p_node) {
@@ -100,12 +101,18 @@ void AnimationPlayerEditor::_notification(int p_what) {
remove_anim->set_icon( get_icon("Del","EditorIcons") );
edit_anim->set_icon( get_icon("Edit","EditorIcons") );
blend_anim->set_icon( get_icon("Blend","EditorIcons") );
- play->set_icon( get_icon("Play","EditorIcons") );
+ play->set_icon( get_icon("PlayStart","EditorIcons") );
+ play_from->set_icon( get_icon("Play","EditorIcons") );
+ play_bw->set_icon( get_icon("PlayStartBackwards","EditorIcons") );
+ play_bw_from->set_icon( get_icon("PlayBackwards","EditorIcons") );
+
autoplay_icon=get_icon("AutoPlay","EditorIcons");
stop->set_icon( get_icon("Stop","EditorIcons") );
resource_edit_anim->set_icon( get_icon("EditResource","EditorIcons") );
pin->set_normal_texture(get_icon("Pin","EditorIcons") );
pin->set_pressed_texture( get_icon("PinPressed","EditorIcons") );
+ tool_anim->set_icon(get_icon("Tools","EditorIcons"));
+ tool_anim->get_popup()->connect("item_pressed",this,"_animation_tool_menu");
blend_editor.next->connect("text_changed",this,"_blend_editor_next_changed");
@@ -180,9 +187,82 @@ void AnimationPlayerEditor::_play_pressed() {
//unpause
//pause->set_pressed(false);
}
+
+void AnimationPlayerEditor::_play_from_pressed() {
+
+ String current;
+ if (animation->get_selected()>=0 && animation->get_selected()<animation->get_item_count()) {
+
+ current = animation->get_item_text( animation->get_selected() );
+ }
+
+ if (current!="") {
+
+ float time = player->get_current_animation_pos();
+
+ if (current==player->get_current_animation() && player->is_playing()) {
+
+ player->stop(); //so it wont blend with itself
+ }
+
+ player->play( current );
+ player->seek(time);
+ }
+
+ //unstop
+ stop->set_pressed(false);
+ //unpause
+ //pause->set_pressed(false);
+}
+
+
+void AnimationPlayerEditor::_play_bw_pressed() {
+
+ String current;
+ if (animation->get_selected()>=0 && animation->get_selected()<animation->get_item_count()) {
+
+ current = animation->get_item_text( animation->get_selected() );
+ }
+
+ if (current!="") {
+
+ if (current==player->get_current_animation())
+ player->stop(); //so it wont blend with itself
+ player->play(current,-1,-1,true);
+ }
+
+ //unstop
+ stop->set_pressed(false);
+ //unpause
+ //pause->set_pressed(false);
+}
+
+void AnimationPlayerEditor::_play_bw_from_pressed() {
+
+ String current;
+ if (animation->get_selected()>=0 && animation->get_selected()<animation->get_item_count()) {
+
+ current = animation->get_item_text( animation->get_selected() );
+ }
+
+ if (current!="") {
+
+ float time = player->get_current_animation_pos();
+ if (current==player->get_current_animation())
+ player->stop(); //so it wont blend with itself
+
+ player->play(current,-1,-1,true);
+ player->seek(time);
+ }
+
+ //unstop
+ stop->set_pressed(false);
+ //unpause
+ //pause->set_pressed(false);
+}
void AnimationPlayerEditor::_stop_pressed() {
- player->stop();
+ player->stop(false);
play->set_pressed(false);
stop->set_pressed(true);
//pause->set_pressed(false);
@@ -598,6 +678,9 @@ void AnimationPlayerEditor::_update_player() {
stop->set_disabled(animlist.size()==0);
play->set_disabled(animlist.size()==0);
+ play_bw->set_disabled(animlist.size()==0);
+ play_bw_from->set_disabled(animlist.size()==0);
+ play_from->set_disabled(animlist.size()==0);
autoplay->set_disabled(animlist.size()==0);
duplicate_anim->set_disabled(animlist.size()==0);
rename_anim->set_disabled(animlist.size()==0);
@@ -877,11 +960,108 @@ void AnimationPlayerEditor::_hide_anim_editors() {
}
}
+
+void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
+
+ switch(p_option) {
+
+ case TOOL_COPY_ANIM: {
+
+ if (!animation->get_item_count()) {
+ error_dialog->set_text("ERROR: No animation to copy!");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
+ String current = animation->get_item_text(animation->get_selected());
+ Ref<Animation> anim = player->get_animation(current);
+ //editor->edit_resource(anim);
+ EditorSettings::get_singleton()->set_resource_clipboard(anim);
+
+ } break;
+ case TOOL_PASTE_ANIM: {
+
+ Ref<Animation> anim = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (!anim.is_valid()) {
+ error_dialog->set_text("ERROR: No animation resource on clipboard!");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
+ String name = anim->get_name();
+ if (name=="") {
+ name="Pasted Animation";
+ }
+
+ int idx=1;
+ String base = name;
+ while (player->has_animation(name)) {
+
+ idx++;
+ name=base+" "+itos(idx);
+ }
+
+ undo_redo->create_action("Paste Animation");
+ undo_redo->add_do_method(player,"add_animation",name,anim);
+ undo_redo->add_undo_method(player,"remove_animation",name);
+ undo_redo->add_do_method(this,"_animation_player_changed",player);
+ undo_redo->add_undo_method(this,"_animation_player_changed",player);
+ undo_redo->commit_action();
+
+ _select_anim_by_name(name);
+
+
+ } break;
+ case TOOL_EDIT_RESOURCE: {
+
+ if (!animation->get_item_count()) {
+ error_dialog->set_text("ERROR: No animation to edit!");
+ error_dialog->popup_centered_minsize();
+ return;
+ }
+
+ String current = animation->get_item_text(animation->get_selected());
+ Ref<Animation> anim = player->get_animation(current);
+ editor->edit_resource(anim);
+
+ } break;
+
+ }
+}
+
+void AnimationPlayerEditor::_unhandled_key_input(const InputEvent& p_ev) {
+
+ if (is_visible() && p_ev.type==InputEvent::KEY && p_ev.key.pressed && !p_ev.key.echo && !p_ev.key.mod.alt && !p_ev.key.mod.control && !p_ev.key.mod.meta) {
+
+ switch(p_ev.key.scancode) {
+
+ case KEY_A: {
+ if (!p_ev.key.mod.shift)
+ _play_bw_from_pressed();
+ else
+ _play_bw_pressed();
+ } break;
+ case KEY_S: {
+ _stop_pressed();
+ } break;
+ case KEY_D: {
+ if (!p_ev.key.mod.shift)
+ _play_from_pressed();
+ else
+ _play_pressed();
+ } break;
+ }
+ }
+}
+
void AnimationPlayerEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_input_event"),&AnimationPlayerEditor::_input_event);
ObjectTypeDB::bind_method(_MD("_node_removed"),&AnimationPlayerEditor::_node_removed);
ObjectTypeDB::bind_method(_MD("_play_pressed"),&AnimationPlayerEditor::_play_pressed);
+ ObjectTypeDB::bind_method(_MD("_play_from_pressed"),&AnimationPlayerEditor::_play_from_pressed);
+ ObjectTypeDB::bind_method(_MD("_play_bw_pressed"),&AnimationPlayerEditor::_play_bw_pressed);
+ ObjectTypeDB::bind_method(_MD("_play_bw_from_pressed"),&AnimationPlayerEditor::_play_bw_from_pressed);
ObjectTypeDB::bind_method(_MD("_stop_pressed"),&AnimationPlayerEditor::_stop_pressed);
ObjectTypeDB::bind_method(_MD("_autoplay_pressed"),&AnimationPlayerEditor::_autoplay_pressed);
ObjectTypeDB::bind_method(_MD("_pause_pressed"),&AnimationPlayerEditor::_pause_pressed);
@@ -908,6 +1088,8 @@ void AnimationPlayerEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_hide_anim_editors"),&AnimationPlayerEditor::_hide_anim_editors);
ObjectTypeDB::bind_method(_MD("_animation_duplicate"),&AnimationPlayerEditor::_animation_duplicate);
ObjectTypeDB::bind_method(_MD("_blend_editor_next_changed"),&AnimationPlayerEditor::_blend_editor_next_changed);
+ ObjectTypeDB::bind_method(_MD("_unhandled_key_input"),&AnimationPlayerEditor::_unhandled_key_input);
+ ObjectTypeDB::bind_method(_MD("_animation_tool_menu"),&AnimationPlayerEditor::_animation_tool_menu);
@@ -935,47 +1117,56 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
add_child(hb);
- add_anim = memnew( Button );
+ add_anim = memnew( ToolButton );
add_anim->set_tooltip("Create new animation in player.");
hb->add_child(add_anim);
-
- load_anim = memnew( Button );
+ load_anim = memnew( ToolButton );
load_anim->set_tooltip("Load an animation from disk.");
hb->add_child(load_anim);
- duplicate_anim = memnew( Button );
+ duplicate_anim = memnew( ToolButton );
hb->add_child(duplicate_anim);
duplicate_anim->set_tooltip("Duplicate Animation");
+ rename_anim = memnew( ToolButton );
+ hb->add_child(rename_anim);
+ rename_anim->set_tooltip("Rename Animation");
+
+ remove_anim = memnew( ToolButton );
+
+ hb->add_child(remove_anim);
+ remove_anim->set_tooltip("Remove Animation");
+
+
animation = memnew( OptionButton );
hb->add_child(animation);
animation->set_h_size_flags(SIZE_EXPAND_FILL);
animation->set_tooltip("Display list of animations in player.");
- autoplay = memnew( Button );
+ autoplay = memnew( ToolButton );
hb->add_child(autoplay);
autoplay->set_tooltip("Autoplay On Load");
- rename_anim = memnew( Button );
- hb->add_child(rename_anim);
- rename_anim->set_tooltip("Rename Animation");
-
- remove_anim = memnew( Button );
-
- hb->add_child(remove_anim);
- remove_anim->set_tooltip("Remove Animation");
- blend_anim = memnew( Button );
+ blend_anim = memnew( ToolButton );
hb->add_child(blend_anim);
blend_anim->set_tooltip("Edit Target Blend Times");
+ tool_anim = memnew( MenuButton);
+ //tool_anim->set_flat(false);
+ tool_anim->set_tooltip("Animation Tools");
+ tool_anim->get_popup()->add_item("Copy Animation",TOOL_COPY_ANIM);
+ tool_anim->get_popup()->add_item("Paste Animation",TOOL_PASTE_ANIM);
+ //tool_anim->get_popup()->add_separator();
+ //tool_anim->get_popup()->add_item("Edit Anim Resource",TOOL_PASTE_ANIM);
+ hb->add_child(tool_anim);
- edit_anim = memnew( Button );
+ edit_anim = memnew( ToolButton );
edit_anim->set_toggle_mode(true);
hb->add_child(edit_anim);
edit_anim->set_tooltip("Open animation editor.\nProperty editor will displays all editable keys too.");
@@ -984,15 +1175,29 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
hb = memnew (HBoxContainer);
add_child(hb);
- play = memnew( Button );
- play->set_tooltip("Play selected animation.");
+ play_bw_from = memnew( ToolButton );
+ play_bw_from->set_tooltip("Play backwards selected animation from current pos. (A)");
+ hb->add_child(play_bw_from);
- hb->add_child(play);
+ play_bw = memnew( ToolButton );
+ play_bw->set_tooltip("Play backwards selected animation from end. (Shift+A)");
+ hb->add_child(play_bw);
- stop = memnew( Button );
+ stop = memnew( ToolButton );
stop->set_toggle_mode(true);
hb->add_child(stop);
- play->set_tooltip("Stop animation playback.");
+ stop->set_tooltip("Stop animation playback. (S)");
+
+ play = memnew( ToolButton );
+ play->set_tooltip("Play selected animation from start. (Shift+D)");
+ hb->add_child(play);
+
+
+ play_from = memnew( ToolButton );
+ play_from->set_tooltip("Play selected animation from current pos. (D)");
+ hb->add_child(play_from);
+
+
//pause = memnew( Button );
//pause->set_toggle_mode(true);
@@ -1024,6 +1229,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
resource_edit_anim= memnew( Button );
hb->add_child(resource_edit_anim);
+ resource_edit_anim->hide();
file = memnew(FileDialog);
@@ -1074,7 +1280,10 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
autoplay->connect("pressed", this,"_autoplay_pressed");
autoplay->set_toggle_mode(true);
- play->connect("pressed", this,"_play_pressed");
+ play->connect("pressed", this,"_play_pressed");
+ play_from->connect("pressed", this,"_play_from_pressed");
+ play_bw->connect("pressed", this,"_play_bw_pressed");
+ play_bw_from->connect("pressed", this,"_play_bw_from_pressed");
stop->connect("pressed", this,"_stop_pressed");
//pause->connect("pressed", this,"_pause_pressed");
add_anim->connect("pressed", this,"_animation_new");
@@ -1104,6 +1313,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
renaming=false;
last_active=false;
+
+ set_process_unhandled_key_input(true);
}
diff --git a/tools/editor/plugins/animation_player_editor_plugin.h b/tools/editor/plugins/animation_player_editor_plugin.h
index 380dfd1903..5c9dc6cab8 100644
--- a/tools/editor/plugins/animation_player_editor_plugin.h
+++ b/tools/editor/plugins/animation_player_editor_plugin.h
@@ -49,10 +49,19 @@ class AnimationPlayerEditor : public VBoxContainer {
EditorNode *editor;
AnimationPlayer *player;
+ enum {
+ TOOL_COPY_ANIM,
+ TOOL_PASTE_ANIM,
+ TOOL_EDIT_RESOURCE
+ };
OptionButton *animation;
Button *stop;
Button *play;
+ Button *play_from;
+ Button *play_bw;
+ Button *play_bw_from;
+
// Button *pause;
Button *add_anim;
Button *autoplay;
@@ -63,6 +72,7 @@ class AnimationPlayerEditor : public VBoxContainer {
Button *load_anim;
Button *blend_anim;
Button *remove_anim;
+ MenuButton *tool_anim;
TextureButton *pin;
Label *nodename;
SpinBox *frame;
@@ -95,6 +105,9 @@ class AnimationPlayerEditor : public VBoxContainer {
void _select_anim_by_name(const String& p_anim);
void _play_pressed();
+ void _play_from_pressed();
+ void _play_bw_pressed();
+ void _play_bw_from_pressed();
void _autoplay_pressed();
void _stop_pressed();
void _pause_pressed();
@@ -126,6 +139,8 @@ class AnimationPlayerEditor : public VBoxContainer {
void _animation_key_editor_seek(float p_pos);
void _animation_key_editor_anim_len_changed(float p_new);
+ void _unhandled_key_input(const InputEvent& p_ev);
+ void _animation_tool_menu(int p_option);
AnimationPlayerEditor();
protected:
diff --git a/tools/editor/plugins/editor_preview_plugins.cpp b/tools/editor/plugins/editor_preview_plugins.cpp
new file mode 100644
index 0000000000..9532c6b9e9
--- /dev/null
+++ b/tools/editor/plugins/editor_preview_plugins.cpp
@@ -0,0 +1,776 @@
+#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"
+#include "scene/resources/mesh.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() {
+
+
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+bool EditorMeshPreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"Mesh"); //any Mesh
+}
+
+Ref<Texture> EditorMeshPreviewPlugin::generate(const RES& p_from) {
+
+ Ref<Mesh> mesh = p_from;
+ ERR_FAIL_COND_V(mesh.is_null(),Ref<Texture>());
+
+ VS::get_singleton()->instance_set_base(mesh_instance,mesh->get_rid());
+
+ AABB aabb= mesh->get_aabb();
+ Vector3 ofs = aabb.pos + aabb.size*0.5;
+ aabb.pos-=ofs;
+ Transform xform;
+ xform.basis=Matrix3().rotated(Vector3(0,1,0),Math_PI*0.125);
+ xform.basis = Matrix3().rotated(Vector3(1,0,0),-Math_PI*0.125)*xform.basis;
+ AABB rot_aabb = xform.xform(aabb);
+ float m = MAX(rot_aabb.size.x,rot_aabb.size.y)*0.5;
+ if (m==0)
+ return Ref<Texture>();
+ m=1.0/m;
+ m*=0.5;
+ //print_line("scale: "+rtos(m));
+ xform.basis.scale(Vector3(m,m,m));
+ xform.origin=-xform.basis.xform(ofs); //-ofs*m;
+ xform.origin.z-=rot_aabb.size.z*2;
+ VS::get_singleton()->instance_set_transform(mesh_instance,xform);
+
+
+
+ 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()->instance_set_base(mesh_instance,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;
+}
+
+EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() {
+
+ 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);
+ VS::get_singleton()->camera_set_orthogonal(camera,1.0,0.01,1000.0);
+
+ 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();
+ mesh_instance = VS::get_singleton()->instance_create();
+ VS::get_singleton()->instance_set_scenario(mesh_instance,scenario);
+
+
+
+}
+
+EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() {
+
+ //VS::get_singleton()->free(sphere);
+ VS::get_singleton()->free(mesh_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);
+
+}
diff --git a/tools/editor/plugins/editor_preview_plugins.h b/tools/editor/plugins/editor_preview_plugins.h
new file mode 100644
index 0000000000..98071e2a0e
--- /dev/null
+++ b/tools/editor/plugins/editor_preview_plugins.h
@@ -0,0 +1,88 @@
+#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();
+};
+
+
+class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator {
+
+ RID scenario;
+ RID mesh_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);
+
+ EditorMeshPreviewPlugin();
+ ~EditorMeshPreviewPlugin();
+};
+
+
+#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/property_editor.cpp b/tools/editor/property_editor.cpp
index 1c6e57beaa..559267dc07 100644
--- a/tools/editor/property_editor.cpp
+++ b/tools/editor/property_editor.cpp
@@ -2629,7 +2629,12 @@ void PropertyEditor::update_tree() {
if (keying) {
- item->add_button(1,get_icon("Key","EditorIcons"),2);
+ if (p.hint==PROPERTY_HINT_SPRITE_FRAME) {
+
+ item->add_button(1,get_icon("KeyNext","EditorIcons"),5);
+ } else {
+ item->add_button(1,get_icon("Key","EditorIcons"),2);
+ }
}
if (get_instanced_node()) {
@@ -2904,6 +2909,16 @@ void PropertyEditor::edit(Object* p_object) {
}
+void PropertyEditor::_set_range_def(Object *p_item, String prop,float p_frame) {
+
+ TreeItem *ti = p_item->cast_to<TreeItem>();
+ ERR_FAIL_COND(!ti);
+
+ ti->call_deferred("set_range",1, p_frame);
+ obj->call_deferred("set",prop,p_frame);
+
+}
+
void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
TreeItem *ti = p_item->cast_to<TreeItem>();
ERR_FAIL_COND(!ti);
@@ -2915,7 +2930,15 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
if (!d.has("name"))
return;
String prop=d["name"];
- emit_signal("property_keyed",prop,obj->get(prop));
+ emit_signal("property_keyed",prop,obj->get(prop),false);
+ } else if (p_button==5) {
+ print_line("PB5");
+ if (!d.has("name"))
+ return;
+ String prop=d["name"];
+ emit_signal("property_keyed",prop,obj->get(prop),true);
+ //set_range(p_column, ti->get_range(p_column)+1.0 );
+ call_deferred("_set_range_def",ti,prop,ti->get_range(p_column)+1.0);
} else if (p_button==3) {
if (!get_instanced_node())
@@ -3046,6 +3069,7 @@ void PropertyEditor::_bind_methods() {
ObjectTypeDB::bind_method( "_edit_button",&PropertyEditor::_edit_button);
ObjectTypeDB::bind_method( "_changed_callback",&PropertyEditor::_changed_callbacks);
ObjectTypeDB::bind_method( "_draw_flags",&PropertyEditor::_draw_flags);
+ ObjectTypeDB::bind_method( "_set_range_def",&PropertyEditor::_set_range_def);
ADD_SIGNAL( MethodInfo("property_toggled",PropertyInfo( Variant::STRING, "property"),PropertyInfo( Variant::BOOL, "value")));
ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) );
diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h
index 7a7354c88e..164643afaa 100644
--- a/tools/editor/property_editor.h
+++ b/tools/editor/property_editor.h
@@ -187,6 +187,7 @@ class PropertyEditor : public Control {
Node *get_instanced_node();
void _refresh_item(TreeItem *p_item);
+ void _set_range_def(Object *p_item, String prop, float p_frame);
UndoRedo *undo_redo;
protected:
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;