diff options
125 files changed, 5770 insertions, 824 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 06b71f05c0..128bc94989 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -1757,7 +1757,9 @@ _Mutex::~_Mutex(){ void _Thread::_start_func(void *ud) { - _Thread *t=(_Thread*)ud; + Ref<_Thread>* tud=(Ref<_Thread>*)ud; + Ref<_Thread> t=*tud; + memdelete(tud); Variant::CallError ce; const Variant* arg[1]={&t->userdata}; t->ret=t->target_instance->call(t->target_method,arg,1,ce); @@ -1804,9 +1806,11 @@ Error _Thread::start(Object *p_instance,const StringName& p_method,const Variant userdata=p_userdata; active=true; + Ref<_Thread> *ud = memnew( Ref<_Thread>(this) ); + Thread::Settings s; s.priority=(Thread::Priority)p_priority; - thread = Thread::create(_start_func,this,s); + thread = Thread::create(_start_func,ud,s); if (!thread) { active=false; target_method=StringName(); @@ -1867,5 +1871,8 @@ _Thread::_Thread() { _Thread::~_Thread() { + if (active) { + ERR_EXPLAIN("Reference to a Thread object object was lost while the thread is still running.."); + } ERR_FAIL_COND(active==true); } diff --git a/core/globals.cpp b/core/globals.cpp index 23d8c16ace..0315ff0c24 100644 --- a/core/globals.cpp +++ b/core/globals.cpp @@ -339,7 +339,7 @@ Error Globals::setup(const String& p_path,const String & p_main_pack) { //try to load settings in ascending through dirs shape! //tries to open pack, but only first time - if (first_time && _load_resource_pack(current_dir+"/data.pck")) { + if (first_time && (_load_resource_pack(current_dir+"/data.pck") || _load_resource_pack(current_dir+"/data.pcz") )) { if (_load_settings("res://engine.cfg")==OK || _load_settings_binary("res://engine.cfb")==OK) { _load_settings("res://override.cfg"); @@ -1460,6 +1460,7 @@ Globals::Globals() { custom_prop_info["display/orientation"]=PropertyInfo(Variant::STRING,"display/orientation",PROPERTY_HINT_ENUM,"landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor"); custom_prop_info["render/mipmap_policy"]=PropertyInfo(Variant::INT,"render/mipmap_policy",PROPERTY_HINT_ENUM,"Allow,Allow For Po2,Disallow"); custom_prop_info["render/thread_model"]=PropertyInfo(Variant::INT,"render/thread_model",PROPERTY_HINT_ENUM,"Single-Unsafe,Single-Safe,Multi-Threaded"); + custom_prop_info["physics_2d/thread_model"]=PropertyInfo(Variant::INT,"physics_2d/thread_model",PROPERTY_HINT_ENUM,"Single-Unsafe,Single-Safe,Multi-Threaded"); set("display/emulate_touchscreen",false); using_datapack=false; diff --git a/core/image.cpp b/core/image.cpp index 04b3905489..037018519e 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1124,6 +1124,7 @@ void Image::create( const char ** p_xpm ) { } #define DETECT_ALPHA_MAX_TRESHOLD 254 #define DETECT_ALPHA_MIN_TRESHOLD 2 + #define DETECT_ALPHA( m_value )\ { \ uint8_t value=m_value;\ @@ -1136,6 +1137,82 @@ void Image::create( const char ** p_xpm ) { }\ } +#define DETECT_NON_ALPHA( m_value )\ +{ \ + uint8_t value=m_value;\ + if (value>0) {\ + \ + detected=true;\ + break;\ + }\ +} + + +bool Image::is_invisible() const { + + if (format==FORMAT_GRAYSCALE || + format==FORMAT_RGB || + format==FORMAT_INDEXED) + return false; + + int len = data.size(); + + if (len==0) + return true; + + if (format >= FORMAT_YUV_422 && format <= FORMAT_YUV_444) + return false; + + int w,h; + _get_mipmap_offset_and_size(1,len,w,h); + + DVector<uint8_t>::Read r = data.read(); + const unsigned char *data_ptr=r.ptr(); + + bool detected=false; + + switch(format) { + case FORMAT_INTENSITY: { + + for(int i=0;i<len;i++) { + DETECT_NON_ALPHA(data_ptr[i]); + } + } break; + case FORMAT_GRAYSCALE_ALPHA: { + + + for(int i=0;i<(len>>1);i++) { + DETECT_NON_ALPHA(data_ptr[(i<<1)+1]); + } + + } break; + case FORMAT_RGBA: { + + for(int i=0;i<(len>>2);i++) { + DETECT_NON_ALPHA(data_ptr[(i<<2)+3]) + } + + } break; + case FORMAT_INDEXED: { + + return false; + } break; + case FORMAT_INDEXED_ALPHA: { + + return false; + } break; + case FORMAT_PVRTC2_ALPHA: + case FORMAT_PVRTC4_ALPHA: + case FORMAT_BC2: + case FORMAT_BC3: { + detected=true; + } break; + default: {} + } + + return !detected; +} + Image::AlphaMode Image::detect_alpha() const { if (format==FORMAT_GRAYSCALE || @@ -1746,6 +1823,10 @@ Error Image::_decompress_bc() { return OK; } +bool Image::is_compressed() const { + return format>=FORMAT_BC1; +} + Image Image::decompressed() const { @@ -1998,7 +2079,7 @@ void Image::blit_rect(const Image& p_src, const Rect2& p_src_rect,const Point2& } -Image (*Image::_png_mem_loader_func)(const uint8_t*)=NULL; +Image (*Image::_png_mem_loader_func)(const uint8_t*,int)=NULL; void (*Image::_image_compress_bc_func)(Image *)=NULL; void (*Image::_image_compress_pvrtc2_func)(Image *)=NULL; void (*Image::_image_compress_pvrtc4_func)(Image *)=NULL; @@ -2167,7 +2248,7 @@ void Image::fix_alpha_edges() { } -Image::Image(const uint8_t* p_png) { +Image::Image(const uint8_t* p_png,int p_len) { width=0; height=0; @@ -2175,7 +2256,7 @@ Image::Image(const uint8_t* p_png) { format=FORMAT_GRAYSCALE; if (_png_mem_loader_func) { - *this = _png_mem_loader_func(p_png); + *this = _png_mem_loader_func(p_png,p_len); } } diff --git a/core/image.h b/core/image.h index ddb5e88ebf..8ce4f22dc1 100644 --- a/core/image.h +++ b/core/image.h @@ -94,7 +94,7 @@ public: /* INTERPOLATE GAUSS */ }; - static Image (*_png_mem_loader_func)(const uint8_t* p_png); + static Image (*_png_mem_loader_func)(const uint8_t* p_png,int p_size); static void (*_image_compress_bc_func)(Image *); static void (*_image_compress_pvrtc2_func)(Image *); static void (*_image_compress_pvrtc4_func)(Image *); @@ -305,6 +305,7 @@ public: }; AlphaMode detect_alpha() const; + bool is_invisible() const; void put_indexed_pixel(int p_x, int p_y, uint8_t p_idx,int p_mipmap=0); uint8_t get_indexed_pixel(int p_x, int p_y,int p_mipmap=0) const; @@ -335,6 +336,7 @@ public: Image compressed(int p_mode); /* from the Image::CompressMode enum */ Error decompress(); Image decompressed() const; + bool is_compressed() const; void fix_alpha_edges(); void premultiply_alpha(); @@ -349,7 +351,7 @@ public: Image get_rect(const Rect2& p_area) const; static void set_compress_bc_func(void (*p_compress_func)(Image *)); - Image(const uint8_t* p_mem_png); + Image(const uint8_t* p_mem_png, int p_len=-1); Image(const char **p_xpm); ~Image(); diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 2880c4ebda..83da55fc61 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -74,6 +74,14 @@ bool FileAccessMemory::file_exists(const String& p_name) { } +Error FileAccessMemory::open_custom(const uint8_t* p_data, int p_len) { + + data=(uint8_t*)p_data; + length=p_len; + pos=0; + return OK; +} + Error FileAccessMemory::_open(const String& p_path, int p_mode_flags) { ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND); diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index 5a9ec2b3c6..8c58a8a8ce 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -44,6 +44,7 @@ public: static void register_file(String p_name, Vector<uint8_t> p_data); static void cleanup(); + virtual Error open_custom(const uint8_t* p_data, int p_len); ///< open a file virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file virtual void close(); ///< close a file virtual bool is_open() const; ///< true when file is open diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index 7a1b6454bd..ab2eb3b3f2 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -31,6 +31,7 @@ #include "file_access_zip.h" #include "core/os/file_access.h" +#include "core/os/copymem.h" ZipArchive* ZipArchive::instance = NULL; @@ -103,9 +104,17 @@ static int godot_testerror(voidpf opaque, voidpf stream) { return f->get_error()!=OK?1:0; }; +static voidpf godot_alloc(voidpf opaque, uInt items, uInt size) { + return memalloc(items * size); }; +static void godot_free(voidpf opaque, voidpf address) { + + memfree(address); +}; + +}; // extern "C" void ZipArchive::close_handle(unzFile p_file) const { @@ -125,6 +134,7 @@ unzFile ZipArchive::get_file_handle(String p_file) const { ERR_FAIL_COND_V(!f, NULL); zlib_filefunc_def io; + zeromem(&io, sizeof(io)); io.opaque = f; io.zopen_file = godot_open; @@ -136,9 +146,13 @@ unzFile ZipArchive::get_file_handle(String p_file) const { io.zclose_file = godot_close; io.zerror_file = godot_testerror; + io.alloc_mem = godot_alloc; + io.free_mem = godot_free; + unzFile pkg = unzOpen2(packages[file.package].filename.utf8().get_data(), &io); ERR_FAIL_COND_V(!pkg, NULL); - unzGoToFilePos(pkg, &file.file_pos); + int unz_err = unzGoToFilePos(pkg, &file.file_pos); + ERR_FAIL_COND_V(unz_err != UNZ_OK, NULL); if (unzOpenCurrentFile(pkg) != UNZ_OK) { unzClose(pkg); @@ -150,7 +164,7 @@ unzFile ZipArchive::get_file_handle(String p_file) const { bool ZipArchive::try_open_pack(const String& p_name) { - //printf("opening pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz")); + //printf("opening zip pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz")); if (p_name.extension().nocasecmp_to("zip") != 0 && p_name.extension().nocasecmp_to("pcz") != 0) return false; @@ -198,7 +212,8 @@ bool ZipArchive::try_open_pack(const String& p_name) { files[fname] = f; uint8_t md5[16]={0,0,0,0,0,0,0,0 , 0,0,0,0,0,0,0,0}; - PackedData::get_singleton()->add_path(p_name, fname, 0, 0, md5, this); + PackedData::get_singleton()->add_path(p_name, fname, 1, 0, md5, this); + //printf("packed data add path %ls, %ls\n", p_name.c_str(), fname.c_str()); if ((i+1)<gi.number_entry) { unzGoToNextFile(zfile); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 3d7d2f2367..9fb17bcffb 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -861,7 +861,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { print_bl("minor: "+itos(ver_minor)); print_bl("format: "+itos(ver_format)); - if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) { + if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR) { f->close(); ERR_EXPLAIN("File Format '"+itos(FORMAT_VERSION)+"."+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+local_path); @@ -968,7 +968,7 @@ String ResourceInteractiveLoaderBinary::recognize(FileAccess *p_f) { uint32_t ver_minor=f->get_32(); uint32_t ver_format=f->get_32(); - if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) { + if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR) { f->close(); return ""; diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp index ce648523f0..3c100d375a 100644 --- a/core/io/resource_format_xml.cpp +++ b/core/io/resource_format_xml.cpp @@ -1671,7 +1671,7 @@ void ResourceInteractiveLoaderXML::open(FileAccess *p_f) { int major = version.get_slice(".",0).to_int(); int minor = version.get_slice(".",1).to_int(); - if (major>VERSION_MAJOR || (major==VERSION_MAJOR && minor>VERSION_MINOR)) { + if (major>VERSION_MAJOR) { error=ERR_FILE_UNRECOGNIZED; ResourceLoader::notify_load_error(local_path+": File Format '"+version+"' is too new. Please upgrade to a newer engine version."); diff --git a/core/object.cpp b/core/object.cpp index 1a51e79a9f..83a6dada80 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -995,12 +995,44 @@ Variant Object::get_meta(const String& p_name) const { return metadata[p_name]; } + Array Object::_get_property_list_bind() const { List<PropertyInfo> lpi; get_property_list(&lpi); return convert_property_list(&lpi); } + +Array Object::_get_method_list_bind() const { + + List<MethodInfo> ml; + get_method_list(&ml); + Array ret; + + for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) { + + Dictionary d; + d["name"]=E->get().name; + d["args"]=convert_property_list(&E->get().arguments); + Array da; + for(int i=0;i<E->get().default_arguments.size();i++) + da.push_back(E->get().default_arguments[i]); + d["default_args"]=da; + d["flags"]=E->get().flags; + d["id"]=E->get().id; + Dictionary r; + r["type"]=E->get().return_val.type; + r["hint"]=E->get().return_val.hint; + r["hint_string"]=E->get().return_val.hint_string; + d["return_type"]=r; + //va.push_back(d); + ret.push_back(d); + } + + return ret; + +} + DVector<String> Object::_get_meta_list_bind() const { DVector<String> _metaret; @@ -1319,7 +1351,7 @@ Error Object::connect(const StringName& p_signal, Object *p_to_object, const Str if (!s) { bool signal_is_valid = ObjectTypeDB::has_signal(get_type_name(),p_signal); if (!signal_is_valid) { - ERR_EXPLAIN("Attempt to connect to nonexistent signal: "+p_signal); + ERR_EXPLAIN("Attempt to connect nonexistent signal '"+p_signal+"' to method '"+p_to_method+"'"); ERR_FAIL_COND_V(!signal_is_valid,ERR_INVALID_PARAMETER); } signal_map[p_signal]=Signal(); @@ -1439,6 +1471,7 @@ void Object::_bind_methods() { ObjectTypeDB::bind_method(_MD("set","property","value"),&Object::_set_bind); ObjectTypeDB::bind_method(_MD("get","property"),&Object::_get_bind); ObjectTypeDB::bind_method(_MD("get_property_list"),&Object::_get_property_list_bind); + ObjectTypeDB::bind_method(_MD("get_method_list"),&Object::_get_method_list_bind); ObjectTypeDB::bind_method(_MD("notification","what"),&Object::notification,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_instance_ID"),&Object::get_instance_ID); diff --git a/core/object.h b/core/object.h index fc64b91412..8d1f8ebc5a 100644 --- a/core/object.h +++ b/core/object.h @@ -54,6 +54,7 @@ enum PropertyHint { PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing funciton (Math::ease) PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) + PROPERTY_HINT_SPRITE_FRAME, PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer) PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags) PROPERTY_HINT_ALL_FLAGS, @@ -448,6 +449,7 @@ protected: DVector<String> _get_meta_list_bind() const; Array _get_property_list_bind() const; + Array _get_method_list_bind() const; public: //should be protected, but bug in clang++ static void initialize_type(); diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index a1031cf5f0..d0baae5872 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -56,6 +56,17 @@ String DirAccess::_get_root_string() const { return ""; } +int DirAccess::get_current_drive() { + + String path = get_current_dir().to_lower(); + for(int i=0;i<get_drive_count();i++) { + String d = get_drive(i).to_lower(); + if (path.begins_with(d)) + return i; + } + + return 0; +} static Error _erase_recursive(DirAccess *da) { diff --git a/core/os/dir_access.h b/core/os/dir_access.h index 3df9bca45a..8bacc96c60 100644 --- a/core/os/dir_access.h +++ b/core/os/dir_access.h @@ -84,6 +84,7 @@ public: virtual int get_drive_count()=0; virtual String get_drive(int p_drive)=0; + virtual int get_current_drive(); virtual Error change_dir(String p_dir)=0; ///< can be relative or absolute, return false on success virtual String get_current_dir()=0; ///< return current dir location diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index 83d3155b03..b4c02ddbce 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -31,7 +31,20 @@ void MainLoop::_bind_methods() { - ObjectTypeDB::bind_method("input_event",&MainLoop::input_event); + ObjectTypeDB::bind_method(_MD("input_event","ev"),&MainLoop::input_event); + ObjectTypeDB::bind_method(_MD("input_text","text"),&MainLoop::input_text); + ObjectTypeDB::bind_method(_MD("init"),&MainLoop::init); + ObjectTypeDB::bind_method(_MD("iteration","delta"),&MainLoop::iteration); + ObjectTypeDB::bind_method(_MD("idle","delta"),&MainLoop::idle); + ObjectTypeDB::bind_method(_MD("finish"),&MainLoop::finish); + + BIND_VMETHOD( MethodInfo("_input_event",PropertyInfo(Variant::INPUT_EVENT,"ev")) ); + BIND_VMETHOD( MethodInfo("_input_text",PropertyInfo(Variant::STRING,"text")) ); + BIND_VMETHOD( MethodInfo("_initialize") ); + BIND_VMETHOD( MethodInfo("_iteration",PropertyInfo(Variant::REAL,"delta")) ); + BIND_VMETHOD( MethodInfo("_idle",PropertyInfo(Variant::REAL,"delta")) ); + BIND_VMETHOD( MethodInfo("_finalize") ); + BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN); BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT); @@ -58,13 +71,15 @@ MainLoop::~MainLoop() void MainLoop::input_text( const String& p_text ) { + if (get_script_instance()) + get_script_instance()->call("_input_text",p_text); } void MainLoop::input_event( const InputEvent& p_event ) { if (get_script_instance()) - get_script_instance()->call("input_event",p_event); + get_script_instance()->call("_input_event",p_event); } @@ -74,13 +89,13 @@ void MainLoop::init() { set_script(init_script.get_ref_ptr()); if (get_script_instance()) - get_script_instance()->call("init"); + get_script_instance()->call("_initialize"); } bool MainLoop::iteration(float p_time) { if (get_script_instance()) - return get_script_instance()->call("iteration",p_time); + return get_script_instance()->call("_iteration",p_time); return false; @@ -88,14 +103,14 @@ bool MainLoop::iteration(float p_time) { bool MainLoop::idle(float p_time) { if (get_script_instance()) - return get_script_instance()->call("idle",p_time); + return get_script_instance()->call("_idle",p_time); return false; } void MainLoop::finish() { if (get_script_instance()) { - get_script_instance()->call("finish"); + get_script_instance()->call("_finalize"); set_script(RefPtr()); //clear script } diff --git a/core/variant.cpp b/core/variant.cpp index d7817ac268..034dc2b4fc 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -302,8 +302,8 @@ bool Variant::can_convert(Variant::Type p_type_from,Variant::Type p_type_to) { case COLOR: { static const Type valid[] = { - //STRING, - //INT, + STRING, + INT, NIL, }; @@ -1653,6 +1653,10 @@ Variant::operator Color() const { if (type==COLOR) return *reinterpret_cast<const Color*>(_data._mem); + else if (type==STRING) + return Color::html( operator String() ); + else if (type==INT) + return Color::hex( operator int() ); else return Color(); } diff --git a/demos/2d/kinematic_char/engine.cfg b/demos/2d/kinematic_char/engine.cfg index 0132442c18..4ce8f836ae 100644 --- a/demos/2d/kinematic_char/engine.cfg +++ b/demos/2d/kinematic_char/engine.cfg @@ -4,6 +4,13 @@ name="Kinematic Collision" main_scene="res://colworld.scn" icon="res://icon.png" +[display] + +width=800 +height=600 +stretch_mode="2d" +stretch_aspect="keep" + [input] move_up=[key(Up)] diff --git a/demos/2d/lights_shadows/engine.cfg b/demos/2d/lights_shadows/engine.cfg index 7e028c3556..771288c209 100644 --- a/demos/2d/lights_shadows/engine.cfg +++ b/demos/2d/lights_shadows/engine.cfg @@ -6,6 +6,9 @@ main_scene="res://light_shadows.scn" [display] stretch_mode="2d" +width=800 +height=600 +stretch_aspect="keep" [rasterizer] diff --git a/demos/2d/motion/engine.cfg b/demos/2d/motion/engine.cfg index cf16105b1c..29c4d0da20 100644 --- a/demos/2d/motion/engine.cfg +++ b/demos/2d/motion/engine.cfg @@ -3,3 +3,12 @@ name="Motion Test" main_scene="res://motion.scn" +<<<<<<< HEAD +======= +[display] + +width=800 +height=600 +stretch_mode="2d" +stretch_aspect="keep" +>>>>>>> ab99671bb835a5fe24a092ec34afe1ad862ac254 diff --git a/demos/2d/navpoly/engine.cfg b/demos/2d/navpoly/engine.cfg index 51eefd7b77..40515dd3d2 100644 --- a/demos/2d/navpoly/engine.cfg +++ b/demos/2d/navpoly/engine.cfg @@ -2,3 +2,10 @@ name="Navigation Polygon (2D)" main_scene="res://navigation.scn" + +[display] + +width=800 +height=600 +stretch_mode="2d" +stretch_aspect="keep" diff --git a/demos/2d/normalmaps/engine.cfg b/demos/2d/normalmaps/engine.cfg index 3fc2048716..f0002dc2b8 100644 --- a/demos/2d/normalmaps/engine.cfg +++ b/demos/2d/normalmaps/engine.cfg @@ -2,3 +2,10 @@ name="2D Normal Mapping" main_scene="res://normalmap.scn" + +[display] + +stretch_mode="2d" +width=800 +height=600 +stretch_aspect="ignore" diff --git a/demos/2d/screen_space_shaders/engine.cfg b/demos/2d/screen_space_shaders/engine.cfg index 108fdeba34..527e2f8f0a 100644 --- a/demos/2d/screen_space_shaders/engine.cfg +++ b/demos/2d/screen_space_shaders/engine.cfg @@ -3,3 +3,9 @@ name="Screen-Space Shaders" main_scene="res://screen_shaders.scn" +[display] + +width=780 +height=600 +stretch_mode="2d" +stretch_aspect="keep" diff --git a/demos/2d/screen_space_shaders/screen_shaders.scn b/demos/2d/screen_space_shaders/screen_shaders.scn Binary files differindex cc62ac8203..fc2be96fc9 100644 --- a/demos/2d/screen_space_shaders/screen_shaders.scn +++ b/demos/2d/screen_space_shaders/screen_shaders.scn diff --git a/demos/2d/texscreen/bubbles.scn b/demos/2d/texscreen/bubbles.scn Binary files differindex 779cba6930..41026aceed 100644 --- a/demos/2d/texscreen/bubbles.scn +++ b/demos/2d/texscreen/bubbles.scn diff --git a/demos/2d/texscreen/engine.cfg b/demos/2d/texscreen/engine.cfg index 58193c8c4a..fb683dfc1d 100644 --- a/demos/2d/texscreen/engine.cfg +++ b/demos/2d/texscreen/engine.cfg @@ -2,3 +2,10 @@ name="Glass Bubbles (Texscreen)" main_scene="res://bubbles.scn" + +[display] + +width=800 +height=600 +stretch_mode="2d" +stretch_aspect="keep" diff --git a/demos/gui/input_mapping/controls.gd b/demos/gui/input_mapping/controls.gd new file mode 100644 index 0000000000..6ca059c812 --- /dev/null +++ b/demos/gui/input_mapping/controls.gd @@ -0,0 +1,49 @@ +# Note for the reader: +# +# This demo conveniently uses the same names for actions and for the container nodes +# that hold each remapping button. This allow to get back to the button based simply +# on the name of the corresponding action, but it might not be so simple in your project. +# +# A better approach for large-scale input remapping might be to do the connections between +# buttons and wait_for_input through the code, passing as arguments both the name of the +# action and the node, e.g.: +# button.connect("pressed", self, "wait_for_input", [ button, action ]) + +extends Control + +var player_actions = [ "move_up", "move_down", "move_left", "move_right", "jump" ] +var action # To register the action the UI is currently handling +var button # Button node corresponding to the above action + +func wait_for_input(action_bind): + action = action_bind + # See note at the beginning of the script + button = get_node("bindings").get_node(action).get_node("Button") + get_node("contextual_help").set_text("Press a key to assign to the '" + action + "' action.") + set_process_input(true) + +func _input(event): + # Handle the first pressed key + if (event.type == InputEvent.KEY): + # Register the event as handled and stop polling + get_tree().set_input_as_handled() + set_process_input(false) + # Reinitialise the contextual help label + get_node("contextual_help").set_text("Click a key binding to reassign it, or press the Cancel action.") + if (not event.is_action("ui_cancel")): + # Display the string corresponding to the pressed key + button.set_text(OS.get_scancode_string(event.scancode)) + # Start by removing previously key binding(s) + for old_event in InputMap.get_action_list(action): + InputMap.action_erase_event(action, old_event) + # Add the new key binding + InputMap.action_add_event(action, event) + +func _ready(): + # Initialise each button with the default key binding from InputMap + var input_event + for action in player_actions: + # We assume that the key binding that we want is the first one (0), if there are several + input_event = InputMap.get_action_list(action)[0] + # See note at the beginning of the script + get_node("bindings").get_node(action).get_node("Button").set_text(OS.get_scancode_string(input_event.scancode)) diff --git a/demos/gui/input_mapping/controls.scn b/demos/gui/input_mapping/controls.scn Binary files differnew file mode 100644 index 0000000000..276712ba22 --- /dev/null +++ b/demos/gui/input_mapping/controls.scn diff --git a/demos/gui/input_mapping/engine.cfg b/demos/gui/input_mapping/engine.cfg new file mode 100644 index 0000000000..959c0ac7d5 --- /dev/null +++ b/demos/gui/input_mapping/engine.cfg @@ -0,0 +1,18 @@ +[application] + +name="Input Mapping GUI" +main_scene="res://controls.scn" +icon="icon.png" + +[display] + +width=640 +height=480 + +[input] + +move_up=[key(Up)] +move_down=[key(Down)] +move_left=[key(Left)] +move_right=[key(Right)] +jump=[key(Space)] diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index 2e1488ff9d..2a4720b07b 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -31,6 +31,8 @@ #include "print_string.h" #include "os/os.h" + + void ImageLoaderPNG::_read_png_data(png_structp png_ptr,png_bytep data, png_size_t p_length) { FileAccess *f = (FileAccess*)png_get_io_ptr(png_ptr); @@ -253,6 +255,7 @@ void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const struct PNGReadStatus { int offset; + int size; const unsigned char *image; }; @@ -261,17 +264,26 @@ static void user_read_data(png_structp png_ptr,png_bytep data, png_size_t p_leng PNGReadStatus *rstatus; rstatus=(PNGReadStatus*)png_get_io_ptr(png_ptr); - memcpy(data,&rstatus->image[rstatus->offset],p_length); - rstatus->offset+=p_length; + int to_read=p_length; + if (rstatus->size>=0) { + to_read = MIN( p_length, rstatus->size - rstatus->offset); + } + memcpy(data,&rstatus->image[rstatus->offset],to_read); + rstatus->offset+=to_read; + + if (to_read<p_length) { + memset(&data[to_read],0,p_length-to_read); + } } -static Image _load_mem_png(const uint8_t* p_png) { +static Image _load_mem_png(const uint8_t* p_png,int p_size) { PNGReadStatus prs; prs.image=p_png; prs.offset=0; + prs.size=p_size; Image img; Error err = ImageLoaderPNG::_load_image(&prs,user_read_data,&img); @@ -283,9 +295,10 @@ static Image _load_mem_png(const uint8_t* p_png) { static Image _lossless_unpack_png(const DVector<uint8_t>& p_data) { + int len = p_data.size(); DVector<uint8_t>::Read r = p_data.read(); ERR_FAIL_COND_V(r[0]!='P' || r[1]!='N' || r[2]!='G' || r[3]!=' ',Image()); - return _load_mem_png(&r[4]); + return _load_mem_png(&r[4],len-4); } @@ -424,6 +437,7 @@ static DVector<uint8_t> _lossless_pack_png(const Image& p_image) { ImageLoaderPNG::ImageLoaderPNG() { + Image::_png_mem_loader_func=_load_mem_png; Image::lossless_unpacker=_lossless_unpack_png; Image::lossless_packer=_lossless_pack_png; diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h index 7acfd041ee..8413a7eae1 100644 --- a/drivers/png/image_loader_png.h +++ b/drivers/png/image_loader_png.h @@ -40,7 +40,10 @@ class ImageLoaderPNG : public ImageFormatLoader { static void _read_png_data(png_structp png_ptr,png_bytep data, png_size_t p_length); + public: + + static Error _load_image(void *rf_up,png_rw_ptr p_func,Image *p_image); virtual Error load_image(Image *p_image,FileAccess *f); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/main/main.cpp b/main/main.cpp index c02f90e701..2d5039b658 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1356,6 +1356,8 @@ bool Main::iteration() { message_queue->flush(); PhysicsServer::get_singleton()->step(frame_slice*time_scale); + + Physics2DServer::get_singleton()->end_sync(); Physics2DServer::get_singleton()->step(frame_slice*time_scale); time_accum-=frame_slice; diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 6ce62bfae2..3158254781 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -437,6 +437,7 @@ public: } + int ac = E->get().argtypes.size(); if (ac<p_argcount) { @@ -455,7 +456,6 @@ public: } - for(int i=0;i<p_argcount;i++) { if (!Variant::can_convert(p_args[i]->get_type(),E->get().argtypes[i])) { @@ -476,6 +476,10 @@ public: JNIEnv *env = ThreadAndroid::get_env(); + int res = env->PushLocalFrame(16); + + ERR_FAIL_COND_V(res!=0,Variant()); + //print_line("argcount "+String::num(p_argcount)); List<jobject> to_erase; for(int i=0;i<p_argcount;i++) { @@ -568,6 +572,7 @@ public: print_line("failure.."); + env->PopLocalFrame(NULL); ERR_FAIL_V(Variant()); } break; } @@ -576,6 +581,8 @@ public: env->DeleteLocalRef(to_erase.front()->get()); to_erase.pop_front(); } + + env->PopLocalFrame(NULL); //print_line("success"); return ret; @@ -1613,11 +1620,15 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_method(JNIEnv * env, jobj JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_callobject(JNIEnv * env, jobject p_obj, jint ID, jstring method, jobjectArray params) { - String str_method = env->GetStringUTFChars( method, NULL ); - Object* obj = ObjectDB::get_instance(ID); ERR_FAIL_COND(!obj); + int res = env->PushLocalFrame(16); + ERR_FAIL_COND(res!=0); + + String str_method = env->GetStringUTFChars( method, NULL ); + + int count = env->GetArrayLength(params); Variant* vlist = (Variant*)alloca(sizeof(Variant) * count); Variant** vptr = (Variant**)alloca(sizeof(Variant*) * count); @@ -1637,15 +1648,22 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_callobject(JNIEnv * env, Variant::CallError err; obj->call(str_method, (const Variant**)vptr, count, err); // something + + env->PopLocalFrame(NULL); + }; JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_calldeferred(JNIEnv * env, jobject p_obj, jint ID, jstring method, jobjectArray params) { - String str_method = env->GetStringUTFChars( method, NULL ); Object* obj = ObjectDB::get_instance(ID); ERR_FAIL_COND(!obj); + int res = env->PushLocalFrame(16); + ERR_FAIL_COND(res!=0); + + String str_method = env->GetStringUTFChars( method, NULL ); + int count = env->GetArrayLength(params); Variant args[VARIANT_ARG_MAX]; @@ -1666,6 +1684,8 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_calldeferred(JNIEnv * env obj->call_deferred(str_method, args[0],args[1],args[2],args[3],args[4]); // something + env->PopLocalFrame(NULL); + }; //Main::cleanup(); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 80953df85f..612148418b 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -163,7 +163,8 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_ // physics_server = memnew( PhysicsServerSW ); physics_server->init(); - physics_2d_server = memnew( Physics2DServerSW ); + //physics_2d_server = memnew( Physics2DServerSW ); + physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); physics_2d_server->init(); input = memnew( InputDefault ); diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 41892d23b4..7a5a55653f 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -37,6 +37,7 @@ #include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h" #include "servers/audio/audio_server_sw.h" #include "servers/physics_2d/physics_2d_server_sw.h" +#include "servers/physics_2d/physics_2d_server_wrap_mt.h" #include "servers/visual/rasterizer.h" diff --git a/platform/iphone/game_center.h b/platform/iphone/game_center.h index 1f4820a3c2..8f180d1638 100644 --- a/platform/iphone/game_center.h +++ b/platform/iphone/game_center.h @@ -51,6 +51,12 @@ public: Error post_score(Variant p_score); Error award_achievement(Variant p_params); + void reset_achievements(); + void request_achievements(); + void request_achievement_descriptions(); + Error show_game_center(Variant p_params); + + void game_center_closed(); int get_pending_event_count(); Variant pop_pending_event(); diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm index fd1e5f3be7..79c056776d 100644 --- a/platform/iphone/game_center.mm +++ b/platform/iphone/game_center.mm @@ -32,6 +32,7 @@ extern "C" { #import <GameKit/GameKit.h> +#import "app_delegate.h" }; GameCenter* GameCenter::instance = NULL; @@ -42,6 +43,10 @@ void GameCenter::_bind_methods() { ObjectTypeDB::bind_method(_MD("post_score"),&GameCenter::post_score); ObjectTypeDB::bind_method(_MD("award_achievement"),&GameCenter::award_achievement); + ObjectTypeDB::bind_method(_MD("reset_achievements"),&GameCenter::reset_achievements); + ObjectTypeDB::bind_method(_MD("request_achievements"),&GameCenter::request_achievements); + ObjectTypeDB::bind_method(_MD("request_achievement_descriptions"),&GameCenter::request_achievement_descriptions); + ObjectTypeDB::bind_method(_MD("show_game_center"),&GameCenter::show_game_center); ObjectTypeDB::bind_method(_MD("get_pending_event_count"),&GameCenter::get_pending_event_count); ObjectTypeDB::bind_method(_MD("pop_pending_event"),&GameCenter::pop_pending_event); @@ -50,23 +55,41 @@ void GameCenter::_bind_methods() { Error GameCenter::connect() { - GKLocalPlayer* player = [GKLocalPlayer localPlayer]; - [player authenticateWithCompletionHandler:^(NSError* error) { + //if this class isn't available, game center isn't implemented + if ((NSClassFromString(@"GKLocalPlayer")) == nil) { + GameCenter::get_singleton()->connected = false; + return ERR_UNAVAILABLE; + } - Dictionary ret; - ret["type"] = "authentication"; - if (player.isAuthenticated) { - ret["result"] = "ok"; - GameCenter::get_singleton()->connected = true; - } else { - ret["result"] = "error"; - ret["error_code"] = error.code; - ret["error_description"] = [error.localizedDescription UTF8String]; - GameCenter::get_singleton()->connected = false; - }; + GKLocalPlayer* player = [GKLocalPlayer localPlayer]; + ERR_FAIL_COND_V(![player respondsToSelector:@selector(authenticateHandler)], ERR_UNAVAILABLE); + + ViewController *root_controller=(ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController; + ERR_FAIL_COND_V(!root_controller, FAILED); + + //this handler is called serveral times. first when the view needs to be shown, then again after the view is cancelled or the user logs in. or if the user's already logged in, it's called just once to confirm they're authenticated. This is why no result needs to be specified in the presentViewController phase. in this case, more calls to this function will follow. + player.authenticateHandler = (^(UIViewController *controller, NSError *error) { + if (controller) { + [root_controller presentViewController:controller animated:YES completion:nil]; + } + else { + Dictionary ret; + ret["type"] = "authentication"; + if (player.isAuthenticated) { + ret["result"] = "ok"; + GameCenter::get_singleton()->connected = true; + } else { + ret["result"] = "error"; + ret["error_code"] = error.code; + ret["error_description"] = [error.localizedDescription UTF8String]; + GameCenter::get_singleton()->connected = false; + }; + + pending_events.push_back(ret); + }; + + }); - pending_events.push_back(ret); - }]; return OK; }; @@ -85,7 +108,9 @@ Error GameCenter::post_score(Variant p_score) { GKScore* reporter = [[[GKScore alloc] initWithCategory:cat_str] autorelease]; reporter.value = score; - [reporter reportScoreWithCompletionHandler:^(NSError* error) { + ERR_FAIL_COND_V([GKScore respondsToSelector:@selector(reportScores)], ERR_UNAVAILABLE); + + [GKScore reportScores:@[reporter] withCompletionHandler:^(NSError* error) { Dictionary ret; ret["type"] = "post_score"; @@ -114,8 +139,15 @@ Error GameCenter::award_achievement(Variant p_params) { GKAchievement* achievement = [[[GKAchievement alloc] initWithIdentifier: name_str] autorelease]; ERR_FAIL_COND_V(!achievement, FAILED); + ERR_FAIL_COND_V([GKAchievement respondsToSelector:@selector(reportAchievements)], ERR_UNAVAILABLE); + achievement.percentComplete = progress; - [achievement reportAchievementWithCompletionHandler:^(NSError* error) { + achievement.showsCompletionBanner = NO; + if (params.has("show_completion_banner")) { + achievement.showsCompletionBanner = params["show_completion_banner"] ? YES : NO; + } + + [GKAchievement reportAchievements:@[achievement] withCompletionHandler:^(NSError *error) { Dictionary ret; ret["type"] = "award_achievement"; @@ -132,6 +164,168 @@ Error GameCenter::award_achievement(Variant p_params) { return OK; }; +void GameCenter::request_achievement_descriptions() { + + [GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:^(NSArray *descriptions, NSError *error) { + + Dictionary ret; + ret["type"] = "achievement_descriptions"; + if (error == nil) { + ret["result"] = "ok"; + StringArray names; + StringArray titles; + StringArray unachieved_descriptions; + StringArray achieved_descriptions; + IntArray maximum_points; + Array hidden; + Array replayable; + + for (int i=0; i<[descriptions count]; i++) { + + GKAchievementDescription* description = [descriptions objectAtIndex:i]; + + const char* str = [description.identifier UTF8String]; + names.push_back(String::utf8(str != NULL ? str : "")); + + str = [description.title UTF8String]; + titles.push_back(String::utf8(str != NULL ? str : "")); + + str = [description.unachievedDescription UTF8String]; + unachieved_descriptions.push_back(String::utf8(str != NULL ? str : "")); + + str = [description.achievedDescription UTF8String]; + achieved_descriptions.push_back(String::utf8(str != NULL ? str : "")); + + maximum_points.push_back(description.maximumPoints); + + hidden.push_back(description.hidden == YES); + + replayable.push_back(description.replayable == YES); + } + + ret["names"] = names; + ret["titles"] = titles; + ret["unachieved_descriptions"] = unachieved_descriptions; + ret["achieved_descriptions"] = achieved_descriptions; + ret["maximum_points"] = maximum_points; + ret["hidden"] = hidden; + ret["replayable"] = replayable; + + } else { + ret["result"] = "error"; + ret["error_code"] = error.code; + }; + + pending_events.push_back(ret); + }]; +}; + + +void GameCenter::request_achievements() { + + [GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) { + + Dictionary ret; + ret["type"] = "achievements"; + if (error == nil) { + ret["result"] = "ok"; + StringArray names; + RealArray percentages; + + for (int i=0; i<[achievements count]; i++) { + + GKAchievement* achievement = [achievements objectAtIndex:i]; + const char* str = [achievement.identifier UTF8String]; + names.push_back(String::utf8(str != NULL ? str : "")); + + percentages.push_back(achievement.percentComplete); + } + + ret["names"] = names; + ret["progress"] = percentages; + + } else { + ret["result"] = "error"; + ret["error_code"] = error.code; + }; + + pending_events.push_back(ret); + }]; +}; + +void GameCenter::reset_achievements() { + + [GKAchievement resetAchievementsWithCompletionHandler:^(NSError *error) + { + Dictionary ret; + ret["type"] = "reset_achievements"; + if (error == nil) { + ret["result"] = "ok"; + } else { + ret["result"] = "error"; + ret["error_code"] = error.code; + }; + + pending_events.push_back(ret); + }]; +}; + +Error GameCenter::show_game_center(Variant p_params) { + + ERR_FAIL_COND_V(!NSProtocolFromString(@"GKGameCenterControllerDelegate"), FAILED); + + Dictionary params = p_params; + + GKGameCenterViewControllerState view_state = GKGameCenterViewControllerStateDefault; + if (params.has("view")) { + String view_name = params["view"]; + if (view_name == "default") { + view_state = GKGameCenterViewControllerStateDefault; + } + else if (view_name == "leaderboards") { + view_state = GKGameCenterViewControllerStateLeaderboards; + } + else if (view_name == "achievements") { + view_state = GKGameCenterViewControllerStateAchievements; + } + else if (view_name == "challenges") { + view_state = GKGameCenterViewControllerStateChallenges; + } + else { + return ERR_INVALID_PARAMETER; + } + } + + GKGameCenterViewController *controller = [[GKGameCenterViewController alloc] init]; + ERR_FAIL_COND_V(!controller, FAILED); + + ViewController *root_controller=(ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController; + ERR_FAIL_COND_V(!root_controller, FAILED); + + controller.gameCenterDelegate = root_controller; + controller.viewState = view_state; + if (view_state == GKGameCenterViewControllerStateLeaderboards) { + controller.leaderboardIdentifier = nil; + if (params.has("leaderboard_name")) { + String name = params["leaderboard_name"]; + NSString* name_str = [[[NSString alloc] initWithUTF8String:name.utf8().get_data()] autorelease]; + controller.leaderboardIdentifier = name_str; + } + } + + [root_controller presentViewController: controller animated: YES completion:nil]; + + return OK; +}; + +void GameCenter::game_center_closed() { + + Dictionary ret; + ret["type"] = "show_game_center"; + ret["result"] = "ok"; + pending_events.push_back(ret); +} + int GameCenter::get_pending_event_count() { return pending_events.size(); diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm index 1d40b1762e..e3ba6bbd73 100644 --- a/platform/iphone/in_app_store.mm +++ b/platform/iphone/in_app_store.mm @@ -210,7 +210,7 @@ Error InAppStore::request_product_info(Variant p_params) { receipt_to_send = [receipt description]; } Dictionary receipt_ret; - receipt_ret["receipt"] = String::utf8([receipt_to_send UTF8String]); + receipt_ret["receipt"] = String::utf8(receipt_to_send != nil ? [receipt_to_send UTF8String] : ""); receipt_ret["sdk"] = sdk_version; ret["receipt"] = receipt_ret; diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index bf85ecc9dd..ade1c292a4 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -136,7 +136,8 @@ void OSIPhone::initialize(const VideoMode& p_desired,int p_video_driver,int p_au // physics_server = memnew( PhysicsServerSW ); physics_server->init(); - physics_2d_server = memnew( Physics2DServerSW ); + //physics_2d_server = memnew( Physics2DServerSW ); + physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); physics_2d_server->init(); input = memnew( InputDefault ); diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 721db36f41..844f067552 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -38,6 +38,7 @@ #include "servers/visual/rasterizer.h" #include "servers/physics/physics_server_sw.h" #include "servers/physics_2d/physics_2d_server_sw.h" +#include "servers/physics_2d/physics_2d_server_wrap_mt.h" #include "servers/audio/audio_server_sw.h" #include "servers/audio/sample_manager_sw.h" #include "servers/spatial_sound/spatial_sound_server_sw.h" diff --git a/platform/iphone/view_controller.h b/platform/iphone/view_controller.h index 9432aebd97..0cee2f6fbf 100644 --- a/platform/iphone/view_controller.h +++ b/platform/iphone/view_controller.h @@ -27,8 +27,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #import <UIKit/UIKit.h> +#import <GameKit/GameKit.h> -@interface ViewController : UIViewController { +@interface ViewController : UIViewController <GKGameCenterControllerDelegate> { }; diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm index a5ca689e61..bc9950979e 100644 --- a/platform/iphone/view_controller.mm +++ b/platform/iphone/view_controller.mm @@ -124,10 +124,15 @@ int add_cmdline(int p_argc, char** p_args) { } }; - - (BOOL)prefersStatusBarHidden { return YES; } +- (void) gameCenterViewControllerDidFinish:(GKGameCenterViewController*) gameCenterViewController { + //[gameCenterViewController dismissViewControllerAnimated:YES completion:^{GameCenter::get_singleton()->game_center_closed();}];//version for signaling when overlay is completely gone + GameCenter::get_singleton()->game_center_closed(); + [gameCenterViewController dismissViewControllerAnimated:YES completion:nil]; +} + @end diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 1e9a7e89e8..144037b1cb 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -44,6 +44,7 @@ #include "drivers/rtaudio/audio_driver_rtaudio.h" #include "drivers/alsa/audio_driver_alsa.h" #include "servers/physics_2d/physics_2d_server_sw.h" +#include "servers/physics_2d/physics_2d_server_wrap_mt.h" #include "platform/osx/audio_driver_osx.h" #include <ApplicationServices/ApplicationServices.h> diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index eb2a12cdef..e2ff8d1116 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1015,7 +1015,8 @@ void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi // physics_server = memnew( PhysicsServerSW ); physics_server->init(); - physics_2d_server = memnew( Physics2DServerSW ); + //physics_2d_server = memnew( Physics2DServerSW ); + physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); physics_2d_server->init(); input = memnew( InputDefault ); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 1350719778..4e8f9fcd9b 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1177,7 +1177,7 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_ physics_server = memnew( PhysicsServerSW ); physics_server->init(); - physics_2d_server = memnew( Physics2DServerSW ); + physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); physics_2d_server->init(); if (!is_no_window_mode_enabled()) { @@ -1375,6 +1375,9 @@ void OS_Windows::finalize() { physics_2d_server->finish(); memdelete(physics_2d_server); + joystick_change_queue.clear(); + monitor_info.clear(); + } void OS_Windows::finalize_core() { @@ -2052,7 +2055,7 @@ String OS_Windows::get_executable_path() const { wchar_t bufname[4096]; GetModuleFileNameW(NULL,bufname,4096); String s= bufname; - print_line("EXEC PATHP¨®: "+s); + print_line("EXEC PATHP??: "+s); return s; } diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 2e3700da6a..64fbbf23c0 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -45,6 +45,7 @@ #include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h" #include "drivers/unix/ip_unix.h" #include "servers/physics_2d/physics_2d_server_sw.h" +#include "servers/physics_2d/physics_2d_server_wrap_mt.h" #include <windows.h> diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 7fa1666c59..85714c46bb 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -109,8 +109,8 @@ def configure(env): if (env["target"]=="release"): - - if (env["debug_release"]): + + if (env["debug_release"]=="yes"): env.Append(CCFLAGS=['-g2','-fomit-frame-pointer']) else: env.Append(CCFLAGS=['-O2','-ffast-math','-fomit-frame-pointer']) diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 28427fa2f0..f8c570a5c0 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -35,6 +35,7 @@ #include "print_string.h" #include "servers/physics/physics_server_sw.h" + #include "X11/Xutil.h" #include "X11/Xatom.h" @@ -426,7 +427,8 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi // physics_server = memnew( PhysicsServerSW ); physics_server->init(); - physics_2d_server = memnew( Physics2DServerSW ); + //physics_2d_server = memnew( Physics2DServerSW ); + physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>(); physics_2d_server->init(); input = memnew( InputDefault ); diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 0036485f3f..261a54dd25 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -45,6 +45,7 @@ #include "drivers/alsa/audio_driver_alsa.h" #include "drivers/pulseaudio/audio_driver_pulseaudio.h" #include "servers/physics_2d/physics_2d_server_sw.h" +#include "servers/physics_2d/physics_2d_server_wrap_mt.h" #include <X11/keysym.h> #include <X11/Xlib.h> diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 312b04d414..b49426f7e2 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -329,7 +329,7 @@ void AnimatedSprite::_bind_methods() { ADD_SIGNAL(MethodInfo("frame_changed")); ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "frames",PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames")); - ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 9b2cdf4ea2..6a1ea0728d 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -288,6 +288,7 @@ void CanvasItem::show() { if (is_visible()) { _propagate_visibility_changed(true); } + _change_notify("visibility/visible"); } @@ -305,6 +306,7 @@ void CanvasItem::hide() { if (propagate) _propagate_visibility_changed(false); + _change_notify("visibility/visible"); } diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp index 5a02501816..5db0e0a9fc 100644 --- a/scene/2d/navigation2d.cpp +++ b/scene/2d/navigation2d.cpp @@ -91,9 +91,13 @@ void Navigation2D::_navpoly_link(int p_id) { } else { if (C->get().B!=NULL) { - print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b)); + ConnectionPending pending; + pending.polygon=&p; + pending.edge=j; + p.edges[j].P=C->get().pending.push_back(pending); + continue; + //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b)); } - ERR_CONTINUE(C->get().B!=NULL); //wut C->get().B=&p; C->get().B_edge=j; @@ -133,7 +137,12 @@ void Navigation2D::_navpoly_unlink(int p_id) { EdgeKey ek(edges[i].point,edges[next].point); Map<EdgeKey,Connection>::Element *C=connections.find(ek); ERR_CONTINUE(!C); - if (C->get().B) { + + if (edges[i].P) { + C->get().pending.erase(edges[i].P); + edges[i].P=NULL; + + } else if (C->get().B) { //disconnect C->get().B->edges[C->get().B_edge].C=NULL; @@ -149,6 +158,20 @@ void Navigation2D::_navpoly_unlink(int p_id) { C->get().B=NULL; C->get().B_edge=-1; + if (C->get().pending.size()) { + //reconnect if something is pending + ConnectionPending cp = C->get().pending.front()->get(); + C->get().pending.pop_front(); + + C->get().B=cp.polygon; + C->get().B_edge=cp.edge; + C->get().A->edges[C->get().A_edge].C=cp.polygon; + C->get().A->edges[C->get().A_edge].C_edge=cp.edge; + cp.polygon->edges[cp.edge].C=C->get().A; + cp.polygon->edges[cp.edge].C_edge=C->get().A_edge; + cp.polygon->edges[cp.edge].P=NULL; + } + } else { connections.erase(C); //erase diff --git a/scene/2d/navigation2d.h b/scene/2d/navigation2d.h index 829b0f544b..231f1e8c63 100644 --- a/scene/2d/navigation2d.h +++ b/scene/2d/navigation2d.h @@ -41,7 +41,13 @@ class Navigation2D : public Node2D { struct NavMesh; + struct Polygon; + struct ConnectionPending { + + Polygon *polygon; + int edge; + }; struct Polygon { @@ -49,7 +55,8 @@ class Navigation2D : public Node2D { Point point; Polygon *C; //connection int C_edge; - Edge() { C=NULL; C_edge=-1; } + List<ConnectionPending>::Element *P; + Edge() { C=NULL; C_edge=-1; P=NULL; } }; Vector<Edge> edges; @@ -72,6 +79,9 @@ class Navigation2D : public Node2D { int A_edge; Polygon *B; int B_edge; + + List<ConnectionPending> pending; + Connection() { A=NULL; B=NULL; A_edge=-1; B_edge=-1;} }; diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index 0c0a0d7822..067b4794b4 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -320,7 +320,7 @@ void Sprite::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v")); ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes")); ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region")); ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index 48820706dd..bfa8add09c 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -85,9 +85,14 @@ void Navigation::_navmesh_link(int p_id) { } else { if (C->get().B!=NULL) { - print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b)); + ConnectionPending pending; + pending.polygon=&p; + pending.edge=j; + p.edges[j].P=C->get().pending.push_back(pending); + continue; + //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b)); } - ERR_CONTINUE(C->get().B!=NULL); //wut + //ERR_CONTINUE(C->get().B!=NULL); //wut C->get().B=&p; C->get().B_edge=j; @@ -126,8 +131,13 @@ void Navigation::_navmesh_unlink(int p_id) { EdgeKey ek(edges[i].point,edges[next].point); Map<EdgeKey,Connection>::Element *C=connections.find(ek); + ERR_CONTINUE(!C); - if (C->get().B) { + + if (edges[i].P) { + C->get().pending.erase(edges[i].P); + edges[i].P=NULL; + } else if (C->get().B) { //disconnect C->get().B->edges[C->get().B_edge].C=NULL; @@ -143,6 +153,20 @@ void Navigation::_navmesh_unlink(int p_id) { C->get().B=NULL; C->get().B_edge=-1; + if (C->get().pending.size()) { + //reconnect if something is pending + ConnectionPending cp = C->get().pending.front()->get(); + C->get().pending.pop_front(); + + C->get().B=cp.polygon; + C->get().B_edge=cp.edge; + C->get().A->edges[C->get().A_edge].C=cp.polygon; + C->get().A->edges[C->get().A_edge].C_edge=cp.edge; + cp.polygon->edges[cp.edge].C=C->get().A; + cp.polygon->edges[cp.edge].C_edge=C->get().A_edge; + cp.polygon->edges[cp.edge].P=NULL; + } + } else { connections.erase(C); //erase diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h index 0f7f67571f..f8434aaf72 100644 --- a/scene/3d/navigation.h +++ b/scene/3d/navigation.h @@ -42,6 +42,13 @@ class Navigation : public Spatial { struct NavMesh; + struct Polygon; + + struct ConnectionPending { + + Polygon *polygon; + int edge; + }; struct Polygon { @@ -50,7 +57,8 @@ class Navigation : public Spatial { Point point; Polygon *C; //connection int C_edge; - Edge() { C=NULL; C_edge=-1; } + List<ConnectionPending>::Element *P; + Edge() { C=NULL; C_edge=-1; P=NULL; } }; Vector<Edge> edges; @@ -72,6 +80,9 @@ class Navigation : public Spatial { int A_edge; Polygon *B; int B_edge; + + List<ConnectionPending> pending; + Connection() { A=NULL; B=NULL; A_edge=-1; B_edge=-1;} }; diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 4952f742df..e9da95f3fb 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -580,7 +580,7 @@ void Sprite3D::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture")); ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes")); ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region")); ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); @@ -727,7 +727,7 @@ void AnimatedSprite3D::_bind_methods(){ ObjectTypeDB::bind_method(_MD("get_frame"),&AnimatedSprite3D::get_frame); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); ADD_SIGNAL(MethodInfo("frame_changed")); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index c33265ea82..74ae2c0d55 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -967,14 +967,16 @@ String AnimationPlayer::get_current_animation() const { } -void AnimationPlayer::stop() { +void AnimationPlayer::stop(bool p_reset) { Playback &c=playback; c.blend.clear(); - c.current.from=NULL; + if (p_reset) { + c.current.from=NULL; + } _set_process(false); queued.clear(); - playing = false; + playing = false; } void AnimationPlayer::stop_all() { @@ -1211,7 +1213,7 @@ void AnimationPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_default_blend_time"),&AnimationPlayer::get_default_blend_time); ObjectTypeDB::bind_method(_MD("play","name","custom_blend","custom_speed","from_end"),&AnimationPlayer::play,DEFVAL(""),DEFVAL(-1),DEFVAL(1.0),DEFVAL(false)); - ObjectTypeDB::bind_method(_MD("stop"),&AnimationPlayer::stop); + ObjectTypeDB::bind_method(_MD("stop","reset"),&AnimationPlayer::stop,DEFVAL(true)); ObjectTypeDB::bind_method(_MD("stop_all"),&AnimationPlayer::stop_all); ObjectTypeDB::bind_method(_MD("is_playing"),&AnimationPlayer::is_playing); ObjectTypeDB::bind_method(_MD("set_current_animation","anim"),&AnimationPlayer::set_current_animation); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 8d7d6d04e0..3fddc283ae 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -260,7 +260,7 @@ public: void play(const StringName& p_name=StringName(),float p_custom_blend=-1,float p_custom_scale=1.0,bool p_from_end=false); void queue(const StringName& p_name); void clear_queue(); - void stop(); + void stop(bool p_reset=true); bool is_playing() const; String get_current_animation() const; void set_current_animation(const String& p_anim); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 13cf87ac2b..c53de6568a 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -608,18 +608,12 @@ void FileDialog::_update_drives() { drives->clear(); drives->show(); - int current=-1; - String abspath = dir_access->get_current_dir(); - for(int i=0;i<dir_access->get_drive_count();i++) { - String d = dir_access->get_drive(i); - if (abspath.begins_with(d)) - current=i; + String d = dir_access->get_drive(i); drives->add_item(dir_access->get_drive(i)); } - if (current!=-1) - drives->select(current); + drives->select(dir_access->get_current_drive()); } } diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index dac21275dc..27d0f568a2 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -378,7 +378,11 @@ void Label::regenerate_word_cache() { if (uppercase) current=String::char_uppercase(current); - bool not_latin = current>=33 && (current < 65||current >90) && (current<97||current>122) && (current<48||current>57); + // ranges taken from http://www.unicodemap.org/ + // if your language is not well supported, consider helping improve + // the unicode support in Godot. + bool separatable = (current>=0x2E08 && current<=0xFAFF) || (current>=0xFE30 && current<=0xFE4F); + //current>=33 && (current < 65||current >90) && (current<97||current>122) && (current<48||current>57); bool insert_newline=false; int char_width; @@ -433,8 +437,8 @@ void Label::regenerate_word_cache() { } - if ((autowrap && (line_width >= width) && ((last && last->char_pos >= 0) || not_latin)) || insert_newline) { - if (not_latin) { + if ((autowrap && (line_width >= width) && ((last && last->char_pos >= 0) || separatable)) || insert_newline) { + if (separatable) { if (current_word_size>0) { WordCache *wc = memnew( WordCache ); if (word_cache) { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 6b2e5aea78..7a607786ee 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -58,7 +58,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item* p_item) { } -void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos,Item **r_click_item,int *r_click_char,bool *r_outside) { +void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos,Item **r_click_item,int *r_click_char,bool *r_outside,int p_char_count) { RID ci; if (r_outside) @@ -80,6 +80,7 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p int line=0; int spaces=0; + if (p_mode!=PROCESS_CACHE) { ERR_FAIL_INDEX(line,l.offset_caches.size()); @@ -89,6 +90,7 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p if (p_mode==PROCESS_CACHE) { l.offset_caches.clear(); l.height_caches.clear(); + l.char_count=0; } int wofs=margin; @@ -216,6 +218,8 @@ if (m_height > line_height) {\ underline=true; } + } else if (p_mode==PROCESS_CACHE) { + l.char_count+=text->text.length(); } rchar=0; @@ -326,18 +330,23 @@ if (m_height > line_height) {\ } } - int cw; + int cw=0; + + bool visible = visible_characters<0 || p_char_count<visible_characters; if (selected) { cw = font->get_char_size(c[i],c[i+1]).x; draw_rect(Rect2(pofs,y,cw,lh),selection_bg); - font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],selection_fg); + if (visible) + font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],selection_fg); } else { - cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color); + if (visible) + cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color); } + p_char_count++; if (c[i]=='\t') { cw=tab_size*font->get_char_size(' ').width; } @@ -371,6 +380,8 @@ if (m_height > line_height) {\ lh=0; if (p_mode!=PROCESS_CACHE) lh = line<l.height_caches.size()?l.height_caches[line]:1; + else + l.char_count+=1; //images count as chars too ItemImage *img = static_cast<ItemImage*>(it); @@ -383,9 +394,12 @@ if (m_height > line_height) {\ ENSURE_WIDTH( img->image->get_width() ); - if (p_mode==PROCESS_DRAW) { + bool visible = visible_characters<0 || p_char_count<visible_characters; + + if (p_mode==PROCESS_DRAW && visible) { img->image->draw(ci,Point2(wofs,y+lh-font->get_descent()-img->image->get_height())); } + p_char_count++; ADVANCE( img->image->get_width() ); CHECK_HEIGHT( (img->image->get_height()+font->get_descent()) ); @@ -556,11 +570,13 @@ void RichTextLabel::_notification(int p_what) { //todo, change to binary search int from_line = 0; + int total_chars = 0; while (from_line<lines.size()) { if (lines[from_line].height_accum_cache>=ofs) break; from_line++; + total_chars+=lines[from_line].char_count; } if (from_line>=lines.size()) @@ -572,7 +588,8 @@ void RichTextLabel::_notification(int p_what) { while (y<size.height && from_line<lines.size()) { - _process_line(y,size.width-scroll_w,from_line,PROCESS_DRAW,base_font,base_color); + _process_line(y,size.width-scroll_w,from_line,PROCESS_DRAW,base_font,base_color,Point2i(),NULL,NULL,NULL,total_chars); + total_chars+=lines[from_line].char_count; from_line++; } } @@ -1673,6 +1690,8 @@ void RichTextLabel::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_scroll_follow","follow"),&RichTextLabel::set_scroll_follow); ObjectTypeDB::bind_method(_MD("is_scroll_following"),&RichTextLabel::is_scroll_following); + ObjectTypeDB::bind_method(_MD("get_v_scroll"),&RichTextLabel::get_v_scroll); + ObjectTypeDB::bind_method(_MD("set_tab_size","spaces"),&RichTextLabel::set_tab_size); ObjectTypeDB::bind_method(_MD("get_tab_size"),&RichTextLabel::get_tab_size); @@ -1686,11 +1705,17 @@ void RichTextLabel::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_bbcode","text"),&RichTextLabel::set_bbcode); ObjectTypeDB::bind_method(_MD("get_bbcode"),&RichTextLabel::get_bbcode); + ObjectTypeDB::bind_method(_MD("set_visible_characters","amount"),&RichTextLabel::set_visible_characters); + ObjectTypeDB::bind_method(_MD("get_visible_characters"),&RichTextLabel::get_visible_characters); + + ObjectTypeDB::bind_method(_MD("get_total_character_count"),&RichTextLabel::get_total_character_count); + ObjectTypeDB::bind_method(_MD("set_use_bbcode","enable"),&RichTextLabel::set_use_bbcode); ObjectTypeDB::bind_method(_MD("is_using_bbcode"),&RichTextLabel::is_using_bbcode); ADD_PROPERTY(PropertyInfo(Variant::BOOL,"bbcode/enabled"),_SCS("set_use_bbcode"),_SCS("is_using_bbcode")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"bbcode/bbcode",PROPERTY_HINT_MULTILINE_TEXT),_SCS("set_bbcode"),_SCS("get_bbcode")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"visible_characters",PROPERTY_HINT_RANGE,"-1,128000,1"),_SCS("set_visible_characters"),_SCS("get_visible_characters")); ADD_SIGNAL( MethodInfo("meta_clicked",PropertyInfo(Variant::NIL,"meta"))); @@ -1717,6 +1742,27 @@ void RichTextLabel::_bind_methods() { } + +void RichTextLabel::set_visible_characters(int p_visible) { + + visible_characters=p_visible; + update(); +} + +int RichTextLabel::get_visible_characters() const { + + return visible_characters; +} +int RichTextLabel::get_total_character_count() const { + + int tc=0; + for(int i=0;i<lines.size();i++) + tc+=lines[i].char_count; + + return tc; +} + + RichTextLabel::RichTextLabel() { @@ -1754,6 +1800,8 @@ RichTextLabel::RichTextLabel() { selection.active=false; selection.enabled=false; + visible_characters=-1; + } RichTextLabel::~RichTextLabel() { diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 7172e8e500..eaa8d5d60a 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -171,8 +171,9 @@ private: Vector<int> space_caches; int height_cache; int height_accum_cache; + int char_count; - Line() { from=NULL; } + Line() { from=NULL; char_count=0; } }; @@ -223,10 +224,10 @@ private: Selection selection; + int visible_characters; - - void _process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos=Point2i(),Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL); + void _process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos=Point2i(),Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL,int p_char_count=0); void _find_click(const Point2i& p_click,Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL); @@ -246,6 +247,8 @@ private: bool use_bbcode; String bbcode; + + protected: void _notification(int p_what); @@ -304,6 +307,10 @@ public: void set_bbcode(const String& p_bbcode); String get_bbcode() const; + void set_visible_characters(int p_visible); + int get_visible_characters() const; + int get_total_character_count() const; + RichTextLabel(); ~RichTextLabel(); }; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index db8fbf7a63..0c15f99509 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1893,7 +1893,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { selection.from_line=0; selection.from_column=0; selection.to_line=text.size()-1; - selection.to_column=text[selection.to_line].size(); + selection.to_column=text[selection.to_line].length(); selection.selecting_mode=Selection::MODE_NONE; update(); @@ -2778,6 +2778,11 @@ void TextEdit::copy() { if (!selection.active) return; + print_line("from line: "+itos(selection.from_line)); + print_line("from column: "+itos(selection.from_column)); + print_line("to line: "+itos(selection.to_line)); + print_line("to column: "+itos(selection.to_column)); + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); OS::get_singleton()->set_clipboard(clipboard); @@ -2809,7 +2814,7 @@ void TextEdit::select_all() { selection.from_line=0; selection.from_column=0; selection.to_line=text.size()-1; - selection.to_column=text[selection.to_line].size(); + selection.to_column=text[selection.to_line].length(); selection.selecting_mode=Selection::MODE_NONE; update(); diff --git a/scene/io/resource_format_wav.cpp b/scene/io/resource_format_wav.cpp index a37d3b0638..7c90a4b3cd 100644 --- a/scene/io/resource_format_wav.cpp +++ b/scene/io/resource_format_wav.cpp @@ -146,18 +146,28 @@ RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_ } int frames=chunksize; + frames/=format_channels; frames/=(format_bits>>3); - + /*print_line("chunksize: "+itos(chunksize)); + print_line("channels: "+itos(format_channels)); + print_line("bits: "+itos(format_bits)); +*/ sample->create( (format_bits==8) ? Sample::FORMAT_PCM8 : Sample::FORMAT_PCM16, (format_channels==2)?true:false, frames ); sample->set_mix_rate( format_freq ); + int len=frames; + if (format_channels==2) + len*=2; + if (format_bits>8) + len*=2; + DVector<uint8_t> data; - data.resize(chunksize); + data.resize(len); DVector<uint8_t>::Write dataw = data.write(); void * data_ptr = dataw.ptr(); diff --git a/scene/resources/audio_stream_resampled.cpp b/scene/resources/audio_stream_resampled.cpp index 506b34fbf6..6317780bd3 100644 --- a/scene/resources/audio_stream_resampled.cpp +++ b/scene/resources/audio_stream_resampled.cpp @@ -230,6 +230,51 @@ bool AudioStreamResampled::mix(int32_t *p_dest, int p_frames) { case 4: read=_resample<4>(p_dest,todo,increment); break; case 6: read=_resample<6>(p_dest,todo,increment); break; } +#if 1 + //end of stream, fadeout + int remaining = p_frames-todo; + if (remaining && todo>0) { + + //print_line("fadeout"); + for(int c=0;c<channels;c++) { + + for(int i=0;i<todo;i++) { + + int32_t samp = p_dest[i*channels+c]>>8; + uint32_t mul = (todo-i) * 256 /todo; + //print_line("mul: "+itos(i)+" "+itos(mul)); + p_dest[i*channels+c]=samp*mul; + } + + } + + } + +#else + int remaining = p_frames-todo; + if (remaining && todo>0) { + + + for(int c=0;c<channels;c++) { + + int32_t from = p_dest[(todo-1)*channels+c]>>8; + + for(int i=0;i<remaining;i++) { + + uint32_t mul = (remaining-i) * 256 /remaining; + p_dest[(todo+i)*channels+c]=from*mul; + } + + } + + } +#endif + + //zero out what remains there to avoid glitches + for(int i=todo*channels;i<int(p_frames)*channels;i++) { + + p_dest[i]=0; + } if (read>rb_todo) read=rb_todo; @@ -316,6 +361,16 @@ AudioStreamResampled::AudioStreamResampled() { rb=NULL; offset=0; read_buf=NULL; + rb_read_pos=0; + rb_write_pos=0; + + rb_bits=0; + rb_len=0; + rb_mask=0; + read_buff_len=0; + channels=0; + mix_rate=0; + } AudioStreamResampled::~AudioStreamResampled() { diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 2fddafc07b..d43ffd2130 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -692,7 +692,6 @@ void make_default_theme() { // FileDialog t->set_icon("folder","FileDialog",make_icon(icon_folder_png)); - t->set_color("files_disabled","FileDialog",Color(0,0,0,0.7)); diff --git a/scene/resources/shader_graph.cpp b/scene/resources/shader_graph.cpp index 24d5978856..a0766ff317 100644 --- a/scene/resources/shader_graph.cpp +++ b/scene/resources/shader_graph.cpp @@ -1301,7 +1301,7 @@ const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={ {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Diffuse","DIFFUSE_OUT","",SLOT_TYPE_VEC,SLOT_OUT}, {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"DiffuseAlpha","ALPHA_OUT","",SLOT_TYPE_SCALAR,SLOT_OUT}, {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_OUT}, - {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"SpecularExp","SPECULAR","",SLOT_TYPE_SCALAR,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"SpecularExp","SPEC_EXP","",SLOT_TYPE_SCALAR,SLOT_OUT}, {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Emission","EMISSION","",SLOT_TYPE_VEC,SLOT_OUT}, {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Glow","GLOW","",SLOT_TYPE_SCALAR,SLOT_OUT}, {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_OUT}, diff --git a/servers/audio/sample_manager_sw.cpp b/servers/audio/sample_manager_sw.cpp index 5fa3c834c4..9195136a5d 100644 --- a/servers/audio/sample_manager_sw.cpp +++ b/servers/audio/sample_manager_sw.cpp @@ -135,6 +135,7 @@ void SampleManagerMallocSW::sample_set_data(RID p_sample, const DVector<uint8_t> ERR_EXPLAIN("Sample buffer size does not match sample size."); + //print_line("len bytes: "+itos(s->length_bytes)+" bufsize: "+itos(buff_size)); ERR_FAIL_COND(s->length_bytes!=buff_size); DVector<uint8_t>::Read buffer_r=p_buffer.read(); const uint8_t *src = buffer_r.ptr(); diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index 08d871be69..b446f4928a 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -30,7 +30,7 @@ #include "broad_phase_2d_basic.h" #include "broad_phase_2d_hash_grid.h" #include "collision_solver_2d_sw.h" - +#include "globals.h" RID Physics2DServerSW::shape_create(ShapeType p_shape) { Shape2DSW *shape=NULL; @@ -261,7 +261,7 @@ Physics2DDirectSpaceState* Physics2DServerSW::space_get_direct_state(RID p_space Space2DSW *space = space_owner.get(p_space); ERR_FAIL_COND_V(!space,NULL); - if (/*doing_sync ||*/ space->is_locked()) { + if ((using_threads && !doing_sync) || space->is_locked()) { ERR_EXPLAIN("Space state is inaccesible right now, wait for iteration or fixed process notification."); ERR_FAIL_V(NULL); @@ -733,7 +733,7 @@ void Physics2DServerSW::body_set_layer_mask(RID p_body, uint32_t p_flags) { }; -uint32_t Physics2DServerSW::body_get_layer_mask(RID p_body, uint32_t p_flags) const { +uint32_t Physics2DServerSW::body_get_layer_mask(RID p_body) const { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND_V(!body,0); @@ -750,7 +750,7 @@ void Physics2DServerSW::body_set_collision_mask(RID p_body, uint32_t p_flags) { }; -uint32_t Physics2DServerSW::body_get_collision_mask(RID p_body, uint32_t p_flags) const { +uint32_t Physics2DServerSW::body_get_collision_mask(RID p_body) const { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND_V(!body,0); @@ -1196,7 +1196,7 @@ void Physics2DServerSW::set_active(bool p_active) { void Physics2DServerSW::init() { - doing_sync=true; + doing_sync=false; last_step=0.001; iterations=8;// 8? stepper = memnew( Step2DSW ); @@ -1228,6 +1228,7 @@ void Physics2DServerSW::step(float p_step) { void Physics2DServerSW::sync() { + doing_sync=true; }; void Physics2DServerSW::flush_queries() { @@ -1235,7 +1236,7 @@ void Physics2DServerSW::flush_queries() { if (!active) return; - doing_sync=true; + for( Set<const Space2DSW*>::Element *E=active_spaces.front();E;E=E->next()) { Space2DSW *space=(Space2DSW *)E->get(); @@ -1244,6 +1245,10 @@ void Physics2DServerSW::flush_queries() { }; +void Physics2DServerSW::end_sync() { + doing_sync=false; +} + void Physics2DServerSW::finish() { @@ -1283,6 +1288,7 @@ Physics2DServerSW::Physics2DServerSW() { island_count=0; active_objects=0; collision_pairs=0; + using_threads=int(Globals::get_singleton()->get("physics_2d/thread_model"))==2; }; diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index 341df2fdc9..6e875701b8 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -51,6 +51,8 @@ friend class Physics2DDirectSpaceStateSW; int active_objects; int collision_pairs; + bool using_threads; + Step2DSW *stepper; Set<const Space2DSW*> active_spaces; @@ -179,10 +181,10 @@ public: virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const; virtual void body_set_layer_mask(RID p_body, uint32_t p_mask); - virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const; + virtual uint32_t body_get_layer_mask(RID p_body) const; virtual void body_set_collision_mask(RID p_body, uint32_t p_mask); - virtual uint32_t body_get_collision_mask(RID p_body, uint32_t p_mask) const; + virtual uint32_t body_get_collision_mask(RID p_) const; virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value); virtual float body_get_param(RID p_body, BodyParameter p_param) const; @@ -248,8 +250,9 @@ public: virtual void set_active(bool p_active); virtual void init(); virtual void step(float p_step); - virtual void sync(); + virtual void sync(); virtual void flush_queries(); + virtual void end_sync(); virtual void finish(); int get_process_info(ProcessInfo p_info); diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.cpp b/servers/physics_2d/physics_2d_server_wrap_mt.cpp new file mode 100644 index 0000000000..c5f023f162 --- /dev/null +++ b/servers/physics_2d/physics_2d_server_wrap_mt.cpp @@ -0,0 +1,169 @@ +#include "physics_2d_server_wrap_mt.h" + +#include "os/os.h" + +void Physics2DServerWrapMT::thread_exit() { + + exit=true; +} + +void Physics2DServerWrapMT::thread_step(float p_delta) { + + physics_2d_server->step(p_delta); + step_sem->post(); + +} + +void Physics2DServerWrapMT::_thread_callback(void *_instance) { + + Physics2DServerWrapMT *vsmt = reinterpret_cast<Physics2DServerWrapMT*>(_instance); + + + vsmt->thread_loop(); +} + +void Physics2DServerWrapMT::thread_loop() { + + server_thread=Thread::get_caller_ID(); + + OS::get_singleton()->make_rendering_thread(); + + physics_2d_server->init(); + + exit=false; + step_thread_up=true; + while(!exit) { + // flush commands one by one, until exit is requested + command_queue.wait_and_flush_one(); + } + + command_queue.flush_all(); // flush all + + physics_2d_server->finish(); + +} + + +/* EVENT QUEUING */ + + +void Physics2DServerWrapMT::step(float p_step) { + + if (create_thread) { + + command_queue.push( this, &Physics2DServerWrapMT::thread_step,p_step); + } else { + + command_queue.flush_all(); //flush all pending from other threads + physics_2d_server->step(p_step); + } +} + +void Physics2DServerWrapMT::sync() { + + if (step_sem) { + if (first_frame) + first_frame=false; + else + step_sem->wait(); //must not wait if a step was not issued + } + physics_2d_server->sync();; +} + +void Physics2DServerWrapMT::flush_queries(){ + + physics_2d_server->flush_queries(); +} + +void Physics2DServerWrapMT::end_sync() { + + physics_2d_server->end_sync();; +} + +void Physics2DServerWrapMT::init() { + + if (create_thread) { + + step_sem = Semaphore::create(); + print_line("CREATING PHYSICS 2D THREAD"); + //OS::get_singleton()->release_rendering_thread(); + if (create_thread) { + thread = Thread::create( _thread_callback, this ); + print_line("STARTING PHYISICS 2D THREAD"); + } + while(!step_thread_up) { + OS::get_singleton()->delay_usec(1000); + } + print_line("DONE PHYSICS 2D THREAD"); + } else { + + physics_2d_server->init(); + } + +} + +void Physics2DServerWrapMT::finish() { + + + if (thread) { + + command_queue.push( this, &Physics2DServerWrapMT::thread_exit); + Thread::wait_to_finish( thread ); + memdelete(thread); + +/* + shape_free_cached_ids(); + area_free_cached_ids(); + body_free_cached_ids(); + pin_joint_free_cached_ids(); + groove_joint_free_cached_ids(); + damped_string_free_cached_ids(); +*/ + thread=NULL; + } else { + physics_2d_server->finish(); + } + + if (step_sem) + memdelete(step_sem); + +} + + +Physics2DServerWrapMT::Physics2DServerWrapMT(Physics2DServer* p_contained,bool p_create_thread) : command_queue(p_create_thread) { + + physics_2d_server=p_contained; + create_thread=p_create_thread; + thread=NULL; + step_sem=NULL; + step_pending=0; + step_thread_up=false; + alloc_mutex=Mutex::create(); + + shape_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20); + area_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20); + body_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20); + pin_joint_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20); + groove_joint_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20); + damped_spring_joint_pool_max_size=GLOBAL_DEF("core/thread_rid_pool_prealloc",20); + + if (!p_create_thread) { + server_thread=Thread::get_caller_ID(); + } else { + server_thread=0; + } + + main_thread = Thread::get_caller_ID(); + first_frame=true; +} + + +Physics2DServerWrapMT::~Physics2DServerWrapMT() { + + memdelete(physics_2d_server); + memdelete(alloc_mutex); + //finish(); + +} + + diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h new file mode 100644 index 0000000000..0ddc8f16ec --- /dev/null +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -0,0 +1,297 @@ +#ifndef PHYSICS2DSERVERWRAPMT_H +#define PHYSICS2DSERVERWRAPMT_H + + +#include "servers/physics_2d_server.h" +#include "command_queue_mt.h" +#include "os/thread.h" +#include "globals.h" + +#ifdef DEBUG_SYNC +#define SYNC_DEBUG print_line("sync on: "+String(__FUNCTION__)); +#else +#define SYNC_DEBUG +#endif + + +class Physics2DServerWrapMT : public Physics2DServer { + + mutable Physics2DServer *physics_2d_server; + + mutable CommandQueueMT command_queue; + + static void _thread_callback(void *_instance); + void thread_loop(); + + Thread::ID server_thread; + Thread::ID main_thread; + volatile bool exit; + Thread *thread; + volatile bool step_thread_up; + bool create_thread; + + Semaphore *step_sem; + int step_pending; + void thread_step(float p_delta); + void thread_flush(); + + void thread_exit(); + + Mutex*alloc_mutex; + bool first_frame; + + int shape_pool_max_size; + List<RID> shape_id_pool; + int area_pool_max_size; + List<RID> area_id_pool; + int body_pool_max_size; + List<RID> body_id_pool; + int pin_joint_pool_max_size; + List<RID> pin_joint_id_pool; + int groove_joint_pool_max_size; + List<RID> groove_joint_id_pool; + int damped_spring_joint_pool_max_size; + List<RID> damped_spring_joint_id_pool; + + +public: + +#define ServerName Physics2DServer +#define ServerNameWrapMT Physics2DServerWrapMT +#define server_name physics_2d_server +#include "servers/server_wrap_mt_common.h" + + //FUNC1RID(shape,ShapeType); todo fix + FUNC1R(RID,shape_create,ShapeType); + FUNC2(shape_set_data,RID,const Variant& ); + FUNC2(shape_set_custom_solver_bias,RID,real_t ); + + FUNC1RC(ShapeType,shape_get_type,RID ); + FUNC1RC(Variant,shape_get_data,RID); + FUNC1RC(real_t,shape_get_custom_solver_bias,RID); + + + //these work well, but should be used from the main thread only + bool shape_collide(RID p_shape_A, const Matrix32& p_xform_A,const Vector2& p_motion_A,RID p_shape_B, const Matrix32& p_xform_B, const Vector2& p_motion_B,Vector2 *r_results,int p_result_max,int &r_result_count) { + + ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),false); + return physics_2d_server->shape_collide(p_shape_A,p_xform_A,p_motion_A,p_shape_B,p_xform_B,p_motion_B,r_results,p_result_max,r_result_count); + } + + /* SPACE API */ + + FUNC0R(RID,space_create); + FUNC2(space_set_active,RID,bool); + FUNC1RC(bool,space_is_active,RID); + + FUNC3(space_set_param,RID,SpaceParameter,real_t); + FUNC2RC(real_t,space_get_param,RID,SpaceParameter); + + // this function only works on fixed process, errors and returns null otherwise + Physics2DDirectSpaceState* space_get_direct_state(RID p_space) { + + ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),NULL); + return physics_2d_server->space_get_direct_state(p_space); + } + + + /* AREA API */ + + //FUNC0RID(area); + FUNC0R(RID,area_create); + + FUNC2(area_set_space,RID,RID); + FUNC1RC(RID,area_get_space,RID); + + FUNC2(area_set_space_override_mode,RID,AreaSpaceOverrideMode); + FUNC1RC(AreaSpaceOverrideMode,area_get_space_override_mode,RID); + + FUNC3(area_add_shape,RID,RID,const Matrix32&); + FUNC3(area_set_shape,RID,int,RID); + FUNC3(area_set_shape_transform,RID,int,const Matrix32&); + + FUNC1RC(int,area_get_shape_count,RID); + FUNC2RC(RID,area_get_shape,RID,int); + FUNC2RC(Matrix32,area_get_shape_transform,RID,int); + FUNC2(area_remove_shape,RID,int); + FUNC1(area_clear_shapes,RID); + + FUNC2(area_attach_object_instance_ID,RID,ObjectID); + FUNC1RC(ObjectID,area_get_object_instance_ID,RID); + + FUNC3(area_set_param,RID,AreaParameter,const Variant&); + FUNC2(area_set_transform,RID,const Matrix32&); + + FUNC2RC(Variant,area_get_param,RID,AreaParameter); + FUNC1RC(Matrix32,area_get_transform,RID); + + FUNC2(area_set_collision_mask,RID,uint32_t); + FUNC2(area_set_layer_mask,RID,uint32_t); + + FUNC2(area_set_monitorable,RID,bool); + FUNC2(area_set_pickable,RID,bool); + + FUNC3(area_set_monitor_callback,RID,Object*,const StringName&); + FUNC3(area_set_area_monitor_callback,RID,Object*,const StringName&); + + + /* BODY API */ + + //FUNC2RID(body,BodyMode,bool); + FUNC2R(RID,body_create,BodyMode,bool) + + FUNC2(body_set_space,RID,RID); + FUNC1RC(RID,body_get_space,RID); + + FUNC2(body_set_mode,RID,BodyMode); + FUNC1RC(BodyMode,body_get_mode,RID); + + + FUNC3(body_add_shape,RID,RID,const Matrix32&); + FUNC3(body_set_shape,RID,int,RID); + FUNC3(body_set_shape_transform,RID,int,const Matrix32&); + FUNC3(body_set_shape_metadata,RID,int,const Variant&); + + FUNC1RC(int,body_get_shape_count,RID); + FUNC2RC(Matrix32,body_get_shape_transform,RID,int); + FUNC2RC(Variant,body_get_shape_metadata,RID,int); + FUNC2RC(RID,body_get_shape,RID,int); + + FUNC3(body_set_shape_as_trigger,RID,int,bool); + FUNC2RC(bool,body_is_shape_set_as_trigger,RID,int); + + FUNC2(body_remove_shape,RID,int); + FUNC1(body_clear_shapes,RID); + + FUNC2(body_attach_object_instance_ID,RID,uint32_t); + FUNC1RC(uint32_t,body_get_object_instance_ID,RID); + + FUNC2(body_set_continuous_collision_detection_mode,RID,CCDMode); + FUNC1RC(CCDMode,body_get_continuous_collision_detection_mode,RID); + + FUNC2(body_set_layer_mask,RID,uint32_t); + FUNC1RC(uint32_t,body_get_layer_mask,RID); + + FUNC2(body_set_collision_mask,RID,uint32_t); + FUNC1RC(uint32_t,body_get_collision_mask,RID); + + + FUNC3(body_set_param,RID,BodyParameter,float); + FUNC2RC(float,body_get_param,RID,BodyParameter); + + + FUNC3(body_set_state,RID,BodyState,const Variant&); + FUNC2RC(Variant,body_get_state,RID,BodyState); + + FUNC2(body_set_applied_force,RID,const Vector2&); + FUNC1RC(Vector2,body_get_applied_force,RID); + + FUNC2(body_set_applied_torque,RID,float); + FUNC1RC(float,body_get_applied_torque,RID); + + FUNC3(body_apply_impulse,RID,const Vector2&,const Vector2&); + FUNC2(body_set_axis_velocity,RID,const Vector2&); + + FUNC2(body_add_collision_exception,RID,RID); + FUNC2(body_remove_collision_exception,RID,RID); + FUNC2S(body_get_collision_exceptions,RID,List<RID>*); + + FUNC2(body_set_max_contacts_reported,RID,int); + FUNC1RC(int,body_get_max_contacts_reported,RID); + + FUNC2(body_set_one_way_collision_direction,RID,const Vector2&); + FUNC1RC(Vector2,body_get_one_way_collision_direction,RID); + + FUNC2(body_set_one_way_collision_max_depth,RID,float); + FUNC1RC(float,body_get_one_way_collision_max_depth,RID); + + + FUNC2(body_set_contacts_reported_depth_treshold,RID,float); + FUNC1RC(float,body_get_contacts_reported_depth_treshold,RID); + + FUNC2(body_set_omit_force_integration,RID,bool); + FUNC1RC(bool,body_is_omitting_force_integration,RID); + + FUNC4(body_set_force_integration_callback,RID ,Object *,const StringName& ,const Variant& ); + + + bool body_collide_shape(RID p_body, int p_body_shape,RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,Vector2 *r_results,int p_result_max,int &r_result_count) { + return physics_2d_server->body_collide_shape(p_body,p_body_shape,p_shape,p_shape_xform,p_motion,r_results,p_result_max,r_result_count); + } + + FUNC2(body_set_pickable,RID,bool); + + bool body_test_motion(RID p_body,const Vector2& p_motion,float p_margin=0.001,MotionResult *r_result=NULL) { + + ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),false); + return physics_2d_server->body_test_motion(p_body,p_motion,p_margin,r_result); + } + + /* JOINT API */ + + + FUNC3(joint_set_param,RID,JointParam,real_t); + FUNC2RC(real_t,joint_get_param,RID,JointParam); + + + ///FUNC3RID(pin_joint,const Vector2&,RID,RID); + ///FUNC5RID(groove_joint,const Vector2&,const Vector2&,const Vector2&,RID,RID); + ///FUNC4RID(damped_spring_joint,const Vector2&,const Vector2&,RID,RID); + + FUNC3R(RID,pin_joint_create,const Vector2&,RID,RID); + FUNC5R(RID,groove_joint_create,const Vector2&,const Vector2&,const Vector2&,RID,RID); + FUNC4R(RID,damped_spring_joint_create,const Vector2&,const Vector2&,RID,RID); + + FUNC3(damped_string_joint_set_param,RID,DampedStringParam,real_t); + FUNC2RC(real_t,damped_string_joint_get_param,RID,DampedStringParam); + + FUNC1RC(JointType,joint_get_type,RID); + + + /* MISC */ + + + FUNC1(free,RID); + FUNC1(set_active,bool); + + virtual void init(); + virtual void step(float p_step); + virtual void sync(); + virtual void end_sync(); + virtual void flush_queries(); + virtual void finish(); + + int get_process_info(ProcessInfo p_info) { + return physics_2d_server->get_process_info(p_info); + } + + Physics2DServerWrapMT(Physics2DServer* p_contained,bool p_create_thread); + ~Physics2DServerWrapMT(); + + + template<class T> + static Physics2DServer* init_server() { + + int tm = GLOBAL_DEF("physics_2d/thread_model",1); + if (tm==0) //single unsafe + return memnew( T ); + else if (tm==1) //single saef + return memnew( Physics2DServerWrapMT( memnew( T ), false )); + else //single unsafe + return memnew( Physics2DServerWrapMT( memnew( T ), true )); + + + } + +#undef ServerNameWrapMT +#undef ServerName +#undef server_name + +}; + +#ifdef DEBUG_SYNC +#undef DEBUG_SYNC +#endif +#undef SYNC_DEBUG + +#endif // PHYSICS2DSERVERWRAPMT_H diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index 279ad0d742..c2ad7b2165 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -713,7 +713,7 @@ void Physics2DServer::_bind_methods() { Physics2DServer::Physics2DServer() { - ERR_FAIL_COND( singleton!=NULL ); + //ERR_FAIL_COND( singleton!=NULL ); singleton=this; } diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index 5411228c0f..9922d2e345 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -405,10 +405,10 @@ public: virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const=0; virtual void body_set_layer_mask(RID p_body, uint32_t p_mask)=0; - virtual uint32_t body_get_layer_mask(RID p_body, uint32_t p_mask) const=0; + virtual uint32_t body_get_layer_mask(RID p_body) const=0; virtual void body_set_collision_mask(RID p_body, uint32_t p_mask)=0; - virtual uint32_t body_get_collision_mask(RID p_body, uint32_t p_mask) const=0; + virtual uint32_t body_get_collision_mask(RID p_body) const=0; // common body variables enum BodyParameter { @@ -539,6 +539,7 @@ public: virtual void step(float p_step)=0; virtual void sync()=0; virtual void flush_queries()=0; + virtual void end_sync()=0; virtual void finish()=0; enum ProcessInfo { diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h new file mode 100644 index 0000000000..cbb75129d0 --- /dev/null +++ b/servers/server_wrap_mt_common.h @@ -0,0 +1,700 @@ + +#define FUNC0R(m_r,m_type)\ + virtual m_r m_type() { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type();\ + }\ + } + + +#define FUNCRID(m_type)\ + int m_type##allocn() {\ + for(int i=0;i<m_type##_pool_max_size;i++) {\ + m_type##_id_pool.push_back( server_name->m_type##_create() );\ + }\ + return 0;\ + }\ + void m_type##_free_cached_ids() {\ + while (m_type##_id_pool.size()) {\ + free(m_type##_id_pool.front()->get());\ + m_type##_id_pool.pop_front();\ + }\ + }\ + virtual RID m_type##_create() { \ + if (Thread::get_caller_ID()!=server_thread) {\ + RID rid;\ + alloc_mutex->lock();\ + if (m_type##_id_pool.size()==0) {\ + int ret;\ + command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,&ret);\ + }\ + rid=m_type##_id_pool.front()->get();\ + m_type##_id_pool.pop_front();\ + alloc_mutex->unlock();\ + return rid;\ + } else {\ + return server_name->m_type##_create();\ + }\ + } + +#define FUNC1RID(m_type,m_arg1)\ + int m_type##allocn() {\ + for(int i=0;i<m_type##_pool_max_size;i++) {\ + m_type##_id_pool.push_back( server_name->m_type##_create() );\ + }\ + return 0;\ + }\ + void m_type##_free_cached_ids() {\ + while (m_type##_id_pool.size()) {\ + free(m_type##_id_pool.front()->get());\ + m_type##_id_pool.pop_front();\ + }\ + }\ + virtual RID m_type##_create(m_arg1 p1) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + RID rid;\ + alloc_mutex->lock();\ + if (m_type##_id_pool.size()==0) {\ + int ret;\ + command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,&ret);\ + }\ + rid=m_type##_id_pool.front()->get();\ + m_type##_id_pool.pop_front();\ + alloc_mutex->unlock();\ + return rid;\ + } else {\ + return server_name->m_type##_create(p1);\ + }\ + } + +#define FUNC2RID(m_type,m_arg1,m_arg2)\ + int m_type##allocn() {\ + for(int i=0;i<m_type##_pool_max_size;i++) {\ + m_type##_id_pool.push_back( server_name->m_type##_create() );\ + }\ + return 0;\ + }\ + void m_type##_free_cached_ids() {\ + while (m_type##_id_pool.size()) {\ + free(m_type##_id_pool.front()->get());\ + m_type##_id_pool.pop_front();\ + }\ + }\ + virtual RID m_type##_create(m_arg1 p1,m_arg2 p2) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + RID rid;\ + alloc_mutex->lock();\ + if (m_type##_id_pool.size()==0) {\ + int ret;\ + command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,&ret);\ + }\ + rid=m_type##_id_pool.front()->get();\ + m_type##_id_pool.pop_front();\ + alloc_mutex->unlock();\ + return rid;\ + } else {\ + return server_name->m_type##_create(p1,p2);\ + }\ + } + +#define FUNC3RID(m_type,m_arg1,m_arg2,m_arg3)\ + int m_type##allocn() {\ + for(int i=0;i<m_type##_pool_max_size;i++) {\ + m_type##_id_pool.push_back( server_name->m_type##_create() );\ + }\ + return 0;\ + }\ + void m_type##_free_cached_ids() {\ + while (m_type##_id_pool.size()) {\ + free(m_type##_id_pool.front()->get());\ + m_type##_id_pool.pop_front();\ + }\ + }\ + virtual RID m_type##_create(m_arg1 p1,m_arg2 p2,m_arg3 p3) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + RID rid;\ + alloc_mutex->lock();\ + if (m_type##_id_pool.size()==0) {\ + int ret;\ + command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,p3,&ret);\ + }\ + rid=m_type##_id_pool.front()->get();\ + m_type##_id_pool.pop_front();\ + alloc_mutex->unlock();\ + return rid;\ + } else {\ + return server_name->m_type##_create(p1,p2,p3);\ + }\ + } + + +#define FUNC4RID(m_type,m_arg1,m_arg2,m_arg3,m_arg4)\ + int m_type##allocn() {\ + for(int i=0;i<m_type##_pool_max_size;i++) {\ + m_type##_id_pool.push_back( server_name->m_type##_create() );\ + }\ + return 0;\ + }\ + void m_type##_free_cached_ids() {\ + while (m_type##_id_pool.size()) {\ + free(m_type##_id_pool.front()->get());\ + m_type##_id_pool.pop_front();\ + }\ + }\ + virtual RID m_type##_create(m_arg1 p1,m_arg2 p2,m_arg3 p3,m_arg4 p4) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + RID rid;\ + alloc_mutex->lock();\ + if (m_type##_id_pool.size()==0) {\ + int ret;\ + command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,p3,p4,&ret);\ + }\ + rid=m_type##_id_pool.front()->get();\ + m_type##_id_pool.pop_front();\ + alloc_mutex->unlock();\ + return rid;\ + } else {\ + return server_name->m_type##_create(p1,p2,p3,p4);\ + }\ + } + + +#define FUNC5RID(m_type,m_arg1,m_arg2,m_arg3,m_arg4,m_arg5)\ + int m_type##allocn() {\ + for(int i=0;i<m_type##_pool_max_size;i++) {\ + m_type##_id_pool.push_back( server_name->m_type##_create() );\ + }\ + return 0;\ + }\ + void m_type##_free_cached_ids() {\ + while (m_type##_id_pool.size()) {\ + free(m_type##_id_pool.front()->get());\ + m_type##_id_pool.pop_front();\ + }\ + }\ + virtual RID m_type##_create(m_arg1 p1,m_arg2 p2,m_arg3 p3,m_arg4 p4,m_arg5 p5) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + RID rid;\ + alloc_mutex->lock();\ + if (m_type##_id_pool.size()==0) {\ + int ret;\ + command_queue.push_and_ret( this, &ServerNameWrapMT::m_type##allocn,p1,p2,p3,p4,p5,&ret);\ + }\ + rid=m_type##_id_pool.front()->get();\ + m_type##_id_pool.pop_front();\ + alloc_mutex->unlock();\ + return rid;\ + } else {\ + return server_name->m_type##_create(p1,p2,p3,p4,p5);\ + }\ + } + +#define FUNC0RC(m_r,m_type)\ + virtual m_r m_type() const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type();\ + }\ + } + + +#define FUNC0(m_type)\ + virtual void m_type() { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type);\ + } else {\ + server_name->m_type();\ + }\ + } + +#define FUNC0C(m_type)\ + virtual void m_type() const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type);\ + } else {\ + server_name->m_type();\ + }\ + } + + +#define FUNC0S(m_type)\ + virtual void m_type() { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type);\ + } else {\ + server_name->m_type();\ + }\ + } + +#define FUNC0SC(m_type)\ + virtual void m_type() const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type);\ + } else {\ + server_name->m_type();\ + }\ + } + + +/////////////////////////////////////////////// + + +#define FUNC1R(m_r,m_type,m_arg1)\ + virtual m_r m_type(m_arg1 p1) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1);\ + }\ + } + +#define FUNC1RC(m_r,m_type,m_arg1)\ + virtual m_r m_type(m_arg1 p1) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1);\ + }\ + } + + +#define FUNC1S(m_type,m_arg1)\ + virtual void m_type(m_arg1 p1) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1);\ + } else {\ + server_name->m_type(p1);\ + }\ + } + +#define FUNC1SC(m_type,m_arg1)\ + virtual void m_type(m_arg1 p1) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1);\ + } else {\ + server_name->m_type(p1);\ + }\ + } + + +#define FUNC1(m_type,m_arg1)\ + virtual void m_type(m_arg1 p1) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1);\ + } else {\ + server_name->m_type(p1);\ + }\ + } + +#define FUNC1C(m_type,m_arg1)\ + virtual void m_type(m_arg1 p1) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1);\ + } else {\ + server_name->m_type(p1);\ + }\ + } + + + + +#define FUNC2R(m_r,m_type,m_arg1, m_arg2)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2);\ + }\ + } + +#define FUNC2RC(m_r,m_type,m_arg1, m_arg2)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2);\ + }\ + } + + +#define FUNC2S(m_type,m_arg1, m_arg2)\ + virtual void m_type(m_arg1 p1, m_arg2 p2) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2);\ + } else {\ + server_name->m_type(p1, p2);\ + }\ + } + +#define FUNC2SC(m_type,m_arg1, m_arg2)\ + virtual void m_type(m_arg1 p1, m_arg2 p2) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2);\ + } else {\ + server_name->m_type(p1, p2);\ + }\ + } + + +#define FUNC2(m_type,m_arg1, m_arg2)\ + virtual void m_type(m_arg1 p1, m_arg2 p2) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2);\ + } else {\ + server_name->m_type(p1, p2);\ + }\ + } + +#define FUNC2C(m_type,m_arg1, m_arg2)\ + virtual void m_type(m_arg1 p1, m_arg2 p2) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2);\ + } else {\ + server_name->m_type(p1, p2);\ + }\ + } + + + + +#define FUNC3R(m_r,m_type,m_arg1, m_arg2, m_arg3)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2, p3);\ + }\ + } + +#define FUNC3RC(m_r,m_type,m_arg1, m_arg2, m_arg3)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3,&ret);\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2, p3);\ + }\ + } + + +#define FUNC3S(m_type,m_arg1, m_arg2, m_arg3)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3);\ + } else {\ + server_name->m_type(p1, p2, p3);\ + }\ + } + +#define FUNC3SC(m_type,m_arg1, m_arg2, m_arg3)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3);\ + } else {\ + server_name->m_type(p1, p2, p3);\ + }\ + } + + +#define FUNC3(m_type,m_arg1, m_arg2, m_arg3)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2, p3);\ + } else {\ + server_name->m_type(p1, p2, p3);\ + }\ + } + +#define FUNC3C(m_type,m_arg1, m_arg2, m_arg3)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2, p3);\ + } else {\ + server_name->m_type(p1, p2, p3);\ + }\ + } + + + + +#define FUNC4R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2, p3, p4);\ + }\ + } + +#define FUNC4RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2, p3, p4);\ + }\ + } + + +#define FUNC4S(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4);\ + } else {\ + server_name->m_type(p1, p2, p3, p4);\ + }\ + } + +#define FUNC4SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4);\ + } else {\ + server_name->m_type(p1, p2, p3, p4);\ + }\ + } + + +#define FUNC4(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4);\ + } else {\ + server_name->m_type(p1, p2, p3, p4);\ + }\ + } + +#define FUNC4C(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4);\ + } else {\ + server_name->m_type(p1, p2, p3, p4);\ + }\ + } + + + + +#define FUNC5R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2, p3, p4, p5);\ + }\ + } + +#define FUNC5RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2, p3, p4, p5);\ + }\ + } + + +#define FUNC5S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5);\ + }\ + } + +#define FUNC5SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5);\ + }\ + } + + +#define FUNC5(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5);\ + }\ + } + +#define FUNC5C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5);\ + }\ + } + + + + +#define FUNC6R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2, p3, p4, p5, p6);\ + }\ + } + +#define FUNC6RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6,&ret);\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2, p3, p4, p5, p6);\ + }\ + } + + +#define FUNC6S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5, p6);\ + }\ + } + +#define FUNC6SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5, p6);\ + }\ + } + + +#define FUNC6(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5, p6);\ + }\ + } + +#define FUNC6C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5, p6);\ + }\ + } + + + + +#define FUNC7R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\ + }\ + } + +#define FUNC7RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ + virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + m_r ret;\ + command_queue.push_and_ret( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\ + SYNC_DEBUG\ + return ret;\ + } else {\ + return server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\ + }\ + } + + +#define FUNC7S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\ + }\ + } + +#define FUNC7SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push_and_sync( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\ + }\ + } + + +#define FUNC7(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\ + }\ + } + +#define FUNC7C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ + virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \ + if (Thread::get_caller_ID()!=server_thread) {\ + command_queue.push( server_name, &ServerName::m_type,p1, p2, p3, p4, p5, p6, p7);\ + } else {\ + server_name->m_type(p1, p2, p3, p4, p5, p6, p7);\ + }\ + } + diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp index a044981bbb..44a41a93da 100644 --- a/servers/visual/visual_server_wrap_mt.cpp +++ b/servers/visual/visual_server_wrap_mt.cpp @@ -187,8 +187,8 @@ VisualServerWrapMT::VisualServerWrapMT(VisualServer* p_contained,bool p_create_t draw_pending=0; draw_thread_up=false; alloc_mutex=Mutex::create(); - texture_pool_max_size=GLOBAL_DEF("render/thread_textures_prealloc",20); - mesh_pool_max_size=GLOBAL_DEF("render/thread_meshes_prealloc",20); + texture_pool_max_size=GLOBAL_DEF("render/thread_textures_prealloc",5); + mesh_pool_max_size=GLOBAL_DEF("core/rid_pool_prealloc",20); if (!p_create_thread) { server_thread=Thread::get_caller_ID(); } else { diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 3d97243827..d07e1940d7 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -79,554 +79,10 @@ class VisualServerWrapMT : public VisualServer { public: -#define FUNC0R(m_r,m_type)\ - virtual m_r m_type() { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type();\ - }\ - } - -#define FUNCRID(m_type)\ - int m_type##allocn() {\ - for(int i=0;i<m_type##_pool_max_size;i++) {\ - m_type##_id_pool.push_back( visual_server->m_type##_create() );\ - }\ - return 0;\ - }\ - void m_type##_free_cached_ids() {\ - while (m_type##_id_pool.size()) {\ - free(m_type##_id_pool.front()->get());\ - m_type##_id_pool.pop_front();\ - }\ - }\ - virtual RID m_type##_create() { \ - if (Thread::get_caller_ID()!=server_thread) {\ - RID rid;\ - alloc_mutex->lock();\ - if (m_type##_id_pool.size()==0) {\ - int ret;\ - command_queue.push_and_ret( this, &VisualServerWrapMT::m_type##allocn,&ret);\ - }\ - rid=m_type##_id_pool.front()->get();\ - m_type##_id_pool.pop_front();\ - alloc_mutex->unlock();\ - return rid;\ - } else {\ - return visual_server->m_type##_create();\ - }\ - } - -#define FUNC0RC(m_r,m_type)\ - virtual m_r m_type() const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type();\ - }\ - } - - -#define FUNC0(m_type)\ - virtual void m_type() { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type);\ - } else {\ - visual_server->m_type();\ - }\ - } - -#define FUNC0C(m_type)\ - virtual void m_type() const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type);\ - } else {\ - visual_server->m_type();\ - }\ - } - - -#define FUNC0S(m_type)\ - virtual void m_type() { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type);\ - } else {\ - visual_server->m_type();\ - }\ - } - -#define FUNC0SC(m_type)\ - virtual void m_type() const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type);\ - } else {\ - visual_server->m_type();\ - }\ - } - - -/////////////////////////////////////////////// - - -#define FUNC1R(m_r,m_type,m_arg1)\ - virtual m_r m_type(m_arg1 p1) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1);\ - }\ - } - -#define FUNC1RC(m_r,m_type,m_arg1)\ - virtual m_r m_type(m_arg1 p1) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1);\ - }\ - } - - -#define FUNC1S(m_type,m_arg1)\ - virtual void m_type(m_arg1 p1) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1);\ - } else {\ - visual_server->m_type(p1);\ - }\ - } - -#define FUNC1SC(m_type,m_arg1)\ - virtual void m_type(m_arg1 p1) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1);\ - } else {\ - visual_server->m_type(p1);\ - }\ - } - - -#define FUNC1(m_type,m_arg1)\ - virtual void m_type(m_arg1 p1) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1);\ - } else {\ - visual_server->m_type(p1);\ - }\ - } - -#define FUNC1C(m_type,m_arg1)\ - virtual void m_type(m_arg1 p1) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1);\ - } else {\ - visual_server->m_type(p1);\ - }\ - } - - - - -#define FUNC2R(m_r,m_type,m_arg1, m_arg2)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2);\ - }\ - } - -#define FUNC2RC(m_r,m_type,m_arg1, m_arg2)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2);\ - }\ - } - - -#define FUNC2S(m_type,m_arg1, m_arg2)\ - virtual void m_type(m_arg1 p1, m_arg2 p2) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2);\ - } else {\ - visual_server->m_type(p1, p2);\ - }\ - } - -#define FUNC2SC(m_type,m_arg1, m_arg2)\ - virtual void m_type(m_arg1 p1, m_arg2 p2) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2);\ - } else {\ - visual_server->m_type(p1, p2);\ - }\ - } - - -#define FUNC2(m_type,m_arg1, m_arg2)\ - virtual void m_type(m_arg1 p1, m_arg2 p2) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2);\ - } else {\ - visual_server->m_type(p1, p2);\ - }\ - } - -#define FUNC2C(m_type,m_arg1, m_arg2)\ - virtual void m_type(m_arg1 p1, m_arg2 p2) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2);\ - } else {\ - visual_server->m_type(p1, p2);\ - }\ - } - - - - -#define FUNC3R(m_r,m_type,m_arg1, m_arg2, m_arg3)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2, p3);\ - }\ - } - -#define FUNC3RC(m_r,m_type,m_arg1, m_arg2, m_arg3)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3,&ret);\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2, p3);\ - }\ - } - - -#define FUNC3S(m_type,m_arg1, m_arg2, m_arg3)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3);\ - } else {\ - visual_server->m_type(p1, p2, p3);\ - }\ - } - -#define FUNC3SC(m_type,m_arg1, m_arg2, m_arg3)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3);\ - } else {\ - visual_server->m_type(p1, p2, p3);\ - }\ - } - - -#define FUNC3(m_type,m_arg1, m_arg2, m_arg3)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3);\ - } else {\ - visual_server->m_type(p1, p2, p3);\ - }\ - } - -#define FUNC3C(m_type,m_arg1, m_arg2, m_arg3)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3);\ - } else {\ - visual_server->m_type(p1, p2, p3);\ - }\ - } - - - - -#define FUNC4R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2, p3, p4);\ - }\ - } - -#define FUNC4RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2, p3, p4);\ - }\ - } - - -#define FUNC4S(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4);\ - }\ - } - -#define FUNC4SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4);\ - }\ - } - - -#define FUNC4(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4);\ - }\ - } - -#define FUNC4C(m_type,m_arg1, m_arg2, m_arg3, m_arg4)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4);\ - }\ - } - - - - -#define FUNC5R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2, p3, p4, p5);\ - }\ - } - -#define FUNC5RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2, p3, p4, p5);\ - }\ - } - - -#define FUNC5S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5);\ - }\ - } - -#define FUNC5SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5);\ - }\ - } - - -#define FUNC5(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5);\ - }\ - } - -#define FUNC5C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5);\ - }\ - } - - - - -#define FUNC6R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2, p3, p4, p5, p6);\ - }\ - } - -#define FUNC6RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6,&ret);\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2, p3, p4, p5, p6);\ - }\ - } - - -#define FUNC6S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5, p6);\ - }\ - } - -#define FUNC6SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5, p6);\ - }\ - } - - -#define FUNC6(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5, p6);\ - }\ - } - -#define FUNC6C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5, p6);\ - }\ - } - - - - -#define FUNC7R(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\ - }\ - } - -#define FUNC7RC(m_r,m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ - virtual m_r m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - m_r ret;\ - command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\ - SYNC_DEBUG\ - return ret;\ - } else {\ - return visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\ - }\ - } - - -#define FUNC7S(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\ - }\ - } - -#define FUNC7SC(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push_and_sync( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\ - }\ - } - - -#define FUNC7(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\ - }\ - } - -#define FUNC7C(m_type,m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7)\ - virtual void m_type(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5, m_arg6 p6, m_arg7 p7) const { \ - if (Thread::get_caller_ID()!=server_thread) {\ - command_queue.push( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7);\ - } else {\ - visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\ - }\ - } - - - +#define ServerName VisualServer +#define ServerNameWrapMT VisualServerWrapMT +#define server_name visual_server +#include "servers/server_wrap_mt_common.h" //FUNC0R(RID,texture_create); FUNCRID(texture); @@ -1242,7 +698,15 @@ public: VisualServerWrapMT(VisualServer* p_contained,bool p_create_thread); ~VisualServerWrapMT(); +#undef ServerName +#undef ServerNameWrapMT +#undef server_name + }; +#ifdef DEBUG_SYNC +#undef DEBUG_SYNC +#endif +#undef SYNC_DEBUG #endif 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 Binary files differnew file mode 100644 index 0000000000..cdeac1785e --- /dev/null +++ b/tools/editor/icons/icon_curve_constant.png diff --git a/tools/editor/icons/icon_curve_in.png b/tools/editor/icons/icon_curve_in.png Binary files differnew file mode 100644 index 0000000000..2db202632e --- /dev/null +++ b/tools/editor/icons/icon_curve_in.png diff --git a/tools/editor/icons/icon_curve_in_out.png b/tools/editor/icons/icon_curve_in_out.png Binary files differnew file mode 100644 index 0000000000..f4cb593496 --- /dev/null +++ b/tools/editor/icons/icon_curve_in_out.png diff --git a/tools/editor/icons/icon_curve_linear.png b/tools/editor/icons/icon_curve_linear.png Binary files differnew file mode 100644 index 0000000000..9467dc97a3 --- /dev/null +++ b/tools/editor/icons/icon_curve_linear.png diff --git a/tools/editor/icons/icon_curve_out.png b/tools/editor/icons/icon_curve_out.png Binary files differnew file mode 100644 index 0000000000..c91ade6f4a --- /dev/null +++ b/tools/editor/icons/icon_curve_out.png diff --git a/tools/editor/icons/icon_curve_out_in.png b/tools/editor/icons/icon_curve_out_in.png Binary files differnew file mode 100644 index 0000000000..6499fa753e --- /dev/null +++ b/tools/editor/icons/icon_curve_out_in.png diff --git a/tools/editor/icons/icon_key_next.png b/tools/editor/icons/icon_key_next.png Binary files differnew file mode 100644 index 0000000000..759008d064 --- /dev/null +++ b/tools/editor/icons/icon_key_next.png diff --git a/tools/editor/icons/icon_pause.png b/tools/editor/icons/icon_pause.png Binary files differindex e63661353c..7c0a57003e 100644 --- a/tools/editor/icons/icon_pause.png +++ b/tools/editor/icons/icon_pause.png diff --git a/tools/editor/icons/icon_play.png b/tools/editor/icons/icon_play.png Binary files differindex 08cce495a9..d2bd9d310c 100644 --- a/tools/editor/icons/icon_play.png +++ b/tools/editor/icons/icon_play.png diff --git a/tools/editor/icons/icon_play_backwards.png b/tools/editor/icons/icon_play_backwards.png Binary files differnew file mode 100644 index 0000000000..8dff5f20e3 --- /dev/null +++ b/tools/editor/icons/icon_play_backwards.png diff --git a/tools/editor/icons/icon_play_start.png b/tools/editor/icons/icon_play_start.png Binary files differnew file mode 100644 index 0000000000..5b085aa1ed --- /dev/null +++ b/tools/editor/icons/icon_play_start.png diff --git a/tools/editor/icons/icon_play_start_backwards.png b/tools/editor/icons/icon_play_start_backwards.png Binary files differnew file mode 100644 index 0000000000..09afac637c --- /dev/null +++ b/tools/editor/icons/icon_play_start_backwards.png diff --git a/tools/editor/icons/icon_stop.png b/tools/editor/icons/icon_stop.png Binary files differindex fd568b61a8..0fd43b403a 100644 --- a/tools/editor/icons/icon_stop.png +++ b/tools/editor/icons/icon_stop.png diff --git a/tools/editor/icons/icon_wait_no_preview.png b/tools/editor/icons/icon_wait_no_preview.png Binary files differnew file mode 100644 index 0000000000..5d20cd99ec --- /dev/null +++ b/tools/editor/icons/icon_wait_no_preview.png diff --git a/tools/editor/icons/icon_wait_preview_1.png b/tools/editor/icons/icon_wait_preview_1.png Binary files differnew file mode 100644 index 0000000000..0aab42e04a --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_1.png diff --git a/tools/editor/icons/icon_wait_preview_2.png b/tools/editor/icons/icon_wait_preview_2.png Binary files differnew file mode 100644 index 0000000000..f476b9ce1f --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_2.png diff --git a/tools/editor/icons/icon_wait_preview_3.png b/tools/editor/icons/icon_wait_preview_3.png Binary files differnew file mode 100644 index 0000000000..2775d1ef43 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_3.png diff --git a/tools/editor/icons/icon_wait_preview_4.png b/tools/editor/icons/icon_wait_preview_4.png Binary files differnew file mode 100644 index 0000000000..2eaa86fec9 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_4.png diff --git a/tools/editor/icons/icon_wait_preview_5.png b/tools/editor/icons/icon_wait_preview_5.png Binary files differnew file mode 100644 index 0000000000..6590644bc1 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_5.png diff --git a/tools/editor/icons/icon_wait_preview_6.png b/tools/editor/icons/icon_wait_preview_6.png Binary files differnew file mode 100644 index 0000000000..307e412310 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_6.png diff --git a/tools/editor/icons/icon_wait_preview_7.png b/tools/editor/icons/icon_wait_preview_7.png Binary files differnew file mode 100644 index 0000000000..b0edc94d93 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_7.png diff --git a/tools/editor/icons/icon_wait_preview_8.png b/tools/editor/icons/icon_wait_preview_8.png Binary files differnew file mode 100644 index 0000000000..67a2f48ec3 --- /dev/null +++ b/tools/editor/icons/icon_wait_preview_8.png diff --git a/tools/editor/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; diff --git a/tools/export/blender25/io_scene_dae/export_dae.py b/tools/export/blender25/io_scene_dae/export_dae.py index 14db93c874..492a737e23 100644 --- a/tools/export/blender25/io_scene_dae/export_dae.py +++ b/tools/export/blender25/io_scene_dae/export_dae.py @@ -902,18 +902,22 @@ class DaeExporter: if (node.data==None): return armature=None + armcount=0 + for n in node.modifiers: + if (n.type=="ARMATURE"): + armcount+=1 if (node.parent!=None): if (node.parent.type=="ARMATURE"): armature=node.parent - armcount=0 - for n in node.modifiers: - if (n.type=="ARMATURE"): - armcount+=1 - if (armcount>1): - self.operator.report({'WARNING'},'Object "'+node.name+'" refers to more than one armature! This is unsopported.') + if (armcount>1): + self.operator.report({'WARNING'},'Object "'+node.name+'" refers to more than one armature! This is unsopported.') + if (armcount==0): + self.operator.report({'WARNING'},'Object "'+node.name+'" is child of an armature, but has no armature modifier.') + if (armcount>0 and not armature): + self.operator.report({'WARNING'},'Object "'+node.name+'" has armature modifier, but is not a child of an armature. This is unsupported.') if (node.data.shape_keys!=None): diff --git a/tools/pck/pck_packer.h b/tools/pck/pck_packer.h index 76752a6170..2bb51128e9 100644 --- a/tools/pck/pck_packer.h +++ b/tools/pck/pck_packer.h @@ -1,10 +1,10 @@ -#include "core/object.h" +#include "core/reference.h" class FileAccess; -class PCKPacker : public Object { +class PCKPacker : public Reference { - OBJ_TYPE(PCKPacker, Object); + OBJ_TYPE(PCKPacker, Reference); FileAccess* file; int alignment; diff --git a/version.py b/version.py index 348b6b89ed..c723dd2935 100644 --- a/version.py +++ b/version.py @@ -2,6 +2,6 @@ short_name="godot" name="Godot Engine" major=1 minor=1 -status="rc3" +status="stable" |