diff options
244 files changed, 9828 insertions, 1396 deletions
diff --git a/SConstruct b/SConstruct index 9cd1da7f45..9cce6edd81 100644 --- a/SConstruct +++ b/SConstruct @@ -220,14 +220,14 @@ if selected_platform in platform_list: env.Append(LINKFLAGS=string.split(str(LINKFLAGS))) - detect.configure(env) - - flag_list = platform_flags[selected_platform] for f in flag_list: if not (f[0] in ARGUMENTS): # allow command line to override platform flags env[f[0]] = f[1] + #must happen after the flags, so when flags are used by configure, stuff happens (ie, ssl on x11) + detect.configure(env) + #env['platform_libsuffix'] = env['LIBSUFFIX'] suffix="."+selected_platform diff --git a/core/error_list.h b/core/error_list.h index 124027172e..92c417154c 100644 --- a/core/error_list.h +++ b/core/error_list.h @@ -54,6 +54,7 @@ enum Error { ERR_FILE_CANT_READ, ERR_FILE_UNRECOGNIZED, // (15) ERR_FILE_CORRUPT, + ERR_FILE_MISSING_DEPENDENCIES, ERR_FILE_EOF, ERR_CANT_OPEN, ///< Can't open a resource/socket/file ERR_CANT_CREATE, diff --git a/core/error_macros.h b/core/error_macros.h index 18b08d8e0e..76da88287b 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -104,7 +104,7 @@ extern bool _err_error_exists; #define ERR_FAIL_INDEX(m_index,m_size) \ do {if ((m_index)<0 || (m_index)>=(m_size)) { \ - _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Index "_STR(m_index)" out of size ("_STR(m_size)")."); \ + _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Index " _STR(m_index)" out of size (" _STR(m_size)")."); \ return; \ } else _err_error_exists=false; } while(0); \ @@ -115,7 +115,7 @@ extern bool _err_error_exists; #define ERR_FAIL_INDEX_V(m_index,m_size,m_retval) \ do {if ((m_index)<0 || (m_index)>=(m_size)) { \ - _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Index "_STR(m_index)" out of size ("_STR(m_size)")."); \ + _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Index " _STR(m_index)" out of size (" _STR(m_size)")."); \ return m_retval; \ } else _err_error_exists=false;} while (0); @@ -125,14 +125,14 @@ extern bool _err_error_exists; #define ERR_FAIL_NULL(m_param) \ { if ( !m_param ) { \ - _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Parameter ' "_STR(m_param)" ' is null."); \ + _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Parameter ' " _STR(m_param)" ' is null."); \ return; \ }else _err_error_exists=false; } \ #define ERR_FAIL_NULL_V(m_param,m_retval) \ { if ( !m_param ) { \ - _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Parameter ' "_STR(m_param)" ' is null."); \ + _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Parameter ' " _STR(m_param)" ' is null."); \ return m_retval; \ }else _err_error_exists=false; } \ @@ -142,7 +142,7 @@ extern bool _err_error_exists; #define ERR_FAIL_COND(m_cond) \ { if ( m_cond ) { \ - _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true."); \ + _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' " _STR(m_cond)" ' is true."); \ return; \ }else _err_error_exists=false; } \ @@ -154,7 +154,7 @@ extern bool _err_error_exists; #define ERR_FAIL_COND_V(m_cond,m_retval) \ { if ( m_cond ) { \ - _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true. returned: "_STR(m_retval)); \ + _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' " _STR(m_cond)" ' is true. returned: " _STR(m_retval)); \ return m_retval; \ }else _err_error_exists=false; } \ @@ -164,7 +164,7 @@ extern bool _err_error_exists; #define ERR_CONTINUE(m_cond) \ { if ( m_cond ) { \ - _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true. Continuing..:"); \ + _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' " _STR(m_cond)" ' is true. Continuing..:"); \ continue;\ } else _err_error_exists=false;} \ @@ -174,7 +174,7 @@ extern bool _err_error_exists; #define ERR_BREAK(m_cond) \ { if ( m_cond ) { \ - _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true. Breaking..:"); \ + _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' " _STR(m_cond)" ' is true. Breaking..:"); \ break;\ } else _err_error_exists=false;} \ @@ -193,7 +193,7 @@ extern bool _err_error_exists; #define ERR_FAIL_V(m_value) \ { \ - _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Method/Function Failed, returning: "__STR(m_value)); \ + _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Method/Function Failed, returning: " __STR(m_value)); \ _err_error_exists=false; \ return m_value;\ } \ diff --git a/core/global_constants.cpp b/core/global_constants.cpp index b8d113f67c..9fb45c672a 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -422,6 +422,7 @@ static _GlobalConstant _global_constants[]={ BIND_GLOBAL_CONSTANT( ERR_FILE_CANT_READ ), BIND_GLOBAL_CONSTANT( ERR_FILE_UNRECOGNIZED ), BIND_GLOBAL_CONSTANT( ERR_FILE_CORRUPT ), + BIND_GLOBAL_CONSTANT( ERR_FILE_MISSING_DEPENDENCIES), BIND_GLOBAL_CONSTANT( ERR_FILE_EOF ), BIND_GLOBAL_CONSTANT( ERR_CANT_OPEN ), ///< Can't open a resource/socket/file BIND_GLOBAL_CONSTANT( ERR_CANT_CREATE ), diff --git a/core/globals.cpp b/core/globals.cpp index 731c5b7dff..ffd4cf5d5e 100644 --- a/core/globals.cpp +++ b/core/globals.cpp @@ -54,7 +54,7 @@ String Globals::localize_path(const String& p_path) const { if (resource_path=="") return p_path; //not initialied yet - if (p_path.begins_with("res://")) + if (p_path.find(":/") != -1) return p_path.simplify_path(); @@ -1477,7 +1477,6 @@ Globals::Globals() { 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/io/compression.cpp b/core/io/compression.cpp index 0bc006b41e..729b7bec52 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -26,12 +26,12 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "zlib.h" +#include "os/copymem.h" #include "compression.h" #include "fastlz.h" -#include "zlib.h" #include "zip_io.h" -#include "os/copymem.h" int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,Mode p_mode) { diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index d3390ae199..2db6e00f0a 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -50,8 +50,10 @@ Error ImageLoader::load_image(String p_file,Image *p_image, FileAccess *p_custom if (!f) { Error err; f=FileAccess::open(p_file,FileAccess::READ,&err); - if (!f) + if (!f) { + print_line("ERROR OPENING FILE: "+p_file); return err; + } } String extension = p_file.extension(); @@ -62,15 +64,20 @@ Error ImageLoader::load_image(String p_file,Image *p_image, FileAccess *p_custom if (!loader[i]->recognize(extension)) continue; Error err = loader[i]->load_image(p_image,f); + if (err!=ERR_FILE_UNRECOGNIZED) { + + if (!p_custom) memdelete(f); + return err; } } - + print_line("NO LOADER?"); + if (!p_custom) memdelete(f); diff --git a/core/io/ioapi.h b/core/io/ioapi.h index a13d7ba621..24bf612617 100644 --- a/core/io/ioapi.h +++ b/core/io/ioapi.h @@ -40,7 +40,6 @@ #endif #include <stdio.h> -#include <stdlib.h> #include "zlib.h" #if defined(USE_FILE32API) diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index c6cf631de6..60bb8b658e 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -31,6 +31,7 @@ #include "globals.h" #include "io/file_access_compressed.h" #include "io/marshalls.h" +#include "os/dir_access.h" //#define print_bl(m_what) print_line(m_what) #define print_bl(m_what) @@ -99,7 +100,9 @@ enum { OBJECT_EMPTY=0, OBJECT_EXTERNAL_RESOURCE=1, OBJECT_INTERNAL_RESOURCE=2, - FORMAT_VERSION=0 + OBJECT_EXTERNAL_RESOURCE_INDEX=3, + FORMAT_VERSION=1, + FORMAT_VERSION_CAN_RENAME_DEPS=1 }; @@ -375,7 +378,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { } break; case OBJECT_INTERNAL_RESOURCE: { uint32_t index=f->get_32(); - String path = res_path+"::"+itos(index); + String path = res_path+"::"+itos(index); RES res = ResourceLoader::load(path); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); @@ -384,6 +387,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { } break; case OBJECT_EXTERNAL_RESOURCE: { + //old file format, still around for compatibility String type = get_unicode_string(); String path = get_unicode_string(); @@ -394,6 +398,10 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { } + if (remaps.find(path)) { + path=remaps[path]; + } + RES res=ResourceLoader::load(path,type); if (res.is_null()) { @@ -402,6 +410,34 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { r_v=res; } break; + case OBJECT_EXTERNAL_RESOURCE_INDEX: { + //new file format, just refers to an index in the external list + uint32_t erindex = f->get_32(); + + if (erindex>=external_resources.size()) { + WARN_PRINT("Broken external resource! (index out of size"); + r_v=Variant(); + } else { + + String type = external_resources[erindex].type; + String path = external_resources[erindex].path; + + if (path.find("://")==-1 && path.is_rel_path()) { + // path is relative to file being loaded, so convert to a resource path + path=Globals::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); + + } + + RES res=ResourceLoader::load(path,type); + + if (res.is_null()) { + WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); + } + r_v=res; + } + + + } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); @@ -628,17 +664,20 @@ Error ResourceInteractiveLoaderBinary::poll(){ if (s<external_resources.size()) { - RES res = ResourceLoader::load(external_resources[s].path,external_resources[s].type); + String path = external_resources[s].path; + if (remaps.has(path)) { + path=remaps[path]; + } + RES res = ResourceLoader::load(path,external_resources[s].type); if (res.is_null()) { if (!ResourceLoader::get_abort_on_missing_resources()) { - ResourceLoader::notify_load_error("Resource Not Found: "+external_resources[s].path); + ResourceLoader::notify_dependency_error(local_path,path,external_resources[s].type); } else { - - error=ERR_FILE_CORRUPT; - ERR_EXPLAIN("Can't load dependency: "+external_resources[s].path); + error=ERR_FILE_MISSING_DEPENDENCIES; + ERR_EXPLAIN("Can't load dependency: "+path); ERR_FAIL_V(error); } @@ -787,6 +826,27 @@ int ResourceInteractiveLoaderBinary::get_stage_count() const { return external_resources.size()+internal_resources.size(); } + +static void save_ustring(FileAccess* f,const String& p_string) { + + + CharString utf8 = p_string.utf8(); + f->store_32(utf8.length()+1); + f->store_buffer((const uint8_t*)utf8.get_data(),utf8.length()+1); +} + + +static String get_ustring(FileAccess *f) { + + int len = f->get_32(); + Vector<char> str_buf; + str_buf.resize(len); + f->get_buffer((uint8_t*)&str_buf[0],len); + String s; + s.parse_utf8(&str_buf[0]); + return s; +} + String ResourceInteractiveLoaderBinary::get_unicode_string() { int len = f->get_32(); @@ -801,7 +861,7 @@ String ResourceInteractiveLoaderBinary::get_unicode_string() { -void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<String> *p_dependencies) { +void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<String> *p_dependencies,bool p_add_types) { open(p_f); if (error) @@ -814,6 +874,10 @@ void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<Stri dep=ResourceLoader::guess_full_filename(dep,external_resources[i].type); } + if (p_add_types && external_resources[i].type!=String()) { + dep+="::"+external_resources[i].type; + } + p_dependencies->push_back(dep); } @@ -866,7 +930,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) { + 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); @@ -903,6 +967,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { } //see if the exporter has different set of external resources for more efficient loading + /* String preload_depts = "deps/"+res_path.md5_text(); if (Globals::get_singleton()->has(preload_depts)) { external_resources.clear(); @@ -913,7 +978,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { external_resources[i].path=depts.get_name(i); } print_line(res_path+" - EXTERNAL RESOURCES: "+itos(external_resources.size())); - } + }*/ print_bl("ext resources: "+itos(ext_resources_size)); uint32_t int_resources_size=f->get_32(); @@ -973,7 +1038,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) { + if (ver_format>FORMAT_VERSION || ver_major>VERSION_MAJOR) { f->close(); return ""; @@ -1000,8 +1065,10 @@ ResourceInteractiveLoaderBinary::~ResourceInteractiveLoaderBinary() { } -Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(const String &p_path) { +Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(const String &p_path, Error *r_error) { + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -1114,7 +1181,7 @@ Error ResourceFormatLoaderBinary::load_import_metadata(const String &p_path, Ref } -void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<String> *p_dependencies) { +void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types) { FileAccess *f = FileAccess::open(p_path,FileAccess::READ); ERR_FAIL_COND(!f); @@ -1123,7 +1190,217 @@ void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<Stri ria->local_path=Globals::get_singleton()->localize_path(p_path); ria->res_path=ria->local_path; // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); - ria->get_dependencies(f,p_dependencies); + ria->get_dependencies(f,p_dependencies,p_add_types); +} + +Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path,const Map<String,String>& p_map) { + + +// Error error=OK; + + + FileAccess *f=FileAccess::open(p_path,FileAccess::READ); + ERR_FAIL_COND_V(!f,ERR_CANT_OPEN); + + FileAccess* fw=NULL;//=FileAccess::open(p_path+".depren"); + + String local_path=p_path.get_base_dir(); + + uint8_t header[4]; + f->get_buffer(header,4); + if (header[0]=='R' && header[1]=='S' && header[2]=='C' && header[3]=='C') { + //compressed + FileAccessCompressed *fac = memnew( FileAccessCompressed ); + fac->open_after_magic(f); + f=fac; + + FileAccessCompressed *facw = memnew( FileAccessCompressed ); + facw->configure("RSCC"); + Error err = facw->_open(p_path+".depren",FileAccess::WRITE); + if (err) { + memdelete(fac); + memdelete(facw); + ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); + } + + fw=facw; + + + } else if (header[0]!='R' || header[1]!='S' || header[2]!='R' || header[3]!='C') { + //not normal + + //error=ERR_FILE_UNRECOGNIZED; + memdelete(f); + ERR_EXPLAIN("Unrecognized binary resource file: "+local_path); + ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); + } else { + fw = FileAccess::open(p_path+".depren",FileAccess::WRITE); + if (!fw) { + memdelete(f); + } + ERR_FAIL_COND_V(!fw,ERR_CANT_CREATE); + } + + bool big_endian = f->get_32(); +#ifdef BIG_ENDIAN_ENABLED + endian_swap = !big_endian; +#else + bool endian_swap = big_endian; +#endif + + bool use_real64 = f->get_32(); + + f->set_endian_swap(big_endian!=0); //read big endian if saved as big endian + fw->store_32(endian_swap); + fw->set_endian_swap(big_endian!=0); + fw->store_32(use_real64); //use real64 + + uint32_t ver_major=f->get_32(); + uint32_t ver_minor=f->get_32(); + uint32_t ver_format=f->get_32(); + + if (ver_format<FORMAT_VERSION_CAN_RENAME_DEPS) { + + memdelete(f); + memdelete(fw); + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + da->remove(p_path+".depren"); + memdelete(da); + //fuck it, use the old approach; + + WARN_PRINT(("This file is old, so it can't refactor dependencies, opening and resaving: "+p_path).utf8().get_data()); + + Error err; + f = FileAccess::open(p_path,FileAccess::READ,&err); + if (err!=OK) { + ERR_FAIL_COND_V(err!=OK,ERR_FILE_CANT_OPEN); + } + + Ref<ResourceInteractiveLoaderBinary> ria = memnew( ResourceInteractiveLoaderBinary ); + ria->local_path=Globals::get_singleton()->localize_path(p_path); + ria->res_path=ria->local_path; + ria->remaps=p_map; + // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); + ria->open(f); + + err = ria->poll(); + + while(err==OK) { + err=ria->poll(); + } + + ERR_FAIL_COND_V(err!=ERR_FILE_EOF,ERR_FILE_CORRUPT); + RES res = ria->get_resource(); + ERR_FAIL_COND_V(!res.is_valid(),ERR_FILE_CORRUPT); + + return ResourceFormatSaverBinary::singleton->save(p_path,res); + } + + if (ver_format>FORMAT_VERSION || ver_major>VERSION_MAJOR) { + + memdelete(f); + memdelete(fw); + 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); + ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); + + } + + fw->store_32( VERSION_MAJOR ); //current version + fw->store_32( VERSION_MINOR ); + fw->store_32( FORMAT_VERSION ); + + save_ustring(fw,get_ustring(f)); //type + + + size_t md_ofs = f->get_pos(); + size_t importmd_ofs = f->get_64(); + fw->store_64(0); //metadata offset + + for(int i=0;i<14;i++) { + fw->store_32(0); + f->get_32(); + } + + //string table + uint32_t string_table_size=f->get_32(); + + fw->store_32(string_table_size); + + for(uint32_t i=0;i<string_table_size;i++) { + + String s = get_ustring(f); + save_ustring(fw,s); + } + + //external resources + uint32_t ext_resources_size=f->get_32(); + fw->store_32(ext_resources_size); + for(uint32_t i=0;i<ext_resources_size;i++) { + + String type = get_ustring(f); + String path = get_ustring(f); + + bool relative=false; + if (!path.begins_with("res://")) { + path=local_path.plus_file(path).simplify_path(); + relative=true; + } + + + if (p_map.has(path)) { + String np=p_map[path]; + path=np; + } + + if (relative) { + //restore relative + path=local_path.path_to_file(path); + } + + save_ustring(fw,type); + save_ustring(fw,path); + } + + int64_t size_diff = (int64_t)fw->get_pos() - (int64_t)f->get_pos(); + + //internal resources + uint32_t int_resources_size=f->get_32(); + fw->store_32(int_resources_size); + + for(uint32_t i=0;i<int_resources_size;i++) { + + + String path=get_ustring(f); + uint64_t offset=f->get_64(); + save_ustring(fw,path); + fw->store_64(offset+size_diff); + } + + //rest of file + uint8_t b = f->get_8(); + while(!f->eof_reached()) { + fw->store_8(b); + b = f->get_8(); + } + + bool all_ok = fw->get_error()==OK; + + fw->seek(md_ofs); + fw->store_64(importmd_ofs+size_diff); + + + memdelete(f); + memdelete(fw); + + if (!all_ok) { + return ERR_CANT_CREATE; + } + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + da->remove(p_path); + da->rename(p_path+".depren",p_path); + memdelete(da); + return OK; } @@ -1433,10 +1710,8 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant& p_property, } if (res->get_path().length() && res->get_path().find("::")==-1) { - f->store_32(OBJECT_EXTERNAL_RESOURCE); - save_unicode_string(res->get_save_type()); - String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); - save_unicode_string(path); + f->store_32(OBJECT_EXTERNAL_RESOURCE_INDEX); + f->store_32(external_resources[res]); } else { if (!resource_set.has(res)) { @@ -1594,11 +1869,12 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant& p_variant RES res = p_variant.operator RefPtr(); - if (res.is_null()) + if (res.is_null() || external_resources.has(res)) return; if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) { - external_resources.insert(res); + int idx = external_resources.size(); + external_resources[res]=idx; return; } @@ -1842,10 +2118,18 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_ // save external resource table f->store_32(external_resources.size()); //amount of external resources - for(Set<RES>::Element *E=external_resources.front();E;E=E->next()) { + Vector<RES> save_order; + save_order.resize(external_resources.size()); + + for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) { + save_order[E->get()]=E->key(); + } - save_unicode_string(E->get()->get_save_type()); - String path = E->get()->get_path(); + for(int i=0;i<save_order.size();i++) { + + save_unicode_string(save_order[i]->get_save_type()); + String path = save_order[i]->get_path(); + path=relative_paths?local_path.path_to_file(path):path; save_unicode_string(path); } // save internal resource table @@ -1995,3 +2279,9 @@ void ResourceFormatSaverBinary::get_recognized_extensions(const RES& p_resource, } +ResourceFormatSaverBinary* ResourceFormatSaverBinary::singleton=NULL; + +ResourceFormatSaverBinary::ResourceFormatSaverBinary() { + + singleton=this; +} diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index da415d97a5..8bf20bc574 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -71,6 +71,7 @@ class ResourceInteractiveLoaderBinary : public ResourceInteractiveLoader { String get_unicode_string(); void _advance_padding(uint32_t p_len); + Map<String,String> remaps; Error error; int stage; @@ -88,9 +89,10 @@ public: virtual int get_stage() const; virtual int get_stage_count() const; + void set_remaps(const Map<String,String>& p_remaps) { remaps=p_remaps; } void open(FileAccess *p_f); String recognize(FileAccess *p_f); - void get_dependencies(FileAccess *p_f,List<String> *p_dependencies); + void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types); ResourceInteractiveLoaderBinary(); @@ -101,13 +103,14 @@ public: class ResourceFormatLoaderBinary : public ResourceFormatLoader { public: - virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path); + virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,Error *r_error=NULL); virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; - virtual void get_dependencies(const String& p_path,List<String> *p_dependencies); + virtual void get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types=false); virtual Error load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const; + virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map); @@ -134,7 +137,7 @@ class ResourceFormatSaverBinaryInstance { Vector<StringName> strings; - Set<RES> external_resources; + Map<RES,int> external_resources; List<RES> saved_resources; @@ -174,11 +177,12 @@ class ResourceFormatSaverBinary : public ResourceFormatSaver { public: + static ResourceFormatSaverBinary* singleton; virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0); virtual bool recognize(const RES& p_resource) const; virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const; - + ResourceFormatSaverBinary(); }; diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp index b744cbf967..9019b4e3c0 100644 --- a/core/io/resource_format_xml.cpp +++ b/core/io/resource_format_xml.cpp @@ -29,10 +29,10 @@ #include "resource_format_xml.h" #include "globals.h" #include "version.h" +#include "os/dir_access.h" - -ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool *r_exit,bool p_printerr) { +ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool *r_exit, bool p_printerr, List<String> *r_order) { while(get_char()!='<' && !f->eof_reached()) {} @@ -107,7 +107,11 @@ ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool if (r_value.size()) { r_value.push_back(0); - tag.args[name].parse_utf8(r_value.get_data()); + String str; + str.parse_utf8(r_value.get_data()); + tag.args[name]=str; + if (r_order) + r_order->push_back(name); } break; @@ -119,7 +123,11 @@ ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool } else if (reading_value && r_value.size()) { r_value.push_back(0); - tag.args[name].parse_utf8(r_value.get_data()); + String str; + str.parse_utf8(r_value.get_data()); + tag.args[name]=str; + if (r_order) + r_order->push_back(name); name=""; r_value.clear(); reading_value=false; @@ -463,6 +471,10 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name) } + if (remaps.has(path)) { + path=remaps[path]; + } + //take advantage of the resource loader cache. The resource is cached on it, even if RES res=ResourceLoader::load(path,hint); @@ -473,10 +485,31 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name) } r_v=res.get_ref_ptr(); + } else if (tag->args.has("external")) { + + int index = tag->args["external"].to_int(); + if (ext_resources.has(index)) { + String path=ext_resources[index].path; + String type=ext_resources[index].type; + + //take advantage of the resource loader cache. The resource is cached on it, even if + RES res=ResourceLoader::load(path,type); + + if (res.is_null()) { + + WARN_PRINT(String("Couldn't load externalresource: "+path).ascii().get_data()); + } + + r_v=res.get_ref_ptr(); + } else { + WARN_PRINT(String("Invalid external resource index: "+itos(index)).ascii().get_data()); + + } } + Error err=goto_end_of_tag(); if (err) { ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error closing <resource> tag."); @@ -1364,32 +1397,6 @@ Error ResourceInteractiveLoaderXML::poll() { if (error!=OK) return error; - if (ext_resources.size()) { - - error=ERR_FILE_CORRUPT; - String path=ext_resources.front()->get(); - - RES res = ResourceLoader::load(path); - - if (res.is_null()) { - - if (ResourceLoader::get_abort_on_missing_resources()) { - ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": editor exported nonexistent resource at: "+path); - ERR_FAIL_V(error); - } else { - ResourceLoader::notify_load_error("Resource Not Found: "+path); - } - } else { - - resource_cache.push_back(res); - } - - error=OK; - ext_resources.pop_front(); - resource_current++; - return error; - } - bool exit; Tag *tag = parse_tag(&exit); @@ -1413,12 +1420,13 @@ Error ResourceInteractiveLoaderXML::poll() { ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> missing 'path' field."); ERR_FAIL_COND_V(!tag->args.has("path"),ERR_FILE_CORRUPT); - String type; + String type="Resource"; if (tag->args.has("type")) type=tag->args["type"]; String path = tag->args["path"]; + ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> can't use a local path, this is a bug?."); ERR_FAIL_COND_V(path.begins_with("local://"),ERR_FILE_CORRUPT); @@ -1427,6 +1435,9 @@ Error ResourceInteractiveLoaderXML::poll() { path=Globals::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); } + if (remaps.has(path)) { + path=remaps[path]; + } RES res = ResourceLoader::load(path,type); @@ -1436,13 +1447,21 @@ Error ResourceInteractiveLoaderXML::poll() { ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> referenced nonexistent resource at: "+path); ERR_FAIL_V(error); } else { - ResourceLoader::notify_load_error("Resource Not Found: "+path); + ResourceLoader::notify_dependency_error(local_path,path,type); } } else { resource_cache.push_back(res); } + if (tag->args.has("index")) { + ExtResource er; + er.path=path; + er.type=type; + ext_resources[tag->args["index"].to_int()]=er; + } + + Error err = close_tag("ext_resource"); if (err) return error; @@ -1566,7 +1585,7 @@ int ResourceInteractiveLoaderXML::get_stage() const { } int ResourceInteractiveLoaderXML::get_stage_count() const { - return resources_total+ext_resources.size(); + return resources_total;//+ext_resources; } ResourceInteractiveLoaderXML::~ResourceInteractiveLoaderXML() { @@ -1574,7 +1593,7 @@ ResourceInteractiveLoaderXML::~ResourceInteractiveLoaderXML() { memdelete(f); } -void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> *p_dependencies) { +void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> *p_dependencies,bool p_add_types) { open(f); @@ -1617,6 +1636,10 @@ void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> * path = ResourceLoader::guess_full_filename(path,type); } + if (p_add_types && tag->args.has("type")) { + path+="::"+tag->args["type"]; + } + p_dependencies->push_back(path); Error err = close_tag("ext_resource"); @@ -1628,6 +1651,167 @@ void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> * } +Error ResourceInteractiveLoaderXML::rename_dependencies(FileAccess *p_f, const String &p_path,const Map<String,String>& p_map) { + + open(p_f); + ERR_FAIL_COND_V(error!=OK,error); + + //FileAccess + + bool old_format=false; + + FileAccess *fw = NULL; + + String base_path=local_path.get_base_dir(); + + while(true) { + bool exit; + List<String> order; + + Tag *tag = parse_tag(&exit,true,&order); + + bool done=false; + + if (!tag) { + if (fw) { + memdelete(fw); + } + error=ERR_FILE_CORRUPT; + ERR_FAIL_COND_V(!exit,error); + error=ERR_FILE_EOF; + + return error; + } + + if (tag->name=="ext_resource") { + + if (!tag->args.has("index") || !tag->args.has("path") || !tag->args.has("type")) { + old_format=true; + break; + } + + if (!fw) { + + fw=FileAccess::open(p_path+".depren",FileAccess::WRITE); + fw->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); //no escape + fw->store_line("<resource_file type=\""+resource_type+"\" subresource_count=\""+itos(resources_total)+"\" version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\" version_name=\""+VERSION_FULL_NAME+"\">"); + + } + + String path = tag->args["path"]; + String index = tag->args["index"]; + String type = tag->args["type"]; + + + bool relative=false; + if (!path.begins_with("res://")) { + path=base_path.plus_file(path).simplify_path(); + relative=true; + } + + + if (p_map.has(path)) { + String np=p_map[path]; + path=np; + } + + if (relative) { + //restore relative + path=base_path.path_to_file(path); + } + + tag->args["path"]=path; + tag->args["index"]=index; + tag->args["type"]=type; + + } else { + + done=true; + } + + String tagt="\t<"; + if (exit) + tagt+="/"; + tagt+=tag->name; + + for(List<String>::Element *E=order.front();E;E=E->next()) { + tagt+=" "+E->get()+"=\""+tag->args[E->get()]+"\""; + } + tagt+=">"; + fw->store_line(tagt); + if (done) + break; + close_tag("ext_resource"); + fw->store_line("\t</ext_resource>"); + + } + + + if (old_format) { + if (fw) + memdelete(fw); + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + da->remove(p_path+".depren"); + memdelete(da); + //fuck it, use the old approach; + + WARN_PRINT(("This file is old, so it can't refactor dependencies, opening and resaving: "+p_path).utf8().get_data()); + + Error err; + FileAccess *f2 = FileAccess::open(p_path,FileAccess::READ,&err); + if (err!=OK) { + ERR_FAIL_COND_V(err!=OK,ERR_FILE_CANT_OPEN); + } + + Ref<ResourceInteractiveLoaderXML> ria = memnew( ResourceInteractiveLoaderXML ); + ria->local_path=Globals::get_singleton()->localize_path(p_path); + ria->res_path=ria->local_path; + ria->remaps=p_map; + // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); + ria->open(f2); + + err = ria->poll(); + + while(err==OK) { + err=ria->poll(); + } + + ERR_FAIL_COND_V(err!=ERR_FILE_EOF,ERR_FILE_CORRUPT); + RES res = ria->get_resource(); + ERR_FAIL_COND_V(!res.is_valid(),ERR_FILE_CORRUPT); + + return ResourceFormatSaverXML::singleton->save(p_path,res); + } + + if (!fw) { + + return OK; //nothing to rename, do nothing + } + + uint8_t c=f->get_8(); + while(!f->eof_reached()) { + fw->store_8(c); + c=f->get_8(); + } + + bool all_ok = fw->get_error()==OK; + + memdelete(fw); + + if (!all_ok) { + return ERR_CANT_CREATE; + } + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + da->remove(p_path); + da->rename(p_path+".depren",p_path); + memdelete(da); + + return OK; + +} + void ResourceInteractiveLoaderXML::open(FileAccess *p_f) { @@ -1686,6 +1870,7 @@ void ResourceInteractiveLoaderXML::open(FileAccess *p_f) { } + /* String preload_depts = "deps/"+local_path.md5_text(); if (Globals::get_singleton()->has(preload_depts)) { ext_resources.clear(); @@ -1697,7 +1882,7 @@ void ResourceInteractiveLoaderXML::open(FileAccess *p_f) { } print_line(local_path+" - EXTERNAL RESOURCES: "+itos(ext_resources.size())); } - +*/ } @@ -1730,7 +1915,10 @@ String ResourceInteractiveLoaderXML::recognize(FileAccess *p_f) { ///////////////////// -Ref<ResourceInteractiveLoader> ResourceFormatLoaderXML::load_interactive(const String &p_path) { +Ref<ResourceInteractiveLoader> ResourceFormatLoaderXML::load_interactive(const String &p_path, Error *r_error) { + + if (r_error) + *r_error=ERR_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -1816,7 +2004,7 @@ String ResourceFormatLoaderXML::get_resource_type(const String &p_path) const{ } -void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String> *p_dependencies) { +void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types) { FileAccess *f = FileAccess::open(p_path,FileAccess::READ); if (!f) { @@ -1828,11 +2016,27 @@ void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String> ria->local_path=Globals::get_singleton()->localize_path(p_path); ria->res_path=ria->local_path; // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); - ria->get_dependencies(f,p_dependencies); + ria->get_dependencies(f,p_dependencies,p_add_types); + +} + +Error ResourceFormatLoaderXML::rename_dependencies(const String &p_path,const Map<String,String>& p_map) { + + FileAccess *f = FileAccess::open(p_path,FileAccess::READ); + if (!f) { + ERR_FAIL_V(ERR_CANT_OPEN); + } + + Ref<ResourceInteractiveLoaderXML> ria = memnew( ResourceInteractiveLoaderXML ); + ria->local_path=Globals::get_singleton()->localize_path(p_path); + ria->res_path=ria->local_path; +// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); + return ria->rename_dependencies(f,p_path,p_map); } + /****************************************************************************************/ /****************************************************************************************/ /****************************************************************************************/ @@ -2024,20 +2228,26 @@ void ResourceFormatSaverXMLInstance::write_property(const String& p_name,const V return; // don't save it } - params="resource_type=\""+res->get_save_type()+"\""; + if (external_resources.has(res)) { - if (res->get_path().length() && res->get_path().find("::")==-1) { - //external resource - String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); - escape(path); - params+=" path=\""+path+"\""; + params="external=\""+itos(external_resources[res])+"\""; } else { + params="resource_type=\""+res->get_save_type()+"\""; - //internal resource - ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); - ERR_FAIL_COND(!resource_set.has(res)); - params+=" path=\"local://"+itos(res->get_subindex())+"\""; + if (res->get_path().length() && res->get_path().find("::")==-1) { + //external resource + String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); + escape(path); + params+=" path=\""+path+"\""; + } else { + + //internal resource + ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); + ERR_FAIL_COND(!resource_set.has(res)); + + params+=" path=\"local://"+itos(res->get_subindex())+"\""; + } } } break; @@ -2441,11 +2651,12 @@ void ResourceFormatSaverXMLInstance::_find_resources(const Variant& p_variant,bo RES res = p_variant.operator RefPtr(); - if (res.is_null()) + if (res.is_null() || external_resources.has(res)) return; if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) { - external_resources.push_back(res); + int index = external_resources.size(); + external_resources[res]=index; return; } @@ -2533,12 +2744,12 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res enter_tag("resource_file","type=\""+p_resource->get_type()+"\" subresource_count=\""+itos(saved_resources.size()+external_resources.size())+"\" version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\" version_name=\""+VERSION_FULL_NAME+"\""); write_string("\n",false); - for(List<RES>::Element *E=external_resources.front();E;E=E->next()) { + for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) { write_tabs(); - String p = E->get()->get_path(); + String p = E->key()->get_path(); - enter_tag("ext_resource","path=\""+p+"\" type=\""+E->get()->get_save_type()+"\""); //bundled + enter_tag("ext_resource","path=\""+p+"\" type=\""+E->key()->get_save_type()+"\" index=\""+itos(E->get())+"\""); //bundled exit_tag("ext_resource"); //bundled write_string("\n",false); } @@ -2667,3 +2878,8 @@ void ResourceFormatSaverXML::get_recognized_extensions(const RES& p_resource,Lis } } + +ResourceFormatSaverXML* ResourceFormatSaverXML::singleton=NULL; +ResourceFormatSaverXML::ResourceFormatSaverXML() { + singleton=this; +} diff --git a/core/io/resource_format_xml.h b/core/io/resource_format_xml.h index d5ba9eb800..77987c6a5b 100644 --- a/core/io/resource_format_xml.h +++ b/core/io/resource_format_xml.h @@ -46,13 +46,21 @@ class ResourceInteractiveLoaderXML : public ResourceInteractiveLoader { String name; HashMap<String,String> args; + }; _FORCE_INLINE_ Error _parse_array_element(Vector<char> &buff,bool p_number_only,FileAccess *f,bool *end); + struct ExtResource { + String path; + String type; + }; + - List<StringName> ext_resources; + Map<String,String> remaps; + + Map<int,ExtResource> ext_resources; int resources_total; int resource_current; @@ -66,7 +74,7 @@ friend class ResourceFormatLoaderXML; List<Tag> tag_stack; List<RES> resource_cache; - Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true); + Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true,List<String> *r_order=NULL); Error close_tag(const String& p_name); _FORCE_INLINE_ void unquote(String& p_str); Error goto_end_of_tag(); @@ -87,7 +95,8 @@ public: void open(FileAccess *p_f); String recognize(FileAccess *p_f); - void get_dependencies(FileAccess *p_f,List<String> *p_dependencies); + void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types); + Error rename_dependencies(FileAccess *p_f, const String &p_path,const Map<String,String>& p_map); ~ResourceInteractiveLoaderXML(); @@ -97,12 +106,13 @@ public: class ResourceFormatLoaderXML : public ResourceFormatLoader { public: - virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path); + virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,Error *r_error=NULL); virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; - virtual void get_dependencies(const String& p_path,List<String> *p_dependencies); + virtual void get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types=false); + virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map); }; @@ -125,7 +135,7 @@ class ResourceFormatSaverXMLInstance { int depth; Set<RES> resource_set; List<RES> saved_resources; - List<RES> external_resources; + Map<RES,int> external_resources; void enter_tag(const char* p_tag,const String& p_args=String()); void exit_tag(const char* p_tag); @@ -148,11 +158,12 @@ public: class ResourceFormatSaverXML : public ResourceFormatSaver { public: + static ResourceFormatSaverXML* singleton; virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0); virtual bool recognize(const RES& p_resource) const; virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const; - + ResourceFormatSaverXML(); }; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 22d89840ae..1e014480f4 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -103,10 +103,10 @@ public: -Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const String &p_path) { +Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const String &p_path, Error *r_error) { //either this - Ref<Resource> res = load(p_path); + Ref<Resource> res = load(p_path,p_path,r_error); if (res.is_null()) return Ref<ResourceInteractiveLoader>(); @@ -115,12 +115,13 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const Stri return ril; } -RES ResourceFormatLoader::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoader::load(const String &p_path, const String& p_original_path, Error *r_error) { + String path=p_path; //or this must be implemented - Ref<ResourceInteractiveLoader> ril = load_interactive(p_path); + Ref<ResourceInteractiveLoader> ril = load_interactive(p_path,r_error); if (!ril.is_valid()) return RES(); ril->set_local_path(p_original_path); @@ -130,9 +131,14 @@ RES ResourceFormatLoader::load(const String &p_path,const String& p_original_pat Error err = ril->poll(); if (err==ERR_FILE_EOF) { + if (r_error) + *r_error=OK; return ril->get_resource(); } + if (r_error) + *r_error=err; + ERR_FAIL_COND_V(err!=OK,RES()); } @@ -140,7 +146,7 @@ RES ResourceFormatLoader::load(const String &p_path,const String& p_original_pat } -void ResourceFormatLoader::get_dependencies(const String& p_path,List<String> *p_dependencies) { +void ResourceFormatLoader::get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types) { //do nothing by default } @@ -149,7 +155,10 @@ void ResourceFormatLoader::get_dependencies(const String& p_path,List<String> *p /////////////////////////////////// -RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_no_cache) { +RES ResourceLoader::load(const String &p_path, const String& p_type_hint, bool p_no_cache, Error *r_error) { + + if (r_error) + *r_error=ERR_CANT_OPEN; String local_path; if (p_path.is_rel_path()) @@ -183,7 +192,7 @@ RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_n if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) continue; found=true; - RES res = loader[i]->load(remapped_path,local_path); + RES res = loader[i]->load(remapped_path,local_path,r_error); if (res.is_null()) continue; if (!p_no_cache) @@ -289,9 +298,11 @@ String ResourceLoader::find_complete_path(const String& p_path,const String& p_t return local_path; } -Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path,const String& p_type_hint,bool p_no_cache) { +Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path,const String& p_type_hint,bool p_no_cache,Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; String local_path; if (p_path.is_rel_path()) @@ -327,7 +338,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) continue; found=true; - Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(remapped_path); + Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(remapped_path,r_error); if (ril.is_null()) continue; if (!p_no_cache) @@ -352,7 +363,32 @@ void ResourceLoader::add_resource_format_loader(ResourceFormatLoader *p_format_l loader[loader_count++]=p_format_loader; } -void ResourceLoader::get_dependencies(const String& p_path,List<String> *p_dependencies) { +void ResourceLoader::get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types) { + + + String local_path; + if (p_path.is_rel_path()) + local_path="res://"+p_path; + else + local_path = Globals::get_singleton()->localize_path(p_path); + + String remapped_path = PathRemap::get_singleton()->get_remap(local_path); + + String extension=remapped_path.extension(); + + for (int i=0;i<loader_count;i++) { + + if (!loader[i]->recognize(extension)) + continue; + //if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) + // continue; + + loader[i]->get_dependencies(remapped_path,p_dependencies,p_add_types); + + } +} + +Error ResourceLoader::rename_dependencies(const String &p_path,const Map<String,String>& p_map) { String local_path; @@ -372,11 +408,15 @@ void ResourceLoader::get_dependencies(const String& p_path,List<String> *p_depen //if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) // continue; - loader[i]->get_dependencies(remapped_path,p_dependencies); + return loader[i]->rename_dependencies(p_path,p_map); } + + return OK; // ?? + } + String ResourceLoader::guess_full_filename(const String &p_path,const String& p_type) { String local_path; @@ -414,6 +454,9 @@ String ResourceLoader::get_resource_type(const String &p_path) { ResourceLoadErrorNotify ResourceLoader::err_notify=NULL; void *ResourceLoader::err_notify_ud=NULL; +DependencyErrorNotify ResourceLoader::dep_err_notify=NULL; +void *ResourceLoader::dep_err_notify_ud=NULL; + bool ResourceLoader::abort_on_missing_resource=true; bool ResourceLoader::timestamp_on_load=false; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index d25727f19f..00a05dcb43 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -57,21 +57,23 @@ public: class ResourceFormatLoader { public: - virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path); - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,Error *r_error=NULL); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const=0; virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const; bool recognize(const String& p_extension) const; virtual bool handles_type(const String& p_type) const=0; virtual String get_resource_type(const String &p_path) const=0; - virtual void get_dependencies(const String& p_path,List<String> *p_dependencies); + virtual void get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types=false); virtual Error load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const { return ERR_UNAVAILABLE; } + virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map) { return OK; } virtual ~ResourceFormatLoader() {} }; typedef void (*ResourceLoadErrorNotify)(void *p_ud,const String& p_text); +typedef void (*DependencyErrorNotify)(void *p_ud,const String& p_loading,const String& p_which,const String& p_type); class ResourceLoader { @@ -86,6 +88,8 @@ class ResourceLoader { static void* err_notify_ud; static ResourceLoadErrorNotify err_notify; + static void* dep_err_notify_ud; + static DependencyErrorNotify dep_err_notify; static bool abort_on_missing_resource; static String find_complete_path(const String& p_path,const String& p_type); @@ -93,14 +97,15 @@ public: - static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,const String& p_type_hint="",bool p_no_cache=false); - static RES load(const String &p_path,const String& p_type_hint="",bool p_no_cache=false); + static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,const String& p_type_hint="",bool p_no_cache=false,Error *r_error=NULL); + static RES load(const String &p_path,const String& p_type_hint="",bool p_no_cache=false,Error *r_error=NULL); static Ref<ResourceImportMetadata> load_import_metadata(const String &p_path); static void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions); static void add_resource_format_loader(ResourceFormatLoader *p_format_loader); static String get_resource_type(const String &p_path); - static void get_dependencies(const String& p_path,List<String> *p_dependencies); + static void get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types=false); + static Error rename_dependencies(const String &p_path,const Map<String,String>& p_map); static String guess_full_filename(const String &p_path,const String& p_type); @@ -108,6 +113,11 @@ public: static void notify_load_error(const String& p_err) { if (err_notify) err_notify(err_notify_ud,p_err); } static void set_error_notify_func(void* p_ud,ResourceLoadErrorNotify p_err_notify) { err_notify=p_err_notify; err_notify_ud=p_ud;} + + static void notify_dependency_error(const String& p_path,const String& p_dependency,const String& p_type) { if (dep_err_notify) dep_err_notify(dep_err_notify_ud,p_path,p_dependency,p_type); } + static void set_dependency_error_notify_func(void* p_ud,DependencyErrorNotify p_err_notify) { dep_err_notify=p_err_notify; dep_err_notify_ud=p_ud;} + + static void set_abort_on_missing_resources(bool p_abort) { abort_on_missing_resource=p_abort; } static bool get_abort_on_missing_resources() { return abort_on_missing_resource; } }; diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h index 05cbe7f98e..8382b65290 100644 --- a/core/io/resource_saver.h +++ b/core/io/resource_saver.h @@ -46,7 +46,7 @@ public: virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0)=0; virtual bool recognize(const RES& p_resource) const=0; virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const=0; - + virtual ~ResourceFormatSaver() {} }; diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index c32b25c407..020d168208 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -30,7 +30,10 @@ #include "os/file_access.h" #include "translation.h" -RES TranslationLoaderPO::load(const String &p_path,const String& p_original_path) { +RES TranslationLoaderPO::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_CANT_OPEN; FileAccess *f=FileAccess::open(p_path,FileAccess::READ); ERR_FAIL_COND_V(!f,RES()); @@ -49,6 +52,8 @@ RES TranslationLoaderPO::load(const String &p_path,const String& p_original_path String msg_id; String msg_str; String config; + if (r_error) + *r_error=ERR_FILE_CORRUPT; Ref<Translation> translation = Ref<Translation>( memnew( Translation )); int line = 1; @@ -174,6 +179,8 @@ RES TranslationLoaderPO::load(const String &p_path,const String& p_original_path } } + if (r_error) + *r_error=OK; return translation; diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h index 9d8ad97a29..e07ae15e28 100644 --- a/core/io/translation_loader_po.h +++ b/core/io/translation_loader_po.h @@ -34,7 +34,7 @@ class TranslationLoaderPO : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/core/io/zip.h b/core/io/zip.h index cca06c2ee8..85f93568c9 100644 --- a/core/io/zip.h +++ b/core/io/zip.h @@ -39,6 +39,8 @@ #ifndef _zip12_H #define _zip12_H +#include <stdlib.h> + #ifdef __cplusplus extern "C" { #endif diff --git a/core/io/zip_io.h b/core/io/zip_io.h index c4b4d6b34d..dd3c371a4a 100644 --- a/core/io/zip_io.h +++ b/core/io/zip_io.h @@ -34,6 +34,7 @@ #include "os/file_access.h" #include "os/copymem.h" + static void* zipio_open(void* data, const char* p_fname, int mode) { FileAccess *&f = *(FileAccess**)data; diff --git a/core/object_type_db.cpp b/core/object_type_db.cpp index c291714573..a64b3d2715 100644 --- a/core/object_type_db.cpp +++ b/core/object_type_db.cpp @@ -746,6 +746,25 @@ bool ObjectTypeDB::has_method(StringName p_type,StringName p_method,bool p_no_in } +bool ObjectTypeDB::get_setter_and_type_for_property(const StringName& p_class, const StringName& p_prop, StringName& r_class, StringName& r_setter) { + + TypeInfo *type=types.getptr(p_class); + TypeInfo *check=type; + while(check) { + + if (check->property_setget.has(p_prop)) { + r_class=check->name; + r_setter=check->property_setget[p_prop].setter; + return true; + } + + check=check->inherits_ptr; + } + + return false; + +} + #ifdef DEBUG_METHODS_ENABLED MethodBind* ObjectTypeDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind , const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) { StringName mdname=method_name.name; diff --git a/core/object_type_db.h b/core/object_type_db.h index caa5baddd5..bfa0f921e5 100644 --- a/core/object_type_db.h +++ b/core/object_type_db.h @@ -475,7 +475,9 @@ public: static void get_integer_constant_list(const StringName& p_type, List<String> *p_constants, bool p_no_inheritance=false); static int get_integer_constant(const StringName& p_type, const StringName &p_name, bool *p_success=NULL); static StringName get_category(const StringName& p_node); - + + static bool get_setter_and_type_for_property(const StringName& p_class, const StringName& p_prop, StringName& r_class, StringName& r_setter); + static void set_type_enabled(StringName p_type,bool p_enable); static bool is_type_enabled(StringName p_type); diff --git a/core/os/input.cpp b/core/os/input.cpp index 2b939ede46..cf2938f5cd 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -271,6 +271,38 @@ void InputDefault::parse_input_event(const InputEvent& p_event) { mouse_button_mask|=(1<<p_event.mouse_button.button_index); else mouse_button_mask&=~(1<<p_event.mouse_button.button_index); + + if (main_loop && emulate_touch && p_event.mouse_button.button_index==1) { + InputEventScreenTouch touch_event; + touch_event.index=0; + touch_event.pressed=p_event.mouse_button.pressed; + touch_event.x=p_event.mouse_button.x; + touch_event.y=p_event.mouse_button.y; + InputEvent ev; + ev.type=InputEvent::SCREEN_TOUCH; + ev.screen_touch=touch_event; + main_loop->input_event(ev); + } + } break; + case InputEvent::MOUSE_MOTION: { + + if (main_loop && emulate_touch && p_event.mouse_motion.button_mask&1) { + InputEventScreenDrag drag_event; + drag_event.index=0; + drag_event.x=p_event.mouse_motion.x; + drag_event.y=p_event.mouse_motion.y; + drag_event.relative_x=p_event.mouse_motion.relative_x; + drag_event.relative_y=p_event.mouse_motion.relative_y; + drag_event.speed_x=p_event.mouse_motion.speed_x; + drag_event.speed_y=p_event.mouse_motion.speed_y; + + InputEvent ev; + ev.type=InputEvent::SCREEN_DRAG; + ev.screen_drag=drag_event; + + main_loop->input_event(ev); + } + } break; case InputEvent::JOYSTICK_BUTTON: { @@ -362,8 +394,19 @@ void InputDefault::action_release(const StringName& p_action){ } } +void InputDefault::set_emulate_touch(bool p_emulate) { + + emulate_touch=p_emulate; +} + +bool InputDefault::is_emulating_touchscreen() const { + + return emulate_touch; +} + InputDefault::InputDefault() { mouse_button_mask=0; + emulate_touch=false; main_loop=NULL; } diff --git a/core/os/input.h b/core/os/input.h index ce14c2166e..5c69ced825 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -78,6 +78,8 @@ public: void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const; + virtual bool is_emulating_touchscreen() const=0; + Input(); }; @@ -99,6 +101,8 @@ class InputDefault : public Input { Vector2 mouse_pos; MainLoop *main_loop; + bool emulate_touch; + struct SpeedTrack { uint64_t last_tick; @@ -147,6 +151,9 @@ public: void iteration(float p_step); + void set_emulate_touch(bool p_emulate); + virtual bool is_emulating_touchscreen() const; + InputDefault(); }; diff --git a/core/os/os.cpp b/core/os/os.cpp index efcd492230..2db926e556 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -31,7 +31,7 @@ #include <stdarg.h> #include "dir_access.h" #include "globals.h" - +#include "input.h" OS* OS::singleton=NULL; @@ -363,7 +363,7 @@ Error OS::set_cwd(const String& p_cwd) { bool OS::has_touchscreen_ui_hint() const { //return false; - return GLOBAL_DEF("display/emulate_touchscreen",false); + return Input::get_singleton() && Input::get_singleton()->is_emulating_touchscreen(); } int OS::get_free_static_memory() const { diff --git a/core/os/os.h b/core/os/os.h index e8ecfa1054..d89734d7d3 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -155,7 +155,7 @@ public: virtual int get_screen_count() const{ return 1; } virtual int get_current_screen() const { return 0; } virtual void set_current_screen(int p_screen) { } - virtual Point2 get_screen_position(int p_screen=0) { return Point2(); } + virtual Point2 get_screen_position(int p_screen=0) const { return Point2(); } virtual Size2 get_screen_size(int p_screen=0) const { return get_window_size(); } virtual Point2 get_window_position() const { return Vector2(); } virtual void set_window_position(const Point2& p_position) {} diff --git a/core/typedefs.h b/core/typedefs.h index ae1eb1f5e7..6ca31fd137 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -41,8 +41,8 @@ #define _MKSTR(m_x) _STR(m_x) #endif // have to include version.h for this to work, include it in the .cpp not the .h -#define VERSION_MKSTRING _MKSTR(VERSION_MAJOR)"."_MKSTR(VERSION_MINOR)"."_MKSTR(VERSION_STATUS)"."_MKSTR(VERSION_REVISION) -#define VERSION_FULL_NAME _MKSTR(VERSION_NAME)" v"VERSION_MKSTRING +#define VERSION_MKSTRING _MKSTR(VERSION_MAJOR)"." _MKSTR(VERSION_MINOR)"." _MKSTR(VERSION_STATUS)"." _MKSTR(VERSION_REVISION) +#define VERSION_FULL_NAME _MKSTR(VERSION_NAME)" v" VERSION_MKSTRING #ifndef _ALWAYS_INLINE_ diff --git a/core/ustring.cpp b/core/ustring.cpp index 3cfc1e4a3c..ff7c8984fa 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -3048,6 +3048,37 @@ bool String::is_valid_identifier() const { //kind of poor should be rewritten properly +String String::world_wrap(int p_chars_per_line) const { + + int from=0; + int last_space=0; + String ret; + for(int i=0;i<length();i++) { + if (i-from>=p_chars_per_line) { + if (last_space==-1) { + ret+=substr(from,i-from+1)+"\n"; + } else { + ret+=substr(from,last_space-from)+"\n"; + i=last_space; //rewind + } + from=i+1; + last_space=-1; + } else if (operator[](i)==' ' || operator[](i)=='\t') { + last_space=i; + } else if (operator[](i)=='\n') { + ret+=substr(from,i-from); + from=i+1; + last_space=-1; + } + } + + if (from<length()) { + ret+=substr(from,length()); + } + + return ret; +} + String String::c_unescape() const { String escaped=*this; diff --git a/core/ustring.h b/core/ustring.h index 1000c1cc8a..fa25a07eb0 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -209,6 +209,7 @@ public: String xml_unescape() const; String c_escape() const; String c_unescape() const; + String world_wrap(int p_chars_per_line) const; String percent_encode() const; String percent_decode() const; diff --git a/core/variant.cpp b/core/variant.cpp index e0bceb4dd8..c6a55b10e6 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -1592,9 +1592,17 @@ Variant::operator String() const { } break; case OBJECT: { - if (_get_obj().obj) + if (_get_obj().obj) { + #ifdef DEBUG_ENABLED + if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null()) { + //only if debugging! + if (!ObjectDB::instance_validate(_get_obj().obj)) { + return "[Deleted Object]"; + }; + }; + #endif return "["+_get_obj().obj->get_type()+":"+itos(_get_obj().obj->get_instance_ID())+"]"; - else + } else return "[Object:null]"; } break; diff --git a/demos/2d/dynamic_collision_shapes/ball.gd b/demos/2d/dynamic_collision_shapes/ball.gd new file mode 100644 index 0000000000..c17b20f9c8 --- /dev/null +++ b/demos/2d/dynamic_collision_shapes/ball.gd @@ -0,0 +1,21 @@ + +extends RigidBody2D + +# member variables here, example: +# var a=2 +# var b="textvar" + +var timeout=5 + +func _process(delta): + timeout-=delta + if (timeout<1): + set_opacity(timeout) + if (timeout<0): + queue_free() +func _ready(): + set_process(true) + # Initialization here + pass + + diff --git a/demos/2d/dynamic_collision_shapes/ball.png b/demos/2d/dynamic_collision_shapes/ball.png Binary files differnew file mode 100644 index 0000000000..b7cf71da29 --- /dev/null +++ b/demos/2d/dynamic_collision_shapes/ball.png diff --git a/demos/2d/dynamic_collision_shapes/ball.scn b/demos/2d/dynamic_collision_shapes/ball.scn Binary files differnew file mode 100644 index 0000000000..e332de276d --- /dev/null +++ b/demos/2d/dynamic_collision_shapes/ball.scn diff --git a/demos/2d/dynamic_collision_shapes/box.png b/demos/2d/dynamic_collision_shapes/box.png Binary files differnew file mode 100644 index 0000000000..f29b83ce38 --- /dev/null +++ b/demos/2d/dynamic_collision_shapes/box.png diff --git a/demos/2d/dynamic_collision_shapes/circle.png b/demos/2d/dynamic_collision_shapes/circle.png Binary files differnew file mode 100644 index 0000000000..9fdfa550b1 --- /dev/null +++ b/demos/2d/dynamic_collision_shapes/circle.png diff --git a/demos/2d/dynamic_collision_shapes/dynamic_colobjs.gd b/demos/2d/dynamic_collision_shapes/dynamic_colobjs.gd new file mode 100644 index 0000000000..a6a42a1914 --- /dev/null +++ b/demos/2d/dynamic_collision_shapes/dynamic_colobjs.gd @@ -0,0 +1,23 @@ + +extends Node2D + +# member variables here, example: +# var a=2 +# var b="textvar" +const EMIT_INTERVAL=0.1 +var timeout=EMIT_INTERVAL + +func _process(delta): + timeout-=delta + if (timeout<0): + timeout=EMIT_INTERVAL + var ball = preload("res://ball.scn").instance() + ball.set_pos( Vector2(randf() * get_viewport_rect().size.x, 0) ) + add_child(ball) + +func _ready(): + set_process(true) + # Initialization here + pass + + diff --git a/demos/2d/dynamic_collision_shapes/dynamic_colobjs.scn b/demos/2d/dynamic_collision_shapes/dynamic_colobjs.scn Binary files differnew file mode 100644 index 0000000000..e6d1ebf9cf --- /dev/null +++ b/demos/2d/dynamic_collision_shapes/dynamic_colobjs.scn diff --git a/demos/2d/dynamic_collision_shapes/engine.cfg b/demos/2d/dynamic_collision_shapes/engine.cfg new file mode 100644 index 0000000000..536b75f2f2 --- /dev/null +++ b/demos/2d/dynamic_collision_shapes/engine.cfg @@ -0,0 +1,4 @@ +[application] + +name="Run-Time CollisionShape" +main_scene="res://dynamic_colobjs.scn" diff --git a/demos/2d/dynamic_collision_shapes/poly.png b/demos/2d/dynamic_collision_shapes/poly.png Binary files differnew file mode 100644 index 0000000000..49ed55cc7d --- /dev/null +++ b/demos/2d/dynamic_collision_shapes/poly.png diff --git a/demos/2d/isometric/dungeon.scn b/demos/2d/isometric/dungeon.scn Binary files differindex 64efc257c0..e03a3bd3dd 100644 --- a/demos/2d/isometric/dungeon.scn +++ b/demos/2d/isometric/dungeon.scn diff --git a/demos/2d/lights_shadows/light_shadows.scn b/demos/2d/lights_shadows/light_shadows.scn Binary files differindex a13e31376e..152f68a407 100644 --- a/demos/2d/lights_shadows/light_shadows.scn +++ b/demos/2d/lights_shadows/light_shadows.scn diff --git a/demos/2d/platformer/engine.cfg b/demos/2d/platformer/engine.cfg index 50b6b862e9..044d661e3e 100644 --- a/demos/2d/platformer/engine.cfg +++ b/demos/2d/platformer/engine.cfg @@ -4,14 +4,14 @@ name="Platformer" main_scene="res://stage.xml" icon="res://icon.png" name_es="Plataformero" +target_fps="60" [display] width=800 height=480 -stretch_2d=false -stretch_mode="viewport" -stretch_aspect="keep" +stretch_mode="2d" +stretch_aspect="keep_height" [image_loader] diff --git a/demos/2d/platformer/stage.xml b/demos/2d/platformer/stage.xml index 4d6083adf6..d081a1be38 100644 --- a/demos/2d/platformer/stage.xml +++ b/demos/2d/platformer/stage.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<resource_file type="PackedScene" subresource_count="10" version="1.1" version_name="Godot Engine v1.1.rc1.custom_build"> +<resource_file type="PackedScene" subresource_count="10" version="1.1" version_name="Godot Engine v1.1.stable.custom_build"> <ext_resource path="res://tileset.xml" type="TileSet"></ext_resource> <ext_resource path="res://coin.xml" type="PackedScene"></ext_resource> <ext_resource path="res://moving_platform.xml" type="PackedScene"></ext_resource> @@ -16,22 +16,12 @@ <string> "conns" </string> <int_array len="0"> </int_array> <string> "names" </string> - <string_array len="133"> + <string_array len="117"> <string> "stage" </string> <string> "Node" </string> - <string> "_import_path" </string> <string> "__meta__" </string> <string> "tile_map" </string> <string> "TileMap" </string> - <string> "visibility/visible" </string> - <string> "visibility/opacity" </string> - <string> "visibility/self_opacity" </string> - <string> "visibility/light_mask" </string> - <string> "transform/pos" </string> - <string> "transform/rot" </string> - <string> "transform/scale" </string> - <string> "z/z" </string> - <string> "z/relative" </string> <string> "mode" </string> <string> "tile_set" </string> <string> "cell/size" </string> @@ -49,6 +39,8 @@ <string> "coins" </string> <string> "coin" </string> <string> "Area2D" </string> + <string> "_import_path" </string> + <string> "transform/pos" </string> <string> "coin 2" </string> <string> "coin 3" </string> <string> "coin 4" </string> @@ -129,14 +121,9 @@ <string> "margin/top" </string> <string> "margin/right" </string> <string> "margin/bottom" </string> - <string> "focus_neighbour/left" </string> - <string> "focus_neighbour/top" </string> - <string> "focus_neighbour/right" </string> - <string> "focus_neighbour/bottom" </string> <string> "focus/ignore_mouse" </string> <string> "focus/stop_mouse" </string> <string> "size_flags/horizontal" </string> - <string> "size_flags/stretch_ratio" </string> <string> "range/min" </string> <string> "range/max" </string> <string> "range/step" </string> @@ -145,19 +132,15 @@ <string> "range/exp_edit" </string> <string> "rounded_values" </string> <string> "text" </string> - <string> "align" </string> - <string> "valign" </string> <string> "autowrap" </string> - <string> "uppercase" </string> <string> "percent_visible" </string> </string_array> <string> "node_count" </string> <int> 67 </int> <string> "nodes" </string> - <int_array len="973"> -1, -1, 1, 0, -1, 2, 2, 0, 3, 1, 0, 0, 0, 5, 4, -1, 25, 2, 0, 6, 2, 7, 3, 8, 3, 9, 4, 10, 5, 11, 6, 12, 7, 13, 8, 14, 2, 15, 8, 16, 9, 17, 10, 18, 11, 19, 12, 20, 13, 21, 8, 22, 14, 23, 14, 24, 3, 25, 6, 26, 4, 27, 4, 28, 15, 3, 16, 0, 0, 0, 1, 29, -1, 1, 2, 0, 0, 2, 0, 31, 30, 17, 3, 2, 0, 10, 18, 3, 19, 0, 2, 0, 31, 32, 17, 3, 2, 0, 10, 20, 3, 19, 0, 2, 0, 31, 33, 17, 3, 2, 0, 10, 21, 3, 19, 0, 2, 0, 31, 34, 17, 3, 2, 0, 10, 22, 3, 19, 0, 2, 0, 31, 35, 17, 3, 2, 0, 10, 23, 3, 19, 0, 2, 0, 31, 36, 17, 3, 2, 0, 10, 24, 3, 19, 0, 2, 0, 31, 37, 17, 3, 2, 0, 10, 25, 3, 19, 0, 2, 0, 31, 38, 17, 3, 2, 0, 10, 26, 3, 19, 0, 2, 0, 31, 39, 17, 3, 2, 0, 10, 27, 3, 19, 0, 2, 0, 31, 40, 17, 3, 2, 0, 10, 28, 3, 19, 0, 2, 0, 31, 41, 17, 3, 2, 0, 10, 29, 3, 19, 0, 2, 0, 31, 42, 17, 3, 2, 0, 10, 30, 3, 19, 0, 2, 0, 31, 43, 17, 3, 2, 0, 10, 31, 3, 19, 0, 2, 0, 31, 44, 17, 3, 2, 0, 10, 32, 3, 19, 0, 2, 0, 31, 45, 17, 3, 2, 0, 10, 33, 3, 19, 0, 2, 0, 31, 46, 17, 3, 2, 0, 10, 34, 3, 19, 0, 2, 0, 31, 47, 17, 3, 2, 0, 10, 35, 3, 19, 0, 2, 0, 31, 48, 17, 3, 2, 0, 10, 36, 3, 19, 0, 2, 0, 31, 49, 17, 3, 2, 0, 10, 37, 3, 19, 0, 2, 0, 31, 50, 17, 3, 2, 0, 10, 38, 3, 19, 0, 2, 0, 31, 51, 17, 3, 2, 0, 10, 39, 3, 19, 0, 2, 0, 31, 52, 17, 3, 2, 0, 10, 40, 3, 19, 0, 2, 0, 31, 53, 17, 3, 2, 0, 10, 41, 3, 19, 0, 2, 0, 31, 54, 17, 3, 2, 0, 10, 42, 3, 19, 0, 2, 0, 31, 55, 17, 3, 2, 0, 10, 43, 3, 19, 0, 2, 0, 31, 56, 17, 3, 2, 0, 10, 44, 3, 19, 0, 2, 0, 31, 57, 17, 3, 2, 0, 10, 45, 3, 19, 0, 2, 0, 31, 58, 17, 3, 2, 0, 10, 46, 3, 19, 0, 2, 0, 31, 59, 17, 3, 2, 0, 10, 47, 3, 19, 0, 2, 0, 31, 60, 17, 3, 2, 0, 10, 48, 3, 19, 0, 2, 0, 31, 61, 17, 3, 2, 0, 10, 49, 3, 19, 0, 2, 0, 31, 62, 17, 3, 2, 0, 10, 50, 3, 19, 0, 2, 0, 31, 63, 17, 3, 2, 0, 10, 51, 3, 19, 0, 2, 0, 31, 64, 17, 3, 2, 0, 10, 52, 3, 19, 0, 2, 0, 31, 65, 17, 3, 2, 0, 10, 53, 3, 19, 0, 2, 0, 31, 66, 17, 3, 2, 0, 10, 54, 3, 19, 0, 2, 0, 31, 67, 17, 3, 2, 0, 10, 55, 3, 19, 0, 2, 0, 31, 68, 17, 3, 2, 0, 10, 56, 3, 19, 0, 2, 0, 31, 69, 17, 3, 2, 0, 10, 57, 3, 19, 0, 2, 0, 31, 70, 17, 3, 2, 0, 10, 58, 3, 19, 0, 2, 0, 31, 71, 17, 3, 2, 0, 10, 59, 3, 19, 0, 2, 0, 31, 72, 17, 3, 2, 0, 10, 60, 3, 19, 0, 0, 0, 1, 73, -1, 1, 2, 0, 0, 45, 0, 75, 74, 61, 5, 2, 0, 10, 62, 3, 63, 76, 64, 77, 65, 0, 45, 0, 75, 78, 61, 5, 2, 0, 10, 66, 3, 63, 76, 67, 77, 68, 0, 45, 0, 75, 79, 61, 5, 2, 0, 10, 69, 3, 63, 76, 70, 77, 68, 0, 45, 0, 75, 80, 71, 3, 2, 0, 10, 72, 3, 73, 0, 45, 0, 82, 81, 74, 3, 2, 0, 10, 75, 3, 76, 0, 0, 0, 84, 83, 77, 3, 2, 0, 10, 78, 3, 79, 0, 0, 0, 86, 85, -1, 7, 2, 0, 87, 80, 88, 14, 89, 2, 90, 81, 91, 2, 92, 14, 0, 0, 0, 1, 93, -1, 1, 2, 0, 0, 53, 0, 84, 94, 82, 3, 2, 0, 10, 83, 3, 84, 0, 53, 0, 84, 95, 82, 3, 2, 0, 10, 85, 3, 84, 0, 53, 0, 84, 96, 82, 3, 2, 0, 10, 86, 3, 84, 0, 53, 0, 84, 97, 82, 3, 2, 0, 10, 87, 3, 84, 0, 53, 0, 84, 98, 82, 3, 2, 0, 10, 88, 3, 84, 0, 53, 0, 84, 99, 82, 3, 2, 0, 10, 89, 3, 84, 0, 53, 0, 84, 100, 82, 3, 2, 0, 10, 90, 3, 84, 0, 53, 0, 84, 101, 82, 3, 2, 0, 10, 91, 3, 84, 0, 53, 0, 84, 102, 82, 3, 2, 0, 10, 92, 3, 84, 0, 53, 0, 84, 103, 82, 3, 2, 0, 10, 93, 3, 84, 0, 53, 0, 84, 104, 82, 3, 2, 0, 10, 94, 3, 84, 0, 0, 0, 106, 105, 95, 2, 2, 0, 3, 96, 0, 0, 0, 107, 107, -1, 30, 2, 0, 6, 2, 7, 3, 8, 3, 9, 4, 108, 97, 109, 98, 110, 99, 111, 100, 112, 0, 113, 0, 114, 0, 115, 0, 116, 2, 117, 2, 118, 13, 119, 3, 120, 6, 121, 101, 122, 3, 123, 102, 124, 6, 125, 14, 126, 14, 127, 103, 128, 8, 129, 8, 130, 2, 131, 14, 132, 104, 0 </int_array> + <int_array len="917"> -1, -1, 1, 0, -1, 1, 2, 0, 0, 0, 0, 4, 3, -1, 15, 5, 1, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 1, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 10, 18, 11, 2, 12, 0, 0, 0, 1, 19, -1, 0, 0, 2, 0, 21, 20, 13, 3, 22, 14, 23, 15, 2, 16, 0, 2, 0, 21, 24, 13, 3, 22, 14, 23, 17, 2, 16, 0, 2, 0, 21, 25, 13, 3, 22, 14, 23, 18, 2, 16, 0, 2, 0, 21, 26, 13, 3, 22, 14, 23, 19, 2, 16, 0, 2, 0, 21, 27, 13, 3, 22, 14, 23, 20, 2, 16, 0, 2, 0, 21, 28, 13, 3, 22, 14, 23, 21, 2, 16, 0, 2, 0, 21, 29, 13, 3, 22, 14, 23, 22, 2, 16, 0, 2, 0, 21, 30, 13, 3, 22, 14, 23, 23, 2, 16, 0, 2, 0, 21, 31, 13, 3, 22, 14, 23, 24, 2, 16, 0, 2, 0, 21, 32, 13, 3, 22, 14, 23, 25, 2, 16, 0, 2, 0, 21, 33, 13, 3, 22, 14, 23, 26, 2, 16, 0, 2, 0, 21, 34, 13, 3, 22, 14, 23, 27, 2, 16, 0, 2, 0, 21, 35, 13, 3, 22, 14, 23, 28, 2, 16, 0, 2, 0, 21, 36, 13, 3, 22, 14, 23, 29, 2, 16, 0, 2, 0, 21, 37, 13, 3, 22, 14, 23, 30, 2, 16, 0, 2, 0, 21, 38, 13, 3, 22, 14, 23, 31, 2, 16, 0, 2, 0, 21, 39, 13, 3, 22, 14, 23, 32, 2, 16, 0, 2, 0, 21, 40, 13, 3, 22, 14, 23, 33, 2, 16, 0, 2, 0, 21, 41, 13, 3, 22, 14, 23, 34, 2, 16, 0, 2, 0, 21, 42, 13, 3, 22, 14, 23, 35, 2, 16, 0, 2, 0, 21, 43, 13, 3, 22, 14, 23, 36, 2, 16, 0, 2, 0, 21, 44, 13, 3, 22, 14, 23, 37, 2, 16, 0, 2, 0, 21, 45, 13, 3, 22, 14, 23, 38, 2, 16, 0, 2, 0, 21, 46, 13, 3, 22, 14, 23, 39, 2, 16, 0, 2, 0, 21, 47, 13, 3, 22, 14, 23, 40, 2, 16, 0, 2, 0, 21, 48, 13, 3, 22, 14, 23, 41, 2, 16, 0, 2, 0, 21, 49, 13, 3, 22, 14, 23, 42, 2, 16, 0, 2, 0, 21, 50, 13, 3, 22, 14, 23, 43, 2, 16, 0, 2, 0, 21, 51, 13, 3, 22, 14, 23, 44, 2, 16, 0, 2, 0, 21, 52, 13, 3, 22, 14, 23, 45, 2, 16, 0, 2, 0, 21, 53, 13, 3, 22, 14, 23, 46, 2, 16, 0, 2, 0, 21, 54, 13, 3, 22, 14, 23, 47, 2, 16, 0, 2, 0, 21, 55, 13, 3, 22, 14, 23, 48, 2, 16, 0, 2, 0, 21, 56, 13, 3, 22, 14, 23, 49, 2, 16, 0, 2, 0, 21, 57, 13, 3, 22, 14, 23, 50, 2, 16, 0, 2, 0, 21, 58, 13, 3, 22, 14, 23, 51, 2, 16, 0, 2, 0, 21, 59, 13, 3, 22, 14, 23, 52, 2, 16, 0, 2, 0, 21, 60, 13, 3, 22, 14, 23, 53, 2, 16, 0, 2, 0, 21, 61, 13, 3, 22, 14, 23, 54, 2, 16, 0, 2, 0, 21, 62, 13, 3, 22, 14, 23, 55, 2, 16, 0, 2, 0, 21, 63, 13, 3, 22, 14, 23, 56, 2, 16, 0, 2, 0, 21, 64, 13, 3, 22, 14, 23, 57, 2, 16, 0, 0, 0, 1, 65, -1, 0, 0, 45, 0, 67, 66, 58, 5, 22, 14, 23, 59, 2, 60, 68, 61, 69, 62, 0, 45, 0, 67, 70, 58, 5, 22, 14, 23, 63, 2, 60, 68, 64, 69, 65, 0, 45, 0, 67, 71, 58, 5, 22, 14, 23, 66, 2, 60, 68, 67, 69, 65, 0, 45, 0, 67, 72, 68, 3, 22, 14, 23, 69, 2, 70, 0, 45, 0, 74, 73, 71, 3, 22, 14, 23, 72, 2, 73, 0, 0, 0, 76, 75, 74, 3, 22, 14, 23, 75, 2, 76, 0, 0, 0, 78, 77, -1, 6, 79, 77, 80, 7, 81, 78, 82, 79, 83, 78, 84, 7, 0, 0, 0, 1, 85, -1, 0, 0, 53, 0, 76, 86, 80, 3, 22, 14, 23, 81, 2, 82, 0, 53, 0, 76, 87, 80, 3, 22, 14, 23, 83, 2, 82, 0, 53, 0, 76, 88, 80, 3, 22, 14, 23, 84, 2, 82, 0, 53, 0, 76, 89, 80, 3, 22, 14, 23, 85, 2, 82, 0, 53, 0, 76, 90, 80, 3, 22, 14, 23, 86, 2, 82, 0, 53, 0, 76, 91, 80, 3, 22, 14, 23, 87, 2, 82, 0, 53, 0, 76, 92, 80, 3, 22, 14, 23, 88, 2, 82, 0, 53, 0, 76, 93, 80, 3, 22, 14, 23, 89, 2, 82, 0, 53, 0, 76, 94, 80, 3, 22, 14, 23, 90, 2, 82, 0, 53, 0, 76, 95, 80, 3, 22, 14, 23, 91, 2, 82, 0, 53, 0, 76, 96, 80, 3, 22, 14, 23, 92, 2, 82, 0, 0, 0, 98, 97, 93, 2, 22, 14, 2, 94, 0, 0, 0, 99, 99, -1, 17, 100, 95, 101, 96, 102, 97, 103, 98, 104, 78, 105, 78, 106, 6, 107, 9, 108, 99, 109, 8, 110, 100, 111, 9, 112, 7, 113, 7, 114, 101, 115, 78, 116, 102, 0 </int_array> <string> "variants" </string> - <array len="105" shared="false"> - <node_path> "" </node_path> + <array len="103" shared="false"> <dictionary shared="false"> <string> "__editor_plugin_screen__" </string> <string> "2D" </string> @@ -166,7 +149,7 @@ <string> "2D" </string> <dictionary shared="false"> <string> "ofs" </string> - <vector2> 328.379, 822.226 </vector2> + <vector2> -70.6559, 735.599 </vector2> <string> "snap_grid" </string> <bool> False </bool> <string> "snap_offset" </string> @@ -186,7 +169,7 @@ <string> "snap_step" </string> <vector2> 10, 10 </vector2> <string> "zoom" </string> - <real> 1.108032 </real> + <real> 0.663419 </real> </dictionary> <string> "3D" </string> <dictionary shared="false"> @@ -280,18 +263,6 @@ <string> "znear" </string> <real> 0.1 </real> </dictionary> - <string> "Script" </string> - <dictionary shared="false"> - <string> "current" </string> - <int> 0 </int> - <string> "sources" </string> - <array len="4" shared="false"> - <string> "res://moving_platform.gd" </string> - <string> "res://enemy.gd" </string> - <string> "res://player.gd" </string> - <string> "res://coin.gd" </string> - </array> - </dictionary> </dictionary> <string> "__editor_run_settings__" </string> <dictionary shared="false"> @@ -301,12 +272,6 @@ <int> 0 </int> </dictionary> </dictionary> - <bool> True </bool> - <real> 1 </real> - <int> 1 </int> - <vector2> 0, 0 </vector2> - <real> 0 </real> - <vector2> 1, 1 </vector2> <int> 0 </int> <resource resource_type="TileSet" path="res://tileset.xml"> </resource> <vector2> 64, 64 </vector2> @@ -314,12 +279,16 @@ <matrix32> 1, 0, 0, 1, 0, 0 </matrix32> <int> 2 </int> <bool> False </bool> + <real> 1 </real> + <real> 0 </real> + <int> 1 </int> <int_array len="2008"> 0, 2, 70, 536870914, 71, 10, 72, 10, 73, 10, 74, 10, 75, 10, 76, 10, 77, 10, 78, 10, 65536, 2, 65606, 536870914, 65607, 10, 65608, 10, 65609, 10, 65610, 10, 65611, 10, 65612, 10, 65613, 10, 65614, 10, 131072, 2, 131142, 536870914, 131143, 10, 131144, 10, 131145, 10, 131146, 10, 131147, 10, 131148, 10, 131149, 10, 131150, 10, 196608, 2, 196626, 9, 196678, 536870914, 196679, 10, 196680, 10, 196681, 10, 196682, 10, 196683, 10, 196684, 10, 196685, 10, 196686, 10, 262144, 2, 262162, 8, 262214, 536870914, 262215, 10, 262216, 10, 262217, 10, 262218, 10, 262219, 10, 262220, 10, 262221, 10, 262222, 10, 327680, 2, 327697, 536870921, 327698, 7, 327733, 9, 327750, 536870914, 327751, 10, 327752, 10, 327753, 10, 327754, 10, 327755, 10, 327756, 10, 327757, 10, 327758, 10, 393216, 2, 393233, 536870920, 393234, 7, 393257, 9, 393269, 7, 393286, 536870914, 393287, 10, 393288, 10, 393289, 10, 393290, 10, 393291, 10, 393292, 10, 393293, 10, 393294, 10, 458752, 2, 458769, 7, 458770, 8, 458790, 9, 458793, 8, 458805, 8, 458822, 536870914, 458823, 10, 458824, 10, 458825, 10, 458826, 10, 458827, 10, 458828, 10, 458829, 10, 458830, 10, 524288, 4, 524289, 1, 524304, 536870913, 524305, 536870918, 524306, 6, 524307, 5, 524308, 1, 524326, 8, 524329, 7, 524341, 7, 524358, 536870914, 524359, 10, 524360, 10, 524361, 10, 524362, 10, 524363, 10, 524364, 10, 524365, 10, 524366, 10, 589824, 10, 589825, 13, 589840, 536870914, 589841, 10, 589842, 10, 589843, 10, 589844, 2, 589862, 7, 589865, 7, 589876, 536870913, 589877, 6, 589878, 1, 589894, 536870914, 589895, 10, 589896, 10, 589897, 10, 589898, 10, 589899, 10, 589900, 10, 589901, 10, 589902, 10, 655360, 2, 655376, 536870914, 655377, 10, 655378, 10, 655379, 10, 655380, 2, 655398, 7, 655401, 8, 655412, 536870925, 655413, 11, 655414, 13, 655430, 536870914, 655431, 10, 655432, 10, 655433, 10, 655434, 10, 655435, 10, 655436, 10, 655437, 10, 655438, 10, 720896, 2, 720912, 536870914, 720913, 10, 720914, 10, 720915, 10, 720916, 2, 720934, 8, 720937, 7, 720958, 536870913, 720959, 5, 720960, 536870917, 720961, 5, 720962, 5, 720963, 536870917, 720964, 5, 720965, 0, 720966, 536870916, 720967, 10, 720968, 10, 720969, 10, 720970, 10, 720971, 10, 720972, 10, 720973, 10, 720974, 10, 786432, 2, 786437, 9, 786448, 536870914, 786449, 10, 786450, 10, 786451, 10, 786452, 2, 786464, 536870913, 786465, 1, 786470, 7, 786473, 7, 786474, 536870924, 786475, 1, 786494, 536870914, 786495, 10, 786496, 10, 786497, 10, 786498, 10, 786499, 10, 786500, 10, 786501, 10, 786502, 10, 786503, 10, 786504, 10, 786505, 10, 786506, 10, 786507, 10, 786508, 10, 786509, 10, 851968, 2, 851973, 7, 851984, 536870914, 851985, 10, 851986, 10, 851987, 10, 851988, 2, 851996, 536870913, 851997, 1, 852000, 536870914, 852001, 3, 852006, 7, 852009, 536870913, 852011, 2, 852030, 536870914, 852031, 10, 852032, 10, 852033, 10, 852034, 10, 852035, 10, 852036, 10, 852037, 10, 852038, 10, 852039, 10, 852040, 10, 852041, 10, 852042, 10, 852043, 10, 852044, 10, 852045, 10, 917504, 2, 917506, 9, 917509, 7, 917512, 536870921, 917520, 536870925, 917521, 11, 917522, 11, 917523, 11, 917524, 13, 917532, 536870925, 917533, 13, 917536, 536870914, 917537, 4, 917538, 1, 917540, 536870913, 917541, 0, 917542, 1, 917545, 536870914, 917546, 10, 917547, 4, 917548, 1, 917566, 536870914, 917567, 10, 917568, 10, 917569, 10, 917570, 10, 917571, 10, 917572, 10, 917573, 10, 917574, 10, 917575, 10, 917576, 10, 917577, 10, 917578, 10, 917579, 10, 917580, 10, 917581, 10, 983040, 2, 983042, 7, 983045, 7, 983048, 536870920, 983050, 536870913, 983051, 0, 983052, 1, 983064, 536870913, 983065, 1, 983072, 536870914, 983073, 10, 983074, 4, 983075, 0, 983076, 536870916, 983077, 10, 983078, 4, 983079, 536870912, 983080, 536870912, 983081, 536870916, 983082, 10, 983083, 10, 983084, 2, 983095, 9, 983102, 536870914, 983103, 10, 983104, 10, 983105, 10, 983106, 10, 983107, 10, 983108, 10, 983109, 10, 983110, 10, 983111, 10, 983112, 10, 983113, 10, 983114, 10, 983115, 10, 983116, 10, 983117, 10, 1048576, 2, 1048578, 8, 1048581, 8, 1048584, 536870919, 1048586, 536870914, 1048587, 536870922, 1048588, 2, 1048600, 536870925, 1048601, 13, 1048604, 9, 1048608, 536870925, 1048609, 536870923, 1048610, 536870923, 1048611, 536870923, 1048612, 10, 1048613, 10, 1048614, 10, 1048615, 10, 1048616, 10, 1048617, 10, 1048618, 10, 1048619, 10, 1048620, 4, 1048621, 1, 1048630, 536870921, 1048631, 8, 1048638, 536870914, 1048639, 10, 1048640, 10, 1048641, 10, 1048642, 10, 1048643, 10, 1048644, 10, 1048645, 10, 1048646, 10, 1048647, 10, 1048648, 10, 1048649, 10, 1048650, 10, 1048651, 10, 1048652, 10, 1048653, 10, 1114112, 4, 1114113, 0, 1114114, 6, 1114115, 0, 1114116, 0, 1114117, 6, 1114118, 1, 1114120, 536870920, 1114122, 536870925, 1114123, 11, 1114124, 13, 1114128, 536870913, 1114129, 5, 1114130, 536870917, 1114131, 5, 1114132, 0, 1114133, 1, 1114140, 7, 1114141, 536870921, 1114148, 536870914, 1114149, 10, 1114150, 10, 1114151, 10, 1114152, 10, 1114153, 10, 1114154, 10, 1114155, 10, 1114156, 10, 1114157, 2, 1114166, 536870920, 1114167, 8, 1114174, 536870914, 1114175, 10, 1114176, 10, 1114177, 10, 1114178, 10, 1114179, 10, 1114180, 10, 1114181, 10, 1114182, 10, 1114183, 10, 1114184, 10, 1114185, 10, 1114186, 10, 1114187, 10, 1114188, 10, 1179648, 10, 1179649, 10, 1179650, 10, 1179651, 10, 1179652, 10, 1179653, 10, 1179654, 2, 1179656, 536870919, 1179663, 536870915, 1179665, 10, 1179666, 10, 1179667, 10, 1179668, 10, 1179669, 4, 1179670, 12, 1179675, 9, 1179676, 8, 1179677, 8, 1179684, 536870914, 1179685, 10, 1179686, 10, 1179687, 10, 1179688, 10, 1179689, 10, 1179690, 10, 1179691, 10, 1179692, 10, 1179693, 4, 1179694, 1, 1179701, 9, 1179702, 536870919, 1179703, 7, 1179710, 536870914, 1179711, 10, 1179712, 10, 1179713, 10, 1179714, 10, 1179715, 10, 1179716, 10, 1179717, 10, 1179718, 10, 1179719, 10, 1179720, 10, 1179721, 10, 1179722, 10, 1245184, 10, 1245185, 10, 1245186, 10, 1245187, 10, 1245188, 10, 1245189, 10, 1245190, 2, 1245192, 536870919, 1245199, 536870913, 1245200, 536870916, 1245201, 10, 1245202, 10, 1245203, 10, 1245204, 10, 1245205, 10, 1245207, 1, 1245211, 7, 1245212, 7, 1245213, 536870920, 1245220, 536870914, 1245221, 10, 1245222, 10, 1245223, 10, 1245224, 10, 1245225, 10, 1245226, 10, 1245227, 10, 1245228, 10, 1245229, 10, 1245230, 2, 1245237, 8, 1245238, 536870919, 1245239, 8, 1245240, 536870921, 1245246, 536870914, 1245247, 10, 1245248, 10, 1245249, 10, 1245250, 10, 1245251, 10, 1245252, 10, 1245253, 10, 1245254, 10, 1245255, 10, 1245256, 10, 1245257, 10, 1245258, 10, 1310720, 10, 1310721, 10, 1310722, 10, 1310723, 10, 1310724, 10, 1310725, 10, 1310726, 2, 1310728, 536870920, 1310730, 536870913, 1310731, 1, 1310734, 536870913, 1310735, 536870916, 1310736, 10, 1310737, 10, 1310738, 10, 1310739, 10, 1310740, 10, 1310741, 10, 1310742, 10, 1310743, 4, 1310744, 1, 1310747, 8, 1310748, 7, 1310749, 536870919, 1310756, 536870914, 1310757, 10, 1310758, 10, 1310759, 10, 1310760, 10, 1310761, 10, 1310762, 10, 1310763, 10, 1310764, 10, 1310765, 10, 1310766, 4, 1310767, 5, 1310768, 12, 1310773, 7, 1310774, 536870919, 1310775, 7, 1310776, 536870919, 1310782, 536870914, 1310783, 10, 1310784, 10, 1310785, 10, 1310786, 10, 1310787, 10, 1310788, 10, 1310789, 10, 1310790, 10, 1310791, 10, 1310792, 10, 1310793, 10, 1376256, 10, 1376257, 10, 1376258, 10, 1376259, 10, 1376260, 10, 1376261, 10, 1376262, 4, 1376263, 0, 1376264, 0, 1376265, 0, 1376266, 536870916, 1376267, 4, 1376268, 0, 1376269, 0, 1376270, 536870916, 1376271, 10, 1376272, 10, 1376273, 10, 1376274, 10, 1376275, 10, 1376276, 10, 1376277, 10, 1376278, 10, 1376279, 10, 1376280, 4, 1376281, 12, 1376283, 8, 1376284, 8, 1376285, 536870920, 1376287, 536870924, 1376288, 0, 1376289, 5, 1376290, 536870917, 1376291, 0, 1376292, 536870916, 1376293, 10, 1376294, 10, 1376295, 10, 1376296, 10, 1376297, 10, 1376298, 10, 1376299, 10, 1376300, 10, 1376301, 10, 1376302, 10, 1376303, 10, 1376305, 12, 1376309, 7, 1376310, 536870920, 1376311, 7, 1376312, 536870920, 1376318, 536870914, 1376319, 10, 1376320, 10, 1376321, 10, 1376322, 10, 1376323, 10, 1376324, 10, 1376325, 10, 1376326, 10, 1376327, 10, 1376328, 10, 1441792, 10, 1441793, 10, 1441794, 10, 1441795, 10, 1441796, 10, 1441797, 10, 1441798, 10, 1441799, 10, 1441800, 10, 1441801, 10, 1441802, 10, 1441803, 10, 1441804, 10, 1441805, 10, 1441806, 10, 1441807, 10, 1441808, 10, 1441809, 10, 1441810, 10, 1441811, 10, 1441812, 10, 1441813, 10, 1441814, 10, 1441815, 10, 1441816, 10, 1441818, 0, 1441819, 6, 1441820, 6, 1441821, 536870918, 1441822, 5, 1441824, 10, 1441825, 10, 1441826, 10, 1441827, 10, 1441828, 10, 1441829, 10, 1441830, 10, 1441831, 10, 1441832, 10, 1441833, 10, 1441834, 10, 1441835, 10, 1441836, 10, 1441837, 10, 1441838, 10, 1441839, 10, 1441840, 10, 1441842, 0, 1441843, 0, 1441844, 0, 1441845, 6, 1441846, 536870918, 1441847, 6, 1441848, 536870918, 1441849, 0, 1441850, 5, 1441851, 536870917, 1441852, 5, 1441853, 0, 1441854, 536870916, 1441855, 10, 1441856, 10, 1441857, 10, 1441858, 10, 1441859, 10, 1441860, 10, 1441861, 10, 1441862, 10, 1441863, 10, 1507328, 10, 1507329, 10, 1507330, 10, 1507331, 10, 1507332, 10, 1507333, 10, 1507334, 10, 1507335, 10, 1507336, 10, 1507337, 10, 1507338, 10, 1507339, 10, 1507340, 10, 1507341, 10, 1507342, 10, 1507343, 10, 1507344, 10, 1507345, 10, 1507346, 10, 1507347, 10, 1507348, 10, 1507349, 10, 1507350, 10, 1507351, 10, 1507352, 10, 1507353, 10, 1507354, 10, 1507355, 10, 1507356, 10, 1507357, 10, 1507358, 10, 1507359, 10, 1507360, 10, 1507361, 10, 1507362, 10, 1507363, 10, 1507364, 10, 1507365, 10, 1507366, 10, 1507367, 10, 1507368, 10, 1507369, 10, 1507370, 10, 1507371, 10, 1507372, 10, 1507373, 10, 1507374, 10, 1507375, 10, 1507376, 10, 1507377, 10, 1507378, 10, 1507379, 10, 1507380, 10, 1507381, 10, 1507382, 10, 1507383, 10, 1507384, 10, 1507385, 10, 1507386, 10, 1507387, 10, 1507388, 10, 1507389, 10, 1507390, 10, 1507391, 10, 1507392, 10, 1507393, 10, 1507394, 10, 1507395, 10, 1507396, 10, 1507397, 10, 1507398, 10, 1507399, 10, 1572864, 10, 1572865, 10, 1572866, 10, 1572867, 10, 1572868, 10, 1572869, 10, 1572870, 10, 1572871, 10, 1572872, 10, 1572873, 10, 1572874, 10, 1572875, 10, 1572876, 10, 1572877, 10, 1572878, 10, 1572879, 10, 1572880, 10, 1572881, 10, 1572882, 10, 1572883, 10, 1572884, 10, 1572885, 10, 1572886, 10, 1572887, 10, 1572888, 10, 1572889, 10, 1572890, 10, 1572891, 10, 1572892, 10, 1572893, 10, 1572894, 10, 1572895, 10, 1572896, 10, 1572897, 10, 1572898, 10, 1572899, 10, 1572900, 10, 1572901, 10, 1572902, 10, 1572903, 10, 1572904, 10, 1572905, 10, 1572906, 10, 1572907, 10, 1572908, 10, 1572909, 10, 1572910, 10, 1572911, 10, 1572912, 10, 1572913, 10, 1572914, 10, 1572915, 10, 1572916, 10, 1572917, 10, 1572918, 10, 1572919, 10, 1572920, 10, 1572921, 10, 1572922, 10, 1572923, 10, 1572924, 10, 1572925, 10, 1572926, 10, 1572927, 10, 1572928, 10, 1572929, 10, 1572930, 10, 1572931, 10, 1572932, 10, 1572933, 10, 1572934, 10, 1572935, 10, 1638400, 10, 1638401, 10, 1638402, 10, 1638403, 10, 1638404, 10, 1638405, 10, 1638406, 10, 1638407, 10, 1638408, 10, 1638409, 10, 1638410, 10, 1638411, 10, 1638412, 10, 1638413, 10, 1638414, 10, 1638415, 10, 1638416, 10, 1638417, 10, 1638418, 10, 1638419, 10, 1638420, 10, 1638421, 10, 1638422, 10, 1638423, 10, 1638424, 10, 1638425, 10, 1638426, 10, 1638427, 10, 1638428, 10, 1638429, 10, 1638430, 10, 1638431, 10, 1638432, 10, 1638433, 10, 1638434, 10, 1638435, 10, 1638436, 10, 1638437, 10, 1638438, 10, 1638439, 10, 1638440, 10, 1638441, 10, 1638442, 10, 1638443, 10, 1638444, 10, 1638445, 10, 1638446, 10, 1638447, 10, 1638448, 10, 1638449, 10, 1638450, 10, 1638451, 10, 1638452, 10, 1638453, 10, 1638454, 10, 1638455, 10, 1638456, 10, 1638457, 10, 1638458, 10, 1638459, 10, 1638460, 10, 1638461, 10, 1638462, 10, 1638463, 10, 1638464, 10, 1638465, 10, 1638466, 10, 1638467, 10, 1638468, 10, 1638469, 10, 1638470, 10, 1638471, 10, 1703952, 10, 1703953, 10, 1703954, 10, 1703955, 10, 1703956, 10, 1703957, 10, 1703958, 10, 1703959, 10, 1703960, 10, 1703961, 10, 1703962, 10, 1703963, 10, 1703964, 10, 1703965, 10, 1703966, 10, 1703967, 10, 1703968, 10, 1703969, 10, 1703970, 10, 1703971, 10, 1703972, 10, 1703973, 10, 1703974, 10, 1703975, 10, 1703976, 10, 1703977, 10, 1703978, 10, 1703979, 10, 1703980, 10, 1703981, 10, 1703982, 10, 1703983, 10, 1703984, 10, 1703985, 10, 1703986, 10, 1703987, 10, 1703988, 10, 1703989, 10, 1703990, 10, 1703991, 10, 1703992, 10, 1703993, 10, 1703994, 10, 1703995, 10, 1703996, 10, 1703997, 10, 1703998, 10, 1703999, 10, 1704000, 10, 1704001, 10, 1704002, 10, 1704003, 10, 1704004, 10, 1704005, 10, 1704006, 10, 1704007, 10, 1769488, 10, 1769489, 10, 1769490, 10, 1769491, 10, 1769492, 10, 1769493, 10, 1769494, 10, 1769495, 10, 1769496, 10, 1769497, 10, 1769498, 10, 1769499, 10, 1769500, 10, 1769501, 10, 1769502, 10, 1769503, 10, 1769504, 10, 1769505, 10, 1769506, 10, 1769507, 10, 1769508, 10, 1769509, 10, 1769510, 10, 1769511, 10, 1769512, 10, 1769513, 10, 1769514, 10, 1769515, 10, 1769516, 10, 1769517, 10, 1769518, 10, 1769519, 10, 1769520, 10, 1769521, 10, 1769522, 10, 1769523, 10, 1769524, 10, 1769525, 10, 1769526, 10, 1769527, 10, 1769528, 10, 1769529, 10, 1769530, 10, 1769531, 10, 1769532, 10, 1769533, 10, 1769534, 10, 1769535, 10, 1769536, 10, 1769537, 10, 1769538, 10, 1769539, 10, 1769540, 10, 1769541, 10 </int_array> <dictionary shared="false"> <string> "_edit_lock_" </string> <bool> True </bool> </dictionary> <resource resource_type="PackedScene" path="res://coin.xml"> </resource> + <node_path> "" </node_path> <vector2> 672, 1179 </vector2> <dictionary shared="false"> <string> "__editor_plugin_screen__" </string> @@ -957,6 +926,7 @@ </dictionary> </dictionary> <resource resource_type="AudioStream" path="res://music.ogg"> </resource> + <bool> True </bool> <real> 2 </real> <resource resource_type="PackedScene" path="res://enemy.xml"> </resource> <vector2> 834.664, 1309.6 </vector2> diff --git a/drivers/chibi/event_stream_chibi.cpp b/drivers/chibi/event_stream_chibi.cpp index e87e0a9aaa..ecb5c3f22b 100644 --- a/drivers/chibi/event_stream_chibi.cpp +++ b/drivers/chibi/event_stream_chibi.cpp @@ -779,8 +779,10 @@ EventStreamChibi::EventStreamChibi() { -RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderChibi::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; String el = p_path.extension().to_lower(); CPFileAccessWrapperImpl f; @@ -791,6 +793,8 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina CPLoader_IT loader(&f); CPLoader::Error err = loader.load_song(p_path.utf8().get_data(),&esc->song,false); ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES()); + if (r_error) + *r_error=OK; return esc; @@ -800,6 +804,8 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina CPLoader_XM loader(&f); CPLoader::Error err=loader.load_song(p_path.utf8().get_data(),&esc->song,false); ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES()); + if (r_error) + *r_error=OK; return esc; } else if (el=="s3m") { @@ -808,6 +814,9 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina CPLoader_S3M loader(&f); CPLoader::Error err=loader.load_song(p_path.utf8().get_data(),&esc->song,false); ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES()); + if (r_error) + *r_error=OK; + return esc; } else if (el=="mod") { @@ -816,6 +825,8 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina CPLoader_MOD loader(&f); CPLoader::Error err=loader.load_song(p_path.utf8().get_data(),&esc->song,false); ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES()); + if (r_error) + *r_error=OK; return esc; } diff --git a/drivers/chibi/event_stream_chibi.h b/drivers/chibi/event_stream_chibi.h index 7b2ee4b471..b564c16018 100644 --- a/drivers/chibi/event_stream_chibi.h +++ b/drivers/chibi/event_stream_chibi.h @@ -301,7 +301,7 @@ public: class ResourceFormatLoaderChibi : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/convex_decomp/b2Glue.h b/drivers/convex_decomp/b2Glue.h index db765f7eb9..7ec6d7f181 100644 --- a/drivers/convex_decomp/b2Glue.h +++ b/drivers/convex_decomp/b2Glue.h @@ -20,7 +20,8 @@ #define B2GLUE_H #include "math_2d.h" -#include <limits> +#include <limits.h> + namespace b2ConvexDecomp { typedef real_t float32; diff --git a/drivers/convex_decomp/b2Polygon.cpp b/drivers/convex_decomp/b2Polygon.cpp index 668313967e..775f2adfe2 100644 --- a/drivers/convex_decomp/b2Polygon.cpp +++ b/drivers/convex_decomp/b2Polygon.cpp @@ -21,8 +21,8 @@ #include "b2Triangle.h" #include "b2Polygon.h" -#include <cmath> -#include <climits> +#include <math.h> +#include <limits.h> #include <assert.h> #define b2Assert assert diff --git a/drivers/convex_decomp/b2Polygon.h b/drivers/convex_decomp/b2Polygon.h index 82cdc56804..36af2fd9d0 100644 --- a/drivers/convex_decomp/b2Polygon.h +++ b/drivers/convex_decomp/b2Polygon.h @@ -22,7 +22,7 @@ #include "b2Triangle.h" #include "stdio.h" #include <string.h> -#include <limits> +#include <limits.h> namespace b2ConvexDecomp { static bool B2_POLYGON_REPORT_ERRORS = false; diff --git a/drivers/dds/texture_loader_dds.cpp b/drivers/dds/texture_loader_dds.cpp index 8e6c3b62e6..9b2e401fd9 100644 --- a/drivers/dds/texture_loader_dds.cpp +++ b/drivers/dds/texture_loader_dds.cpp @@ -64,8 +64,10 @@ static const DDSFormatInfo dds_format_info[DDS_MAX]={ }; -RES ResourceFormatDDS::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatDDS::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -73,6 +75,8 @@ RES ResourceFormatDDS::load(const String &p_path,const String& p_original_path) return RES(); FileAccessRef fref(f); + if (r_error) + *r_error=ERR_FILE_CORRUPT; ERR_EXPLAIN("Unable to open DDS texture file: "+p_path); ERR_FAIL_COND_V(err!=OK,RES()); @@ -427,6 +431,10 @@ RES ResourceFormatDDS::load(const String &p_path,const String& p_original_path) Ref<ImageTexture> texture = memnew( ImageTexture ); texture->create_from_image(img); + if (r_error) + *r_error=OK; + + return texture; } diff --git a/drivers/dds/texture_loader_dds.h b/drivers/dds/texture_loader_dds.h index 18a1485073..c8b3610063 100644 --- a/drivers/dds/texture_loader_dds.h +++ b/drivers/dds/texture_loader_dds.h @@ -7,7 +7,7 @@ class ResourceFormatDDS : public ResourceFormatLoader{ public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index d3a5f3b5bc..ebe0c61967 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -11188,6 +11188,12 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo tc0_idx=0; }; +void RasterizerGLES2::restore_framebuffer() { + + glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer); + +} + RasterizerGLES2::~RasterizerGLES2() { memdelete_arr(skinned_buffer); diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index d337ecfb64..f759e84b53 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -1695,6 +1695,8 @@ public: void reload_vram(); virtual bool has_feature(VS::Features p_feature) const; + + virtual void restore_framebuffer(); static RasterizerGLES2* get_singleton(); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 157f2e398b..d57512c936 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -132,18 +132,18 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a SL::BlockNode *bnode=(SL::BlockNode*)p_node; //variables - code+="{"ENDL; + code+="{" ENDL; for(Map<StringName,SL::DataType>::Element *E=bnode->variables.front();E;E=E->next()) { - code+=_mktab(p_level)+_typestr(E->value())+" "+replace_string(E->key())+";"ENDL; + code+=_mktab(p_level)+_typestr(E->value())+" "+replace_string(E->key())+";" ENDL; } for(int i=0;i<bnode->statements.size();i++) { - code+=_mktab(p_level)+dump_node_code(bnode->statements[i],p_level)+";"ENDL; + code+=_mktab(p_level)+dump_node_code(bnode->statements[i],p_level)+";" ENDL; } - code+="}"ENDL; + code+="}" ENDL; } break; case SL::Node::TYPE_VARIABLE: { @@ -489,15 +489,15 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a SL::ControlFlowNode *cfnode=(SL::ControlFlowNode*)p_node; if (cfnode->flow_op==SL::FLOW_OP_IF) { - code+="if ("+dump_node_code(cfnode->statements[0],p_level)+") {"ENDL; + code+="if ("+dump_node_code(cfnode->statements[0],p_level)+") {" ENDL; code+=dump_node_code(cfnode->statements[1],p_level+1); if (cfnode->statements.size()==3) { - code+="} else {"ENDL; + code+="} else {" ENDL; code+=dump_node_code(cfnode->statements[2],p_level+1); } - code+="}"ENDL; + code+="}" ENDL; } else if (cfnode->flow_op==SL::FLOW_OP_RETURN) { @@ -560,7 +560,7 @@ Error ShaderCompilerGLES2::compile_node(SL::ProgramNode *p_program) { ubase=uniforms->size(); for(Map<StringName,SL::Uniform>::Element *E=p_program->uniforms.front();E;E=E->next()) { - String uline="uniform "+_typestr(E->get().type)+" _"+E->key().operator String()+";"ENDL; + String uline="uniform "+_typestr(E->get().type)+" _"+E->key().operator String()+";" ENDL; global_code+=uline; if (uniforms) { @@ -593,10 +593,10 @@ Error ShaderCompilerGLES2::compile_node(SL::ProgramNode *p_program) { header+=_typestr(fnode->arguments[i].type)+" "+replace_string(fnode->arguments[i].name); } - header+=") {"ENDL; + header+=") {" ENDL; String fcode=header; fcode+=dump_node_code(fnode->body,1); - fcode+="}"ENDL; + fcode+="}" ENDL; global_code+=fcode; } @@ -605,7 +605,7 @@ Error ShaderCompilerGLES2::compile_node(SL::ProgramNode *p_program) { StringName varname=E->key(); String newvarname=replace_string(varname); - global_code+="uniform "+_typestr(E->get())+" "+newvarname+";"ENDL; + global_code+="uniform "+_typestr(E->get())+" "+newvarname+";" ENDL; }*/ code=dump_node_code(p_program,0); diff --git a/drivers/mpc/audio_stream_mpc.cpp b/drivers/mpc/audio_stream_mpc.cpp index cd8125c9af..fe6aa05d00 100644 --- a/drivers/mpc/audio_stream_mpc.cpp +++ b/drivers/mpc/audio_stream_mpc.cpp @@ -1,7 +1,7 @@ #include "audio_stream_mpc.h" -Error AudioStreamMPC::_open_file() { +Error AudioStreamPlaybackMPC::_open_file() { if (f) { memdelete(f); @@ -41,7 +41,7 @@ Error AudioStreamMPC::_open_file() { return OK; } -void AudioStreamMPC::_close_file() { +void AudioStreamPlaybackMPC::_close_file() { if (f) { memdelete(f); @@ -52,7 +52,7 @@ void AudioStreamMPC::_close_file() { data_ofs=0; } -int AudioStreamMPC::_read_file(void *p_dst,int p_bytes) { +int AudioStreamPlaybackMPC::_read_file(void *p_dst,int p_bytes) { if (f) return f->get_buffer((uint8_t*)p_dst,p_bytes); @@ -68,7 +68,7 @@ int AudioStreamMPC::_read_file(void *p_dst,int p_bytes) { return p_bytes; } -bool AudioStreamMPC::_seek_file(int p_pos){ +bool AudioStreamPlaybackMPC::_seek_file(int p_pos){ if (p_pos<0 || p_pos>streamlen) return false; @@ -83,7 +83,7 @@ bool AudioStreamMPC::_seek_file(int p_pos){ return true; } -int AudioStreamMPC::_tell_file() const{ +int AudioStreamPlaybackMPC::_tell_file() const{ if (f) return f->get_pos(); @@ -93,13 +93,13 @@ int AudioStreamMPC::_tell_file() const{ } -int AudioStreamMPC::_sizeof_file() const{ +int AudioStreamPlaybackMPC::_sizeof_file() const{ //print_line("sizeof file, get: "+itos(streamlen)); return streamlen; } -bool AudioStreamMPC::_canseek_file() const{ +bool AudioStreamPlaybackMPC::_canseek_file() const{ //print_line("canseek file, get true"); return true; @@ -107,51 +107,46 @@ bool AudioStreamMPC::_canseek_file() const{ ///////////////////// -mpc_int32_t AudioStreamMPC::_mpc_read(mpc_reader *p_reader,void *p_dst, mpc_int32_t p_bytes) { +mpc_int32_t AudioStreamPlaybackMPC::_mpc_read(mpc_reader *p_reader,void *p_dst, mpc_int32_t p_bytes) { - AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data; + AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data; return smpc->_read_file(p_dst,p_bytes); } -mpc_bool_t AudioStreamMPC::_mpc_seek(mpc_reader *p_reader,mpc_int32_t p_offset) { +mpc_bool_t AudioStreamPlaybackMPC::_mpc_seek(mpc_reader *p_reader,mpc_int32_t p_offset) { - AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data; + AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data; return smpc->_seek_file(p_offset); } -mpc_int32_t AudioStreamMPC::_mpc_tell(mpc_reader *p_reader) { +mpc_int32_t AudioStreamPlaybackMPC::_mpc_tell(mpc_reader *p_reader) { - AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data; + AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data; return smpc->_tell_file(); } -mpc_int32_t AudioStreamMPC::_mpc_get_size(mpc_reader *p_reader) { +mpc_int32_t AudioStreamPlaybackMPC::_mpc_get_size(mpc_reader *p_reader) { - AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data; + AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data; return smpc->_sizeof_file(); } -mpc_bool_t AudioStreamMPC::_mpc_canseek(mpc_reader *p_reader) { +mpc_bool_t AudioStreamPlaybackMPC::_mpc_canseek(mpc_reader *p_reader) { - AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data; + AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data; return smpc->_canseek_file(); } -bool AudioStreamMPC::_can_mix() const { - return /*active &&*/ !paused; -} - - -void AudioStreamMPC::update() { +int AudioStreamPlaybackMPC::mix(int16_t* p_bufer,int p_frames) { if (!active || paused) - return; + return 0; - int todo=get_todo(); + int todo=p_frames; while(todo>MPC_DECODER_BUFFER_LENGTH/si.channels) { @@ -162,7 +157,7 @@ void AudioStreamMPC::update() { mpc_status err = mpc_demux_decode(demux, &frame); if (frame.bits!=-1) { - int16_t *dst_buff = get_write_buffer(); + int16_t *dst_buff = p_bufer; #ifdef MPC_FIXED_POINT @@ -185,21 +180,21 @@ void AudioStreamMPC::update() { #endif int frames = frame.samples; - write(frames); + p_bufer+=si.channels*frames; todo-=frames; } else { if (err != MPC_STATUS_OK) { stop(); - ERR_EXPLAIN("Error decoding MPC"); - ERR_FAIL(); + ERR_PRINT("Error decoding MPC"); + break; } else { //finished if (!loop) { stop(); - return; + break; } else { @@ -213,9 +208,11 @@ void AudioStreamMPC::update() { } } } + + return p_frames-todo; } -Error AudioStreamMPC::_reload() { +Error AudioStreamPlaybackMPC::_reload() { ERR_FAIL_COND_V(demux!=NULL, ERR_FILE_ALREADY_IN_USE); @@ -224,30 +221,39 @@ Error AudioStreamMPC::_reload() { demux = mpc_demux_init(&reader); ERR_FAIL_COND_V(!demux,ERR_CANT_CREATE); - mpc_demux_get_info(demux, &si); - _setup(si.channels,si.sample_freq,MPC_DECODER_BUFFER_LENGTH*2/si.channels); return OK; } -void AudioStreamMPC::set_file(const String& p_file) { +void AudioStreamPlaybackMPC::set_file(const String& p_file) { file=p_file; + Error err = _open_file(); + ERR_FAIL_COND(err!=OK); + demux = mpc_demux_init(&reader); + ERR_FAIL_COND(!demux); + mpc_demux_get_info(demux, &si); + stream_min_size=MPC_DECODER_BUFFER_LENGTH*2/si.channels; + stream_rate=si.sample_freq; + stream_channels=si.channels; + + mpc_demux_exit(demux); + demux=NULL; + _close_file(); + } -String AudioStreamMPC::get_file() const { +String AudioStreamPlaybackMPC::get_file() const { return file; } -void AudioStreamMPC::play() { - +void AudioStreamPlaybackMPC::play(float p_offset) { - _THREAD_SAFE_METHOD_ if (active) stop(); @@ -262,9 +268,9 @@ void AudioStreamMPC::play() { } -void AudioStreamMPC::stop() { +void AudioStreamPlaybackMPC::stop() { + - _THREAD_SAFE_METHOD_ if (!active) return; if (demux) { @@ -275,70 +281,58 @@ void AudioStreamMPC::stop() { active=false; } -bool AudioStreamMPC::is_playing() const { +bool AudioStreamPlaybackMPC::is_playing() const { - return active || (get_total() - get_todo() -1 > 0); + return active; } -void AudioStreamMPC::set_paused(bool p_paused) { - paused=p_paused; -} -bool AudioStreamMPC::is_paused(bool p_paused) const { - - return paused; -} - -void AudioStreamMPC::set_loop(bool p_enable) { +void AudioStreamPlaybackMPC::set_loop(bool p_enable) { loop=p_enable; } -bool AudioStreamMPC::has_loop() const { +bool AudioStreamPlaybackMPC::has_loop() const { return loop; } -float AudioStreamMPC::get_length() const { +float AudioStreamPlaybackMPC::get_length() const { return 0; } -String AudioStreamMPC::get_stream_name() const { +String AudioStreamPlaybackMPC::get_stream_name() const { return ""; } -int AudioStreamMPC::get_loop_count() const { +int AudioStreamPlaybackMPC::get_loop_count() const { return 0; } -float AudioStreamMPC::get_pos() const { +float AudioStreamPlaybackMPC::get_pos() const { return 0; } -void AudioStreamMPC::seek_pos(float p_time) { +void AudioStreamPlaybackMPC::seek_pos(float p_time) { } -AudioStream::UpdateMode AudioStreamMPC::get_update_mode() const { - return UPDATE_THREAD; -} +void AudioStreamPlaybackMPC::_bind_methods() { -void AudioStreamMPC::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("set_file","name"),&AudioStreamMPC::set_file); - ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamMPC::get_file); + ObjectTypeDB::bind_method(_MD("set_file","name"),&AudioStreamPlaybackMPC::set_file); + ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamPlaybackMPC::get_file); ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"file",PROPERTY_HINT_FILE,"mpc"), _SCS("set_file"), _SCS("get_file")); } -AudioStreamMPC::AudioStreamMPC() { +AudioStreamPlaybackMPC::AudioStreamPlaybackMPC() { - preload=true; + preload=false; f=NULL; streamlen=0; data_ofs=0; @@ -356,7 +350,7 @@ AudioStreamMPC::AudioStreamMPC() { } -AudioStreamMPC::~AudioStreamMPC() { +AudioStreamPlaybackMPC::~AudioStreamPlaybackMPC() { stop(); @@ -366,8 +360,9 @@ AudioStreamMPC::~AudioStreamMPC() { -RES ResourceFormatLoaderAudioStreamMPC::load(const String &p_path,const String& p_original_path) { - +RES ResourceFormatLoaderAudioStreamMPC::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=OK; //streamed so it will always work.. AudioStreamMPC *mpc_stream = memnew(AudioStreamMPC); mpc_stream->set_file(p_path); return Ref<AudioStreamMPC>(mpc_stream); diff --git a/drivers/mpc/audio_stream_mpc.h b/drivers/mpc/audio_stream_mpc.h index fa949acd00..122d0d0bbb 100644 --- a/drivers/mpc/audio_stream_mpc.h +++ b/drivers/mpc/audio_stream_mpc.h @@ -1,18 +1,17 @@ #ifndef AUDIO_STREAM_MPC_H #define AUDIO_STREAM_MPC_H -#include "scene/resources/audio_stream_resampled.h" +#include "scene/resources/audio_stream.h" #include "os/file_access.h" #include "mpc/mpcdec.h" #include "os/thread_safe.h" #include "io/resource_loader.h" //#include "../libmpcdec/decoder.h" //#include "../libmpcdec/internal.h" -class AudioStreamMPC : public AudioStreamResampled { - OBJ_TYPE( AudioStreamMPC, AudioStreamResampled ); +class AudioStreamPlaybackMPC : public AudioStreamPlayback { - _THREAD_SAFE_CLASS_ + OBJ_TYPE( AudioStreamPlaybackMPC, AudioStreamPlayback ); bool preload; FileAccess *f; @@ -39,7 +38,9 @@ class AudioStreamMPC : public AudioStreamResampled { static mpc_int32_t _mpc_get_size(mpc_reader *p_reader); static mpc_bool_t _mpc_canseek(mpc_reader *p_reader); - virtual bool _can_mix() const ; + int stream_min_size; + int stream_rate; + int stream_channels; protected: Error _open_file(); @@ -59,12 +60,10 @@ public: void set_file(const String& p_file); String get_file() const; - virtual void play(); + virtual void play(float p_offset=0); virtual void stop(); virtual bool is_playing() const; - virtual void set_paused(bool p_paused); - virtual bool is_paused(bool p_paused) const; virtual void set_loop(bool p_enable); virtual bool has_loop() const; @@ -78,17 +77,39 @@ public: virtual float get_pos() const; virtual void seek_pos(float p_time); - virtual UpdateMode get_update_mode() const; - virtual void update(); + virtual int get_channels() const { return stream_channels; } + virtual int get_mix_rate() const { return stream_rate; } - AudioStreamMPC(); - ~AudioStreamMPC(); + virtual int get_minimum_buffer_size() const { return stream_min_size; } + virtual int mix(int16_t* p_bufer,int p_frames); + + virtual void set_loop_restart_time(float p_time) { } + + AudioStreamPlaybackMPC(); + ~AudioStreamPlaybackMPC(); }; +class AudioStreamMPC : public AudioStream { + + OBJ_TYPE( AudioStreamMPC, AudioStream ); + + String file; +public: + + Ref<AudioStreamPlayback> instance_playback() { + Ref<AudioStreamPlaybackMPC> pb = memnew( AudioStreamPlaybackMPC ); + pb->set_file(file); + return pb; + } + + void set_file(const String& p_file) { file=p_file; } + + +}; class ResourceFormatLoaderAudioStreamMPC : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/pvr/texture_loader_pvr.cpp b/drivers/pvr/texture_loader_pvr.cpp index 5268b953f4..eb67dad8cf 100644 --- a/drivers/pvr/texture_loader_pvr.cpp +++ b/drivers/pvr/texture_loader_pvr.cpp @@ -22,8 +22,10 @@ enum PVRFLags { -RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path,Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -34,6 +36,8 @@ RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path) ERR_FAIL_COND_V(err,RES()); + if (r_error) + *r_error=ERR_FILE_CORRUPT; uint32_t hsize = f->get_32(); @@ -135,6 +139,9 @@ RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path) Ref<ImageTexture> texture = memnew( ImageTexture ); texture->create_from_image(image,tex_flags); + if (r_error) + *r_error=OK; + return texture; } diff --git a/drivers/pvr/texture_loader_pvr.h b/drivers/pvr/texture_loader_pvr.h index ad86660aa1..735cb2b48b 100644 --- a/drivers/pvr/texture_loader_pvr.h +++ b/drivers/pvr/texture_loader_pvr.h @@ -9,7 +9,7 @@ class ResourceFormatPVR : public ResourceFormatLoader{ public: - virtual RES load(const String &p_path,const String& p_original_path); + virtual RES load(const String &p_path,const String& p_original_path,Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/speex/audio_stream_speex.cpp b/drivers/speex/audio_stream_speex.cpp index bcf4c515f8..2440969345 100644 --- a/drivers/speex/audio_stream_speex.cpp +++ b/drivers/speex/audio_stream_speex.cpp @@ -15,14 +15,15 @@ static _FORCE_INLINE_ uint16_t le_short(uint16_t s) } -void AudioStreamSpeex::update() { +int AudioStreamPlaybackSpeex::mix(int16_t* p_buffer,int p_frames) { + + - _THREAD_SAFE_METHOD_; //printf("update, loops %i, read ofs %i\n", (int)loops, read_ofs); //printf("playing %i, paused %i\n", (int)playing, (int)paused); if (!active || !playing || paused || !data.size()) - return; + return 0; /* if (read_ofs >= data.size()) { @@ -35,12 +36,13 @@ void AudioStreamSpeex::update() { }; */ - int todo = get_todo(); + int todo = p_frames; if (todo < page_size) { - return; + return 0; }; - int eos = 0; + int eos = 0; + bool reloaded=false; while (todo > page_size) { @@ -92,7 +94,7 @@ void AudioStreamSpeex::update() { for (int j=0;j!=nframes;j++) { - int16_t* out = get_write_buffer(); + int16_t* out = p_buffer; int ret; /*Decode frame*/ @@ -120,7 +122,7 @@ void AudioStreamSpeex::update() { /*Convert to short and save to output file*/ - for (int i=0;i<frame_size*get_channel_count();i++) { + for (int i=0;i<frame_size*stream_channels;i++) { out[i]=le_short(out[i]); } @@ -149,7 +151,7 @@ void AudioStreamSpeex::update() { } - write(new_frame_size); + p_buffer+=new_frame_size*stream_channels; todo-=new_frame_size; } } @@ -175,6 +177,7 @@ void AudioStreamSpeex::update() { if (loops) { reload(); ++loop_count; + //break; } else { playing=false; unload(); @@ -183,18 +186,22 @@ void AudioStreamSpeex::update() { } }; }; + + return p_frames-todo; }; -void AudioStreamSpeex::unload() { +void AudioStreamPlaybackSpeex::unload() { + - _THREAD_SAFE_METHOD_ if (!active) return; speex_bits_destroy(&bits); if (st) speex_decoder_destroy(st); + + ogg_sync_clear(&oy); active = false; //data.resize(0); st = NULL; @@ -204,7 +211,7 @@ void AudioStreamSpeex::unload() { loop_count = 0; } -void *AudioStreamSpeex::process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers) { +void *AudioStreamPlaybackSpeex::process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers) { void *st; SpeexHeader *header; @@ -276,9 +283,9 @@ void *AudioStreamSpeex::process_header(ogg_packet *op, int *frame_size, int *rat -void AudioStreamSpeex::reload() { +void AudioStreamPlaybackSpeex::reload() { + - _THREAD_SAFE_METHOD_ if (active) unload(); @@ -359,8 +366,10 @@ void AudioStreamSpeex::reload() { }; page_size = nframes * frame_size; + stream_srate=rate; + stream_channels=channels; + stream_minbuff_size=page_size; - _setup(channels, rate,page_size); } else if (packet_count==1) { @@ -374,23 +383,23 @@ void AudioStreamSpeex::reload() { } while (packet_count <= extra_headers); - active = true; + active=true; } -void AudioStreamSpeex::_bind_methods() { +void AudioStreamPlaybackSpeex::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_file","file"),&AudioStreamSpeex::set_file); - ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamSpeex::get_file); + //ObjectTypeDB::bind_method(_MD("set_file","file"),&AudioStreamPlaybackSpeex::set_file); +// ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamPlaybackSpeex::get_file); - ObjectTypeDB::bind_method(_MD("_set_bundled"),&AudioStreamSpeex::_set_bundled); - ObjectTypeDB::bind_method(_MD("_get_bundled"),&AudioStreamSpeex::_get_bundled); + ObjectTypeDB::bind_method(_MD("_set_bundled"),&AudioStreamPlaybackSpeex::_set_bundled); + ObjectTypeDB::bind_method(_MD("_get_bundled"),&AudioStreamPlaybackSpeex::_get_bundled); ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_BUNDLE),_SCS("_set_bundled"),_SCS("_get_bundled")); - ADD_PROPERTY( PropertyInfo(Variant::STRING,"file",PROPERTY_HINT_FILE,"*.spx"),_SCS("set_file"),_SCS("get_file")); + //ADD_PROPERTY( PropertyInfo(Variant::STRING,"file",PROPERTY_HINT_FILE,"*.spx"),_SCS("set_file"),_SCS("get_file")); }; -void AudioStreamSpeex::_set_bundled(const Dictionary& dict) { +void AudioStreamPlaybackSpeex::_set_bundled(const Dictionary& dict) { ERR_FAIL_COND( !dict.has("filename")); ERR_FAIL_COND( !dict.has("data")); @@ -399,7 +408,7 @@ void AudioStreamSpeex::_set_bundled(const Dictionary& dict) { data = dict["data"]; }; -Dictionary AudioStreamSpeex::_get_bundled() const { +Dictionary AudioStreamPlaybackSpeex::_get_bundled() const { Dictionary d; d["filename"] = filename; @@ -408,43 +417,17 @@ Dictionary AudioStreamSpeex::_get_bundled() const { }; -String AudioStreamSpeex::get_file() const { - - return filename; -}; - -void AudioStreamSpeex::set_file(const String& p_file){ - - if (filename == p_file) - return; - - if (active) { - unload(); - } - - if (p_file == "") { - data.resize(0); - return; - }; - - Error err; - FileAccess* file = FileAccess::open(p_file, FileAccess::READ,&err); - if (err != OK) { - data.resize(0); - }; - ERR_FAIL_COND(err != OK); - filename = p_file; - data.resize(file->get_len()); - int read = file->get_buffer(&data[0], data.size()); - memdelete(file); +void AudioStreamPlaybackSpeex::set_data(const Vector<uint8_t>& p_data) { + data=p_data; reload(); } -void AudioStreamSpeex::play() { - _THREAD_SAFE_METHOD_ +void AudioStreamPlaybackSpeex::play(float p_from_pos) { + + reload(); if (!active) @@ -452,85 +435,107 @@ void AudioStreamSpeex::play() { playing = true; } -void AudioStreamSpeex::stop(){ +void AudioStreamPlaybackSpeex::stop(){ + - _THREAD_SAFE_METHOD_ unload(); playing = false; - _clear(); -} -bool AudioStreamSpeex::is_playing() const{ - return _is_ready() && (playing || (get_total() - get_todo() -1 > 0)); } +bool AudioStreamPlaybackSpeex::is_playing() const{ -void AudioStreamSpeex::set_paused(bool p_paused){ - - playing = !p_paused; - paused = p_paused; + return playing; } -bool AudioStreamSpeex::is_paused(bool p_paused) const{ - return paused; -} -void AudioStreamSpeex::set_loop(bool p_enable){ +void AudioStreamPlaybackSpeex::set_loop(bool p_enable){ loops = p_enable; } -bool AudioStreamSpeex::has_loop() const{ +bool AudioStreamPlaybackSpeex::has_loop() const{ return loops; } -float AudioStreamSpeex::get_length() const{ +float AudioStreamPlaybackSpeex::get_length() const{ return 0; } -String AudioStreamSpeex::get_stream_name() const{ +String AudioStreamPlaybackSpeex::get_stream_name() const{ return ""; } -int AudioStreamSpeex::get_loop_count() const{ +int AudioStreamPlaybackSpeex::get_loop_count() const{ return 0; } -float AudioStreamSpeex::get_pos() const{ +float AudioStreamPlaybackSpeex::get_pos() const{ return 0; } -void AudioStreamSpeex::seek_pos(float p_time){ +void AudioStreamPlaybackSpeex::seek_pos(float p_time){ }; -bool AudioStreamSpeex::_can_mix() const { - //return playing; - return data.size() != 0; -}; +AudioStreamPlaybackSpeex::AudioStreamPlaybackSpeex() { -AudioStream::UpdateMode AudioStreamSpeex::get_update_mode() const { + active=false; + st = NULL; + stream_channels=1; + stream_srate=1; + stream_minbuff_size=1; - return UPDATE_THREAD; } -AudioStreamSpeex::AudioStreamSpeex() { +AudioStreamPlaybackSpeex::~AudioStreamPlaybackSpeex() { - active=false; - st = NULL; + unload(); } -AudioStreamSpeex::~AudioStreamSpeex() { - unload(); + + + +//////////////////////////////////////// + + + +void AudioStreamSpeex::set_file(const String& p_file) { + + if (this->file == p_file) + return; + + this->file=p_file; + + if (p_file == "") { + data.resize(0); + return; + }; + + Error err; + FileAccess* file = FileAccess::open(p_file, FileAccess::READ,&err); + if (err != OK) { + data.resize(0); + }; + ERR_FAIL_COND(err != OK); + + this->file = p_file; + data.resize(file->get_len()); + int read = file->get_buffer(&data[0], data.size()); + memdelete(file); + } -RES ResourceFormatLoaderAudioStreamSpeex::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderAudioStreamSpeex::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=OK; AudioStreamSpeex *stream = memnew(AudioStreamSpeex); stream->set_file(p_path); diff --git a/drivers/speex/audio_stream_speex.h b/drivers/speex/audio_stream_speex.h index 9557ebe0b8..570e846734 100644 --- a/drivers/speex/audio_stream_speex.h +++ b/drivers/speex/audio_stream_speex.h @@ -1,7 +1,7 @@ #ifndef AUDIO_STREAM_SPEEX_H #define AUDIO_STREAM_SPEEX_H -#include "scene/resources/audio_stream_resampled.h" +#include "scene/resources/audio_stream.h" #include "speex/speex.h" #include "os/file_access.h" #include "io/resource_loader.h" @@ -14,10 +14,10 @@ #include <ogg/ogg.h> -class AudioStreamSpeex : public AudioStreamResampled { +class AudioStreamPlaybackSpeex : public AudioStreamPlayback { + + OBJ_TYPE(AudioStreamPlaybackSpeex, AudioStreamPlayback); - OBJ_TYPE(AudioStreamSpeex, AudioStreamResampled); - _THREAD_SAFE_CLASS_ void *st; SpeexBits bits; @@ -45,6 +45,9 @@ class AudioStreamSpeex : public AudioStreamResampled { ogg_int64_t page_granule, last_granule; int skip_samples, page_nb_packets; + int stream_channels; + int stream_srate; + int stream_minbuff_size; void* process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers); @@ -52,7 +55,7 @@ class AudioStreamSpeex : public AudioStreamResampled { protected: - virtual bool _can_mix() const; + //virtual bool _can_mix() const; Dictionary _get_bundled() const; void _set_bundled(const Dictionary& dict); @@ -60,16 +63,12 @@ protected: public: - void set_file(const String& p_file); - String get_file() const; + void set_data(const Vector<uint8_t>& p_data); - virtual void play(); + virtual void play(float p_from_pos=0); virtual void stop(); virtual bool is_playing() const; - virtual void set_paused(bool p_paused); - virtual bool is_paused(bool p_paused) const; - virtual void set_loop(bool p_enable); virtual bool has_loop() const; @@ -82,16 +81,42 @@ public: virtual float get_pos() const; virtual void seek_pos(float p_time); - virtual UpdateMode get_update_mode() const; - virtual void update(); + virtual int get_channels() const { return stream_channels; } + virtual int get_mix_rate() const { return stream_srate; } + + virtual int get_minimum_buffer_size() const { return stream_minbuff_size; } + virtual int mix(int16_t* p_bufer,int p_frames); + + virtual void set_loop_restart_time(float p_time) { } //no loop restart, ignore + + AudioStreamPlaybackSpeex(); + ~AudioStreamPlaybackSpeex(); +}; + + + +class AudioStreamSpeex : public AudioStream { + + OBJ_TYPE(AudioStreamSpeex,AudioStream); + + Vector<uint8_t> data; + String file; +public: + + Ref<AudioStreamPlayback> instance_playback() { + Ref<AudioStreamPlaybackSpeex> pb = memnew( AudioStreamPlaybackSpeex ); + pb->set_data(data); + return pb; + } + + void set_file(const String& p_file); - AudioStreamSpeex(); - ~AudioStreamSpeex(); }; + class ResourceFormatLoaderAudioStreamSpeex : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/theora/video_stream_theora.h b/drivers/theora/video_stream_theora.h index b408f9db13..12aac731fc 100644 --- a/drivers/theora/video_stream_theora.h +++ b/drivers/theora/video_stream_theora.h @@ -102,7 +102,7 @@ public: class ResourceFormatLoaderVideoStreamTheora : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/cpu_id.cc b/drivers/theoraplayer/src/YUV/libyuv/src/cpu_id.cc index f52bd95551..aac7390b32 100755 --- a/drivers/theoraplayer/src/YUV/libyuv/src/cpu_id.cc +++ b/drivers/theoraplayer/src/YUV/libyuv/src/cpu_id.cc @@ -174,7 +174,7 @@ int cpu_info_ = kCpuInit; // cpu_info is not initialized yet. #if !defined(__native_client__) && !defined(_M_ARM) static LIBYUV_BOOL TestEnv(const char* name) { -#ifndef _WINRT +#if !defined(_WINRT) && !defined(ORBIS_ENABLED) const char* var = getenv(name); if (var) { if (var[0] != '0') { diff --git a/drivers/theoraplayer/video_stream_theoraplayer.cpp b/drivers/theoraplayer/video_stream_theoraplayer.cpp index ef1f5651ab..876cac3425 100644 --- a/drivers/theoraplayer/video_stream_theoraplayer.cpp +++ b/drivers/theoraplayer/video_stream_theoraplayer.cpp @@ -525,7 +525,9 @@ VideoStreamTheoraplayer::VideoStreamTheoraplayer() { }; -RES ResourceFormatLoaderVideoStreamTheoraplayer::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderVideoStreamTheoraplayer::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=OK; VideoStreamTheoraplayer *stream = memnew(VideoStreamTheoraplayer); stream->set_file(p_path); diff --git a/drivers/theoraplayer/video_stream_theoraplayer.h b/drivers/theoraplayer/video_stream_theoraplayer.h index d43c12609f..69cae7c4a2 100644 --- a/drivers/theoraplayer/video_stream_theoraplayer.h +++ b/drivers/theoraplayer/video_stream_theoraplayer.h @@ -54,7 +54,7 @@ public: class ResourceFormatLoaderVideoStreamTheoraplayer : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 76042089ff..8e70ecc932 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -63,7 +63,7 @@ Error FileAccessUnix::_open(const String& p_path, int p_mode_flags) { fclose(f); f=NULL; - String path=fix_path(p_path); + path=fix_path(p_path); //printf("opening %ls, %i\n", path.c_str(), Memory::get_static_mem_usage()); ERR_FAIL_COND_V(f,ERR_ALREADY_IN_USE); @@ -114,6 +114,9 @@ void FileAccessUnix::close() { return; fclose(f); f = NULL; + if (close_notification_func) { + close_notification_func(path,flags); + } if (save_path!="") { //unlink(save_path.utf8().get_data()); @@ -240,6 +243,7 @@ FileAccess * FileAccessUnix::create_libc() { return memnew( FileAccessUnix ); } +CloseNotificationFunc FileAccessUnix::close_notification_func=NULL; FileAccessUnix::FileAccessUnix() { diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 5b0f0e7cb7..6c41a51ec5 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -38,6 +38,10 @@ /** @author Juan Linietsky <reduzio@gmail.com> */ + + +typedef void (*CloseNotificationFunc)(const String& p_file,int p_flags); + class FileAccessUnix : public FileAccess { FILE *f; @@ -45,10 +49,13 @@ class FileAccessUnix : public FileAccess { void check_errors() const; mutable Error last_error; String save_path; + String path; - static FileAccess* create_libc(); + static FileAccess* create_libc(); public: + static CloseNotificationFunc close_notification_func; + 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/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 314e13cee4..96f90e6be1 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -226,8 +226,9 @@ uint64_t OS_Unix::get_unix_time() const { uint64_t OS_Unix::get_system_time_msec() const { struct timeval tv_now; gettimeofday(&tv_now, NULL); - localtime(&tv_now.tv_usec); - uint64_t msec = tv_now.tv_usec/1000; + //localtime(&tv_now.tv_usec); + //localtime((const long *)&tv_now.tv_usec); + uint64_t msec = uint64_t(tv_now.tv_sec)*1000+tv_now.tv_usec/1000; return msec; } diff --git a/drivers/vorbis/audio_stream_ogg_vorbis.cpp b/drivers/vorbis/audio_stream_ogg_vorbis.cpp index 249059e2c1..ca055c8b62 100644 --- a/drivers/vorbis/audio_stream_ogg_vorbis.cpp +++ b/drivers/vorbis/audio_stream_ogg_vorbis.cpp @@ -30,7 +30,7 @@ -size_t AudioStreamOGGVorbis::_ov_read_func(void *p_dst,size_t p_data, size_t p_count, void *_f) { +size_t AudioStreamPlaybackOGGVorbis::_ov_read_func(void *p_dst,size_t p_data, size_t p_count, void *_f) { //printf("read to %p, %i bytes, %i nmemb, %p\n",p_dst,p_data,p_count,_f); FileAccess *fa=(FileAccess*)_f; @@ -46,7 +46,7 @@ size_t AudioStreamOGGVorbis::_ov_read_func(void *p_dst,size_t p_data, size_t p_c return read; } -int AudioStreamOGGVorbis::_ov_seek_func(void *_f,ogg_int64_t offs, int whence) { +int AudioStreamPlaybackOGGVorbis::_ov_seek_func(void *_f,ogg_int64_t offs, int whence) { //printf("seek to %p, offs %i, whence %i\n",_f,(int)offs,whence); @@ -76,7 +76,7 @@ int AudioStreamOGGVorbis::_ov_seek_func(void *_f,ogg_int64_t offs, int whence) { #endif } -int AudioStreamOGGVorbis::_ov_close_func(void *_f) { +int AudioStreamPlaybackOGGVorbis::_ov_close_func(void *_f) { // printf("close %p\n",_f); if (!_f) @@ -86,7 +86,7 @@ int AudioStreamOGGVorbis::_ov_close_func(void *_f) { fa->close(); return 0; } -long AudioStreamOGGVorbis::_ov_tell_func(void *_f) { +long AudioStreamPlaybackOGGVorbis::_ov_tell_func(void *_f) { //printf("close %p\n",_f); @@ -95,38 +95,32 @@ long AudioStreamOGGVorbis::_ov_tell_func(void *_f) { } -bool AudioStreamOGGVorbis::_can_mix() const { - return /*playing &&*/ !paused; -} - - -void AudioStreamOGGVorbis::update() { +int AudioStreamPlaybackOGGVorbis::mix(int16_t* p_bufer,int p_frames) { - _THREAD_SAFE_METHOD_ - - if (!playing && !setting_up) - return; + if (!playing) + return 0; + int total=p_frames; while (true) { - int todo = get_todo(); + int todo = p_frames; - if (todo==0 || todo<MIN_MIX) + if (todo==0 || todo<MIN_MIX) { break; + } //printf("to mix %i - mix me %i bytes\n",to_mix,to_mix*stream_channels*sizeof(int16_t)); #ifdef BIG_ENDIAN_ENABLED - long ret=ov_read(&vf,(char*)get_write_buffer(),todo*stream_channels*sizeof(int16_t), 1, 2, 1, ¤t_section); + long ret=ov_read(&vf,(char*)p_bufer,todo*stream_channels*sizeof(int16_t), 1, 2, 1, ¤t_section); #else - long ret=ov_read(&vf,(char*)get_write_buffer(),todo*stream_channels*sizeof(int16_t), 0, 2, 1, ¤t_section); + long ret=ov_read(&vf,(char*)p_bufer,todo*stream_channels*sizeof(int16_t), 0, 2, 1, ¤t_section); #endif + if (ret<0) { playing = false; - setting_up=false; - ERR_EXPLAIN("Error reading OGG Vorbis File: "+file); ERR_BREAK(ret<0); } else if (ret==0) { // end of song, reload? @@ -138,9 +132,8 @@ void AudioStreamOGGVorbis::update() { if (!has_loop()) { playing=false; - setting_up=false; repeats=1; - return; + break; } f=FileAccess::open(file,FileAccess::READ); @@ -148,11 +141,22 @@ void AudioStreamOGGVorbis::update() { int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks); if (errv!=0) { playing=false; - setting_up=false; - return; // :( + break;; // :( } - frames_mixed=0; + if (loop_restart_time) { + bool ok = ov_time_seek(&vf,loop_restart_time)==0; + if (!ok) { + playing=false; + //ERR_EXPLAIN("loop restart time rejected"); + ERR_PRINT("loop restart time rejected") + } + + frames_mixed=stream_srate*loop_restart_time; + } else { + + frames_mixed=0; + } repeats++; continue; @@ -162,16 +166,19 @@ void AudioStreamOGGVorbis::update() { ret/=sizeof(int16_t); frames_mixed+=ret; - write(ret); + + p_bufer+=ret*stream_channels; + p_frames-=ret; + } -} + return total-p_frames; +} -void AudioStreamOGGVorbis::play() { - _THREAD_SAFE_METHOD_ +void AudioStreamPlaybackOGGVorbis::play(float p_from) { if (playing) stop(); @@ -179,56 +186,46 @@ void AudioStreamOGGVorbis::play() { if (_load_stream()!=OK) return; + frames_mixed=0; - playing=false; - setting_up=true; - update(); - if (!setting_up) - return; - setting_up=false; playing=true; + if (p_from>0) { + seek_pos(p_from); + } } -void AudioStreamOGGVorbis::_close_file() { +void AudioStreamPlaybackOGGVorbis::_close_file() { if (f) { + memdelete(f); f=NULL; } } -void AudioStreamOGGVorbis::stop() { - - _THREAD_SAFE_METHOD_ +bool AudioStreamPlaybackOGGVorbis::is_playing() const { + return playing; +} +void AudioStreamPlaybackOGGVorbis::stop() { _clear_stream(); playing=false; - _clear(); -} - -AudioStreamOGGVorbis::UpdateMode AudioStreamOGGVorbis::get_update_mode() const { - - return UPDATE_THREAD; + //_clear(); } -bool AudioStreamOGGVorbis::is_playing() const { +float AudioStreamPlaybackOGGVorbis::get_pos() const { - return playing || (get_total() - get_todo() -1 > 0); -} - -float AudioStreamOGGVorbis::get_pos() const { - - int32_t frames = int32_t(frames_mixed) - (int32_t(get_total()) - get_todo()); + int32_t frames = int32_t(frames_mixed); if (frames < 0) frames=0; return double(frames) / stream_srate; } -void AudioStreamOGGVorbis::seek_pos(float p_time) { +void AudioStreamPlaybackOGGVorbis::seek_pos(float p_time) { + - _THREAD_SAFE_METHOD_ if (!playing) return; @@ -237,85 +234,107 @@ void AudioStreamOGGVorbis::seek_pos(float p_time) { frames_mixed=stream_srate*p_time; } -String AudioStreamOGGVorbis::get_stream_name() const { +String AudioStreamPlaybackOGGVorbis::get_stream_name() const { return ""; } -void AudioStreamOGGVorbis::set_loop(bool p_enable) { +void AudioStreamPlaybackOGGVorbis::set_loop(bool p_enable) { loops=p_enable; } -bool AudioStreamOGGVorbis::has_loop() const { +bool AudioStreamPlaybackOGGVorbis::has_loop() const { return loops; } -int AudioStreamOGGVorbis::get_loop_count() const { +int AudioStreamPlaybackOGGVorbis::get_loop_count() const { return repeats; } -void AudioStreamOGGVorbis::set_file(const String& p_file) { +Error AudioStreamPlaybackOGGVorbis::set_file(const String& p_file) { file=p_file; -} - -Error AudioStreamOGGVorbis::_load_stream() { - - _clear_stream(); - if (file=="") - return ERR_INVALID_DATA; - + stream_valid=false; Error err; f=FileAccess::open(file,FileAccess::READ,&err); - if (err) { ERR_FAIL_COND_V( err, err ); } int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks); + switch(errv) { - + case OV_EREAD: { // - A read from media returned an error. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_CANT_READ ); + } break; + case OV_EVERSION: // - Vorbis version mismatch. + case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_UNRECOGNIZED ); + } break; + case OV_EBADHEADER: { // - Invalid Vorbis bitstream header. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_FILE_CORRUPT ); + } break; + case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption. + memdelete(f); f=NULL; + ERR_FAIL_V( ERR_BUG ); + } break; + } const vorbis_info *vinfo=ov_info(&vf,-1); stream_channels=vinfo->channels; stream_srate=vinfo->rate; - Error serr = _setup(stream_channels,stream_srate); + ogg_int64_t len = ov_time_total(&vf,-1); + length=len/1000.0; + ov_clear(&vf); + memdelete(f); + f=NULL; + stream_valid=true; + + + return OK; +} + +Error AudioStreamPlaybackOGGVorbis::_load_stream() { + + ERR_FAIL_COND_V(!stream_valid,ERR_UNCONFIGURED); - if (serr) { - _close_file(); - ERR_FAIL_V( ERR_INVALID_DATA ); + _clear_stream(); + if (file=="") + return ERR_INVALID_DATA; + + Error err; + f=FileAccess::open(file,FileAccess::READ,&err); + if (err) { + ERR_FAIL_COND_V( err, err ); } + int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks); switch(errv) { case OV_EREAD: { // - A read from media returned an error. - _close_file(); + memdelete(f); f=NULL; ERR_FAIL_V( ERR_FILE_CANT_READ ); } break; case OV_EVERSION: // - Vorbis version mismatch. case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data. - _close_file(); + memdelete(f); f=NULL; ERR_FAIL_V( ERR_FILE_UNRECOGNIZED ); } break; case OV_EBADHEADER: { // - Invalid Vorbis bitstream header. - _close_file(); + memdelete(f); f=NULL; ERR_FAIL_V( ERR_FILE_CORRUPT ); } break; case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption. - - _close_file(); + memdelete(f); f=NULL; ERR_FAIL_V( ERR_BUG ); } break; } - - - ogg_int64_t len = ov_time_total(&vf,-1); - - length=len/1000.0; - repeats=0; stream_loaded=true; @@ -324,16 +343,16 @@ Error AudioStreamOGGVorbis::_load_stream() { } -float AudioStreamOGGVorbis::get_length() const { +float AudioStreamPlaybackOGGVorbis::get_length() const { if (!stream_loaded) { - if (const_cast<AudioStreamOGGVorbis*>(this)->_load_stream()!=OK) + if (const_cast<AudioStreamPlaybackOGGVorbis*>(this)->_load_stream()!=OK) return 0; } return length; } -void AudioStreamOGGVorbis::_clear_stream() { +void AudioStreamPlaybackOGGVorbis::_clear_stream() { if (!stream_loaded) return; @@ -346,18 +365,18 @@ void AudioStreamOGGVorbis::_clear_stream() { playing=false; } -void AudioStreamOGGVorbis::set_paused(bool p_paused) { +void AudioStreamPlaybackOGGVorbis::set_paused(bool p_paused) { paused=p_paused; } -bool AudioStreamOGGVorbis::is_paused(bool p_paused) const { +bool AudioStreamPlaybackOGGVorbis::is_paused(bool p_paused) const { return paused; } -AudioStreamOGGVorbis::AudioStreamOGGVorbis() { +AudioStreamPlaybackOGGVorbis::AudioStreamPlaybackOGGVorbis() { loops=false; playing=false; @@ -367,17 +386,18 @@ AudioStreamOGGVorbis::AudioStreamOGGVorbis() { _ov_callbacks.tell_func=_ov_tell_func; f = NULL; stream_loaded=false; - repeats=0; - setting_up=false; + stream_valid=false; + repeats=0; paused=true; stream_channels=0; stream_srate=0; current_section=0; length=0; + loop_restart_time=0; } -AudioStreamOGGVorbis::~AudioStreamOGGVorbis() { +AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() { _clear_stream(); @@ -385,7 +405,9 @@ AudioStreamOGGVorbis::~AudioStreamOGGVorbis() { -RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=OK; AudioStreamOGGVorbis *ogg_stream = memnew(AudioStreamOGGVorbis); ogg_stream->set_file(p_path); diff --git a/drivers/vorbis/audio_stream_ogg_vorbis.h b/drivers/vorbis/audio_stream_ogg_vorbis.h index 8a35fc09cb..827d8b0be3 100644 --- a/drivers/vorbis/audio_stream_ogg_vorbis.h +++ b/drivers/vorbis/audio_stream_ogg_vorbis.h @@ -29,17 +29,16 @@ #ifndef AUDIO_STREAM_OGG_VORBIS_H #define AUDIO_STREAM_OGG_VORBIS_H -#include "scene/resources/audio_stream_resampled.h" +#include "scene/resources/audio_stream.h" #include "vorbis/vorbisfile.h" #include "os/file_access.h" #include "io/resource_loader.h" #include "os/thread_safe.h" -class AudioStreamOGGVorbis : public AudioStreamResampled { - OBJ_TYPE(AudioStreamOGGVorbis,AudioStreamResampled); - _THREAD_SAFE_CLASS_ +class AudioStreamPlaybackOGGVorbis : public AudioStreamPlayback { + OBJ_TYPE(AudioStreamPlaybackOGGVorbis,AudioStreamPlayback); enum { MIN_MIX=1024 @@ -54,9 +53,6 @@ class AudioStreamOGGVorbis : public AudioStreamResampled { static int _ov_close_func(void *_f); static long _ov_tell_func(void *_f); - - virtual bool _can_mix() const; - String file; int64_t frames_mixed; @@ -67,7 +63,7 @@ class AudioStreamOGGVorbis : public AudioStreamResampled { int stream_srate; int current_section; - volatile bool setting_up; + bool paused; bool loops; int repeats; @@ -76,17 +72,21 @@ class AudioStreamOGGVorbis : public AudioStreamResampled { void _clear_stream(); void _close_file(); + bool stream_valid; + float loop_restart_time; -public: +public: - void set_file(const String& p_file); + Error set_file(const String& p_file); - virtual void play(); + virtual void play(float p_from=0); virtual void stop(); virtual bool is_playing() const; + virtual void set_loop_restart_time(float p_time) { loop_restart_time=0; } + virtual void set_paused(bool p_paused); virtual bool is_paused(bool p_paused) const; @@ -102,16 +102,37 @@ public: virtual float get_pos() const; virtual void seek_pos(float p_time); - virtual UpdateMode get_update_mode() const; - virtual void update(); + virtual int get_channels() const { return stream_channels; } + virtual int get_mix_rate() const { return stream_srate; } + + virtual int get_minimum_buffer_size() const { return 0; } + virtual int mix(int16_t* p_bufer,int p_frames); + + AudioStreamPlaybackOGGVorbis(); + ~AudioStreamPlaybackOGGVorbis(); +}; + + +class AudioStreamOGGVorbis : public AudioStream { + + OBJ_TYPE(AudioStreamOGGVorbis,AudioStream); + + String file; +public: + + Ref<AudioStreamPlayback> instance_playback() { + Ref<AudioStreamPlaybackOGGVorbis> pb = memnew( AudioStreamPlaybackOGGVorbis ); + pb->set_file(file); + return pb; + } + + void set_file(const String& p_file) { file=p_file; } - AudioStreamOGGVorbis(); - ~AudioStreamOGGVorbis(); }; class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/main/main.cpp b/main/main.cpp index 19ee1c115f..9b7e190e03 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -75,7 +75,7 @@ #include "core/io/file_access_zip.h" #include "translation.h" #include "version.h" - +#include "os/input.h" #include "performance.h" static Globals *globals=NULL; @@ -94,11 +94,15 @@ static FileAccessNetworkClient *file_access_network_client=NULL; static TranslationServer *translation_server = NULL; static OS::VideoMode video_mode; +static bool init_maximized=false; +static bool init_fullscreen=false; +static bool init_use_custom_pos=false; +static Vector2 init_custom_pos; static int video_driver_idx=-1; static int audio_driver_idx=-1; static String locale; -static bool init_maximized=false; + static int init_screen=-1; static String unescape_cmdline(const String& p_str) { @@ -136,8 +140,10 @@ void Main::print_help(const char* p_binary) { } OS::get_singleton()->print(")\n"); - OS::get_singleton()->print("\t-r WIDTHxHEIGHT\t : Request Screen Resolution\n"); + OS::get_singleton()->print("\t-r WIDTHxHEIGHT\t : Request Window Resolution\n"); + OS::get_singleton()->print("\t-p XxY\t : Request Window Position\n"); OS::get_singleton()->print("\t-f\t\t : Request Fullscreen\n"); + OS::get_singleton()->print("\t-mx\t\t Request Maximized\n"); OS::get_singleton()->print("\t-vd DRIVER\t : Video Driver ("); for (int i=0;i<OS::get_singleton()->get_video_driver_count();i++) { @@ -287,6 +293,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas if (vm.find("x")==-1) { // invalid parameter format + OS::get_singleton()->print("Invalid -r argument: %s\n",vm.utf8().get_data()); goto error; @@ -297,6 +304,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas if (w==0 || h==0) { + OS::get_singleton()->print("Invalid -r resolution, x and y must be >0\n"); goto error; } @@ -307,11 +315,43 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas N=I->next()->next(); } else { + OS::get_singleton()->print("Invalid -p argument, needs resolution\n"); goto error; } - + } else if (I->get()=="-p") { // position + + if (I->next()) { + + String vm=I->next()->get(); + + if (vm.find("x")==-1) { // invalid parameter format + + OS::get_singleton()->print("Invalid -p argument: %s\n",vm.utf8().get_data()); + goto error; + + + } + + int x=vm.get_slice("x",0).to_int(); + int y=vm.get_slice("x",1).to_int(); + + init_custom_pos=Point2(x,y); + init_use_custom_pos=true; + + N=I->next()->next(); + } else { + OS::get_singleton()->print("Invalid -r argument, needs position\n"); + goto error; + + + } + + + } else if (I->get()=="-mx") { // video driver + + init_maximized=true; } else if (I->get()=="-vd") { // video driver if (I->next()) { @@ -319,6 +359,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas video_driver=I->next()->get(); N=I->next()->next(); } else { + OS::get_singleton()->print("Invalid -cd argument, needs driver name\n"); goto error; } @@ -329,6 +370,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas locale=I->next()->get(); N=I->next()->next(); } else { + OS::get_singleton()->print("Invalid -lang argument, needs language code\n"); goto error; } @@ -383,7 +425,8 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas } else if (I->get()=="-f") { // fullscreen - video_mode.fullscreen=true; + //video_mode.fullscreen=false; + init_fullscreen=true; } else if (I->get()=="-e" || I->get()=="-editor") { // fonud editor editor=true; @@ -406,7 +449,6 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas } else { game_path=I->next()->get(); //use game_path instead } - N=I->next()->next(); } else { goto error; @@ -487,8 +529,10 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas debug_mode="remote"; debug_host=I->next()->get(); - if (debug_host.find(":")==-1) //wrong host + if (debug_host.find(":")==-1) { //wrong host + OS::get_singleton()->print("Invalid debug host string\n"); goto error; + } N=I->next()->next(); } else { goto error; @@ -732,6 +776,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas if (p_second_phase) return setup2(); + return OK; error: @@ -785,6 +830,14 @@ Error Main::setup2() { OS::get_singleton()->initialize(video_mode,video_driver_idx,audio_driver_idx); + if (init_use_custom_pos) { + OS::get_singleton()->set_window_position(init_custom_pos); + } + if (init_maximized) { + OS::get_singleton()->set_window_maximized(true); + } else if (init_fullscreen) { + OS::get_singleton()->set_window_fullscreen(true); + } register_core_singletons(); @@ -801,17 +854,29 @@ Error Main::setup2() { if (init_maximized) { OS::get_singleton()->set_window_maximized(true); } + MAIN_PRINT("Main: Load Remaps"); + + path_remap->load_remaps(); if (show_logo) { //boot logo! String boot_logo_path=GLOBAL_DEF("application/boot_splash",String()); bool boot_logo_scale=GLOBAL_DEF("application/boot_splash_fullsize",true); Globals::get_singleton()->set_custom_property_info("application/boot_splash",PropertyInfo(Variant::STRING,"application/boot_splash",PROPERTY_HINT_FILE,"*.png")); - + print_line("BOOT SPLASH: "+boot_logo_path); Image boot_logo; - if (boot_logo_path.strip_edges()!="" && FileAccess::exists(boot_logo_path)) { - boot_logo.load(boot_logo_path); + boot_logo_path = boot_logo_path.strip_edges(); + print_line("BOOT SPLASH IS : "+boot_logo_path); + + if (boot_logo_path!=String() /*&& FileAccess::exists(boot_logo_path)*/) { + Error err = boot_logo.load(boot_logo_path); + if (err!=OK) { + print_line("ËRROR LOADING BOOT LOGO SPLASH :"+boot_logo_path); + } else { + print_line("BOOT SPLASH OK!"); + + } } if (!boot_logo.empty()) { @@ -822,7 +887,7 @@ Error Main::setup2() { VisualServer::get_singleton()->set_boot_image(boot_logo, boot_bg,boot_logo_scale); #ifndef TOOLS_ENABLED //no tools, so free the boot logo (no longer needed) - Globals::get_singleton()->set("application/boot_logo",Image()); + // Globals::get_singleton()->set("application/boot_logo",Image()); #endif } else { @@ -847,10 +912,16 @@ Error Main::setup2() { GLOBAL_DEF("application/icon",String()); Globals::get_singleton()->set_custom_property_info("application/icon",PropertyInfo(Variant::STRING,"application/icon",PROPERTY_HINT_FILE,"*.png,*.webp")); + if (bool(GLOBAL_DEF("display/emulate_touchscreen",false))) { + if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) { + //only if no touchscreen ui hint, set emulation + InputDefault *id = Input::get_singleton()->cast_to<InputDefault>(); + if (id) + id->set_emulate_touch(true); + } + } MAIN_PRINT("Main: Load Remaps"); - path_remap->load_remaps(); - MAIN_PRINT("Main: Load Scene Types"); register_scene_types(); diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 7cb9882f3a..0d986e92a2 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -998,6 +998,44 @@ static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_l return false; } + +static bool _guess_identifier_from_assignment_in_function(GDCompletionContext& context,const StringName& p_identifier, const StringName& p_function,GDCompletionIdentifier &r_type) { + + const GDParser::FunctionNode* func=NULL; + for(int i=0;i<context._class->functions.size();i++) { + if (context._class->functions[i]->name==p_function) { + func=context._class->functions[i]; + break; + } + } + + if (!func) + return false; + + for(int i=0;i<func->body->statements.size();i++) { + + + + if (func->body->statements[i]->type==GDParser::BlockNode::TYPE_OPERATOR) { + const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(func->body->statements[i]); + if (op->op==GDParser::OperatorNode::OP_ASSIGN) { + + if (op->arguments.size() && op->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER) { + + const GDParser::IdentifierNode *id = static_cast<const GDParser::IdentifierNode *>(op->arguments[0]); + + if (id->name==p_identifier) { + + return _guess_expression_type(context,op->arguments[1],func->body->statements[i]->line,r_type); + } + } + } + } + } + + return false; +} + static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) { //go to block first @@ -1089,8 +1127,22 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const r_type=_get_type_from_pinfo(context._class->variables[i]._export); return true; } else if (context._class->variables[i].expression) { - return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type); + + bool rtype = _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type); + if (rtype && r_type.type!=Variant::NIL) + return true; + //return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type); } + + //try to guess from assignment in construtor or _ready + if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_ready",r_type)) + return true; + if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_enter_tree",r_type)) + return true; + if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_init",r_type)) + return true; + + return false; } } } diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index f7aaaf7ee5..9c39051b7f 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -170,6 +170,7 @@ void GDParser::_make_completable_call(int p_arg) { completion_line=tokenizer->get_token_line(); completion_argument=p_arg; completion_block=current_block; + completion_found=true; tokenizer->advance(); } @@ -190,6 +191,7 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide completion_function=current_function; completion_line=tokenizer->get_token_line(); completion_block=current_block; + completion_found=true; tokenizer->advance(); if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) { @@ -1414,6 +1416,24 @@ GDParser::Node* GDParser::_parse_and_reduce_expression(Node *p_parent,bool p_sta return expr; } +bool GDParser::_recover_from_completion() { + + if (!completion_found) { + return false; //can't recover if no completion + } + //skip stuff until newline + while(tokenizer->get_token()!=GDTokenizer::TK_NEWLINE && tokenizer->get_token()!=GDTokenizer::TK_EOF && tokenizer->get_token()!=GDTokenizer::TK_ERROR) { + tokenizer->advance(); + } + completion_found=false; + error_set=false; + if(tokenizer->get_token() == GDTokenizer::TK_ERROR){ + error_set = true; + } + + return true; +} + void GDParser::_parse_block(BlockNode *p_block,bool p_static) { int indent_level = tab_level.back()->get(); @@ -1511,8 +1531,14 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { Node *subexpr=NULL; subexpr = _parse_and_reduce_expression(p_block,p_static); - if (!subexpr) + if (!subexpr) { + if (_recover_from_completion()) { + break; + } return; + } + + lv->assign=subexpr; assigned=subexpr; @@ -1543,8 +1569,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { tokenizer->advance(); Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) + if (!condition) { + if (_recover_from_completion()) { + break; + } return; + } ControlFlowNode *cf_if = alloc_node<ControlFlowNode>(); @@ -1598,8 +1628,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { //condition Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) + if (!condition) { + if (_recover_from_completion()) { + break; + } return; + } cf_else->arguments.push_back(condition); cf_else->cf_type=ControlFlowNode::CF_IF; @@ -1660,8 +1694,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { tokenizer->advance(); Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) + if (!condition) { + if (_recover_from_completion()) { + break; + } return; + } ControlFlowNode *cf_while = alloc_node<ControlFlowNode>(); @@ -1706,8 +1744,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { tokenizer->advance(); Node *container = _parse_and_reduce_expression(p_block,p_static); - if (!container) + if (!container) { + if (_recover_from_completion()) { + break; + } return; + } ControlFlowNode *cf_for = alloc_node<ControlFlowNode>(); @@ -1771,8 +1813,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { } else { //expect expression Node *retexpr = _parse_and_reduce_expression(p_block,p_static); - if (!retexpr) + if (!retexpr) { + if (_recover_from_completion()) { + break; + } return; + } cf_return->arguments.push_back(retexpr); p_block->statements.push_back(cf_return); if (!_end_statement()) { @@ -1787,8 +1833,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { tokenizer->advance(); Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) + if (!condition) { + if (_recover_from_completion()) { + break; + } return; + } AssertNode *an = alloc_node<AssertNode>(); an->condition=condition; p_block->statements.push_back(an); @@ -1801,8 +1851,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { default: { Node *expression = _parse_and_reduce_expression(p_block,p_static,false,true); - if (!expression) + if (!expression) { + if (_recover_from_completion()) { + break; + } return; + } p_block->statements.push_back(expression); if (!_end_statement()) { _set_error("Expected end of statement after expression."); @@ -2625,14 +2679,18 @@ void GDParser::_parse_class(ClassNode *p_class) { Node *subexpr=NULL; - subexpr = _parse_and_reduce_expression(p_class,false); - if (!subexpr) + subexpr = _parse_and_reduce_expression(p_class,false,autoexport); + if (!subexpr) { + if (_recover_from_completion()) { + break; + } return; + } member.expression=subexpr; if (autoexport) { - if (subexpr->type==Node::TYPE_ARRAY) { + if (1)/*(subexpr->type==Node::TYPE_ARRAY) { member._export.type=Variant::ARRAY; @@ -2640,7 +2698,7 @@ void GDParser::_parse_class(ClassNode *p_class) { member._export.type=Variant::DICTIONARY; - } else { + } else*/ { if (subexpr->type!=Node::TYPE_CONSTANT) { @@ -2756,8 +2814,12 @@ void GDParser::_parse_class(ClassNode *p_class) { Node *subexpr=NULL; subexpr = _parse_and_reduce_expression(p_class,true,true); - if (!subexpr) + if (!subexpr) { + if (_recover_from_completion()) { + break; + } return; + } if (subexpr->type!=Node::TYPE_CONSTANT) { _set_error("Expected constant expression"); @@ -2852,6 +2914,7 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p completion_class=NULL; completion_function=NULL; completion_block=NULL; + completion_found=false; current_block=NULL; current_class=NULL; current_function=NULL; @@ -2874,6 +2937,7 @@ Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_ju completion_class=NULL; completion_function=NULL; completion_block=NULL; + completion_found=false; current_block=NULL; current_class=NULL; @@ -2917,6 +2981,8 @@ void GDParser::clear() { current_block=NULL; current_class=NULL; + completion_found=false; + current_function=NULL; validating=false; diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index fd8a2576fa..134279b6d8 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -419,10 +419,12 @@ private: BlockNode *completion_block; int completion_line; int completion_argument; + bool completion_found; PropertyInfo current_export; void _set_error(const String& p_error, int p_line=-1, int p_column=-1); + bool _recover_from_completion(); bool _parse_arguments(Node* p_parent, Vector<Node*>& p_args, bool p_static, bool p_can_codecomplete=false); diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 53ae0c8702..99ddc74bb4 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -2710,7 +2710,10 @@ GDScriptLanguage::~GDScriptLanguage() { /*************** RESOURCE ***************/ -RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderGDScript::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; GDScript *script = memnew( GDScript ); @@ -2742,6 +2745,8 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig script->reload(); } + if (r_error) + *r_error=OK; return scriptres; } diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index fe325ff71e..37ef47af6c 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -557,7 +557,7 @@ public: class ResourceFormatLoaderGDScript : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/platform/android/detect.py b/platform/android/detect.py index 76575a1ec6..fce1fe3ed6 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -173,8 +173,7 @@ def configure(env): env.Append(LDPATH=[ld_path]) env.Append(LIBS=['OpenSLES']) # env.Append(LIBS=['c','m','stdc++','log','EGL','GLESv1_CM','GLESv2','OpenSLES','supc++','android']) - if (env["ndk_platform"]!="2.2"): - env.Append(LIBS=['EGL','OpenSLES','android']) + env.Append(LIBS=['EGL','OpenSLES','android']) env.Append(LIBS=['c','m','stdc++','log','GLESv1_CM','GLESv2', 'z']) env["LINKFLAGS"]= string.split(" -g --sysroot="+ld_sysroot+" -Wl,--no-undefined -Wl,-z,noexecstack ") diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index da3a37fb42..ff70d5ae76 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -29,16 +29,16 @@ #include "file_access_android.h" #include "print_string.h" -#ifdef ANDROID_NATIVE_ACTIVITY + AAssetManager *FileAccessAndroid::asset_manager=NULL; -void FileAccessAndroid::make_default() { +/*void FileAccessAndroid::make_default() { create_func=create_android; -} +}*/ FileAccess* FileAccessAndroid::create_android() { @@ -46,7 +46,7 @@ FileAccess* FileAccessAndroid::create_android() { } -Error FileAccessAndroid::open(const String& p_path, int p_mode_flags) { +Error FileAccessAndroid::_open(const String& p_path, int p_mode_flags) { String path=fix_path(p_path).simplify_path(); if (path.begins_with("/")) @@ -55,7 +55,6 @@ Error FileAccessAndroid::open(const String& p_path, int p_mode_flags) { path=path.substr(6,path.length()); - ERR_FAIL_COND_V(p_mode_flags&FileAccess::WRITE,ERR_UNAVAILABLE); //can't write on android.. a=AAssetManager_open(asset_manager,path.utf8().get_data(),AASSET_MODE_STREAMING); if (!a) @@ -184,4 +183,4 @@ FileAccessAndroid::~FileAccessAndroid() { close(); } -#endif + diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index f477920ae9..506c2c023f 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -29,14 +29,13 @@ #ifndef FILE_ACCESS_ANDROID_H #define FILE_ACCESS_ANDROID_H -#ifdef ANDROID_NATIVE_ACTIVITY #include "os/file_access.h" #include <stdio.h> #include <android/asset_manager.h> #include <android/log.h> -#include <android_native_app_glue.h> +//#include <android_native_app_glue.h> class FileAccessAndroid : public FileAccess { @@ -51,7 +50,7 @@ public: static AAssetManager *asset_manager; - virtual Error open(const String& p_path, int p_mode_flags); ///< 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 @@ -71,12 +70,13 @@ public: virtual bool file_exists(const String& p_path); ///< return true if a file exists + virtual uint64_t _get_modified_time(const String& p_file) { return 0; } - static void make_default(); + //static void make_default(); FileAccessAndroid(); ~FileAccessAndroid(); }; #endif // FILE_ACCESS_ANDROID_H -#endif + diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp index 971d4f84ab..be38d806b2 100644 --- a/platform/android/file_access_jandroid.cpp +++ b/platform/android/file_access_jandroid.cpp @@ -62,13 +62,15 @@ Error FileAccessJAndroid::_open(const String& p_path, int p_mode_flags) { JNIEnv *env = ThreadAndroid::get_env(); - //OS::get_singleton()->print("env: %p, io %p, fo: %p\n",env,io,_file_open); jstring js = env->NewStringUTF(path.utf8().get_data()); int res = env->CallIntMethod(io,_file_open,js,p_mode_flags&WRITE?true:false); env->DeleteLocalRef(js); + OS::get_singleton()->print("fopen: '%s' ret %i\n",path.utf8().get_data(),res); + + if (res<=0) return ERR_FILE_CANT_OPEN; id=res; diff --git a/platform/android/java/src/com/android/godot/Godot.java b/platform/android/java/src/com/android/godot/Godot.java index 9b9b1ab2ad..4c5a313576 100644 --- a/platform/android/java/src/com/android/godot/Godot.java +++ b/platform/android/java/src/com/android/godot/Godot.java @@ -357,7 +357,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC Log.d("GODOT"," " + command_line[w]); } }*/ - GodotLib.initialize(this,io.needsReloadHooks(),command_line); + GodotLib.initialize(this,io.needsReloadHooks(),command_line,getAssets()); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); diff --git a/platform/android/java/src/com/android/godot/GodotIO.java b/platform/android/java/src/com/android/godot/GodotIO.java index addceb1528..a7dc0c2f75 100644 --- a/platform/android/java/src/com/android/godot/GodotIO.java +++ b/platform/android/java/src/com/android/godot/GodotIO.java @@ -94,6 +94,7 @@ public class GodotIO { //System.out.printf("file_open: Attempt to Open %s\n",path); + //Log.v("MyApp", "TRYING TO OPEN FILE: " + path); if (write) return -1; @@ -105,7 +106,7 @@ public class GodotIO { } catch (Exception e) { - //System.out.printf("Exception on file_open: %s\n",e); + //System.out.printf("Exception on file_open: %s\n",path); return -1; } @@ -113,7 +114,7 @@ public class GodotIO { ad.len=ad.is.available(); } catch (Exception e) { - System.out.printf("Exception availabling on file_open: %s\n",e); + System.out.printf("Exception availabling on file_open: %s\n",path); return -1; } diff --git a/platform/android/java/src/com/android/godot/GodotLib.java b/platform/android/java/src/com/android/godot/GodotLib.java index 71c31e9f83..f099e0feff 100644 --- a/platform/android/java/src/com/android/godot/GodotLib.java +++ b/platform/android/java/src/com/android/godot/GodotLib.java @@ -44,7 +44,7 @@ public class GodotLib { * @param height the current view height */ - public static native void initialize(Godot p_instance,boolean need_reload_hook,String[] p_cmdline); + public static native void initialize(Godot p_instance,boolean need_reload_hook,String[] p_cmdline,Object p_asset_manager); public static native void resize(int width, int height,boolean reload); public static native void newcontext(); public static native void quit(); diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index 3158254781..d001cface2 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -33,13 +33,14 @@ #include "main/main.h" #include <unistd.h> #include "file_access_jandroid.h" +#include "file_access_android.h" #include "dir_access_jandroid.h" #include "audio_driver_jandroid.h" #include "globals.h" #include "thread_jandroid.h" #include "core/os/keyboard.h" #include "java_class_wrapper.h" - +#include "android/asset_manager_jni.h" static JavaClassWrapper *java_class_wrapper=NULL; static OS_Android *os_android=NULL; @@ -764,7 +765,7 @@ static void _stop_video() { env->CallVoidMethod(godot_io, _stopVideo); } -JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook, jobjectArray p_cmdline) { +JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook, jobjectArray p_cmdline,jobject p_asset_manager) { __android_log_print(ANDROID_LOG_INFO,"godot","**INIT EVENT! - %p\n",env); @@ -820,7 +821,14 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, } ThreadAndroid::make_default(jvm); +#ifdef USE_JAVA_FILE_ACCESS FileAccessJAndroid::setup(gob); +#else + + jobject amgr = env->NewGlobalRef(p_asset_manager); + + FileAccessAndroid::asset_manager=AAssetManager_fromJava(env,amgr); +#endif DirAccessJAndroid::setup(gob); AudioDriverAndroid::setup(gob); } diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h index 57a4cc8651..9410fe7132 100644 --- a/platform/android/java_glue.h +++ b/platform/android/java_glue.h @@ -36,7 +36,7 @@ extern "C" { - JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook, jobjectArray p_cmdline); + JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook, jobjectArray p_cmdline,jobject p_asset_manager); JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_resize(JNIEnv * env, jobject obj, jint width, jint height, jboolean reload); JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_newcontext(JNIEnv * env, jobject obj); JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 612148418b..e2ff128f0d 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -37,6 +37,8 @@ #include "servers/visual/visual_server_wrap_mt.h" #include "main/main.h" +#include "file_access_android.h" + #include "core/globals.h" #ifdef ANDROID_NATIVE_ACTIVITY @@ -89,8 +91,14 @@ void OS_Android::initialize_core() { if (use_apk_expansion) FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES); - else + else { +#ifdef USE_JAVA_FILE_ACCESS FileAccess::make_default<FileAccessBufferedFA<FileAccessJAndroid> >(FileAccess::ACCESS_RESOURCES); +#else + //FileAccess::make_default<FileAccessBufferedFA<FileAccessAndroid> >(FileAccess::ACCESS_RESOURCES); + FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES); +#endif + } FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM); //FileAccessBufferedFA<FileAccessUnix>::make_default(); diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 7a5a55653f..e9b0d00196 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -41,6 +41,9 @@ #include "servers/visual/rasterizer.h" +//#ifdef USE_JAVA_FILE_ACCESS + + #ifdef ANDROID_NATIVE_ACTIVITY #include <android/sensor.h> diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index d495e3b5fc..d755b3dba0 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -34,5 +34,5 @@ obj = env_ios.Object('godot_iphone.cpp') prog = None prog = env_ios.Program('#bin/godot', [obj] + iphone_lib) -action = "dsymutil "+File(prog)[0].path+" -o " + File(prog)[0].path + ".dSYM" +action = "$IPHONEPATH/usr/bin/dsymutil "+File(prog)[0].path+" -o " + File(prog)[0].path + ".dSYM" env.AddPostAction(prog, action) diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index 3c79137171..d5764b2b5c 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -43,6 +43,11 @@ #import <AdSupport/AdSupport.h> #endif +#ifdef MODULE_PARSE_ENABLED +#import <Parse/Parse.h> +#import "FBSDKCoreKit/FBSDKCoreKit.h" +#endif + #define kFilteringFactor 0.1 #define kRenderingFrequency 60 #define kAccelerometerFrequency 100.0 // Hz @@ -139,8 +144,9 @@ static int frame_count = 0; ++frame_count; // this might be necessary before here - for (NSString* key in [[NSBundle mainBundle] infoDictionary]) { - NSObject* value = [[[NSBundle mainBundle] infoDictionary] objectForKey:key]; + NSDictionary* dict = [[NSBundle mainBundle] infoDictionary]; + for (NSString* key in dict) { + NSObject* value = [dict objectForKey:key]; String ukey = String::utf8([key UTF8String]); // we need a NSObject to Variant conversor @@ -341,6 +347,15 @@ static int frame_count = 0; // For 4.2+ support - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { +#ifdef MODULE_PARSE_ENABLED + NSLog(@"Handling application openURL"); + return [[FBSDKApplicationDelegate sharedInstance] application:application + openURL:url + sourceApplication:sourceApplication + annotation:annotation]; +#endif + + #ifdef MODULE_FACEBOOKSCORER_IOS_ENABLED return [[[FacebookScorer sharedInstance] facebook] handleOpenURL:url]; #else @@ -348,6 +363,32 @@ static int frame_count = 0; #endif } +- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { +#ifdef MODULE_PARSE_ENABLED + // Store the deviceToken in the current installation and save it to Parse. + PFInstallation *currentInstallation = [PFInstallation currentInstallation]; + //NSString* token = [[NSString alloc] initWithData:deviceToken encoding:NSUTF8StringEncoding]; + NSLog(@"Device Token : %@ ", deviceToken); + [currentInstallation setDeviceTokenFromData:deviceToken]; + [currentInstallation saveInBackground]; +#endif +} + +- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { +#ifdef MODULE_PARSE_ENABLED + [PFPush handlePush:userInfo]; + NSDictionary *aps = [userInfo objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + + NSLog(@"Push Notification Payload (app active) %@", aps); + [defaults setObject:aps forKey:@"notificationInfo"]; + [defaults synchronize]; + if (application.applicationState == UIApplicationStateInactive) { + [PFAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo]; + } +#endif +} + - (void)dealloc { [window release]; diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index fb57876a83..3864968d94 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -11,7 +11,8 @@ def get_name(): def can_build(): import sys - if sys.platform == 'darwin': + import os + if sys.platform == 'darwin' or os.environ.has_key("OSXCROSS_IOS"): return True return False @@ -28,6 +29,7 @@ def get_opts(): ('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'), ('ios_appirater', 'Enable Appirater', 'no'), ('ios_exceptions', 'Use exceptions when compiling on playbook', 'yes'), + ('ios_triple', 'Triple for ios toolchain', ''), ] def get_flags(): @@ -35,6 +37,7 @@ def get_flags(): return [ ('tools', 'no'), ('webp', 'yes'), + ("theora","no"), ('openssl','builtin'), #use builtin openssl ] @@ -48,9 +51,10 @@ def configure(env): # env['CC'] = '$IPHONEPATH/Developer/usr/bin/gcc' # env['CXX'] = '$IPHONEPATH/Developer/usr/bin/g++' - env['CC'] = '$IPHONEPATH/usr/bin/clang' - env['CXX'] = '$IPHONEPATH/usr/bin/clang++' - env['AR'] = 'ar' + env['CC'] = '$IPHONEPATH/usr/bin/${ios_triple}clang' + env['CXX'] = '$IPHONEPATH/usr/bin/${ios_triple}clang++' + env['AR'] = '$IPHONEPATH/usr/bin/${ios_triple}ar' + env['RANLIB'] = '$IPHONEPATH/usr/bin/${ios_triple}ranlib' import string if (env["bits"]=="64"): @@ -59,7 +63,7 @@ def configure(env): env.Append(CPPFLAGS=['-DNEED_LONG_INT']) env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON']) else: - env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -MMD -MT dependencies -isysroot $IPHONESDK') + env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=5.1.1 -MMD -MT dependencies -isysroot $IPHONESDK') if (env["bits"]=="64"): env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=5.1.1', @@ -80,7 +84,7 @@ def configure(env): '-framework', 'CoreMedia', ]) else: - env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=4.3', + env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=5.1.1', '-isysroot', '$IPHONESDK', '-framework', 'Foundation', '-framework', 'UIKit', diff --git a/platform/iphone/gl_view.h b/platform/iphone/gl_view.h index c58c863510..cda75394db 100755 --- a/platform/iphone/gl_view.h +++ b/platform/iphone/gl_view.h @@ -34,7 +34,7 @@ #import <MediaPlayer/MediaPlayer.h> #import <AVFoundation/AVFoundation.h> -#define USE_CADISPLAYLINK 1 //iOS version 3.1+ is required +#define USE_CADISPLAYLINK 0 //iOS version 3.1+ is required @protocol GLViewDelegate; diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm index 3309fd0820..4d5d1b81e3 100755 --- a/platform/iphone/gl_view.mm +++ b/platform/iphone/gl_view.mm @@ -345,6 +345,8 @@ static void clear_touches() { [self destroyFramebuffer]; [self createFramebuffer]; [self drawView]; + [self drawView]; + } - (BOOL)createFramebuffer diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm index e3ba6bbd73..f689123c81 100644 --- a/platform/iphone/in_app_store.mm +++ b/platform/iphone/in_app_store.mm @@ -28,6 +28,10 @@ /*************************************************************************/ #ifdef STOREKIT_ENABLED +#ifdef MODULE_FUSEBOXX_ENABLED +#import "modules/fuseboxx/ios/FuseSDK.h" +#endif + #include "in_app_store.h" extern "C" { @@ -222,6 +226,11 @@ Error InAppStore::request_product_info(Variant p_params) { else{ [pending_transactions setObject:transaction forKey:transaction.payment.productIdentifier]; } + + #ifdef MODULE_FUSEBOXX_ENABLED + printf("Registering transaction on Fuseboxx!\n"); + [FuseSDK registerInAppPurchase: transaction]; + #endif } break; case SKPaymentTransactionStateFailed: { printf("status transaction failed!\n"); diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub index c1ba0c2283..cd96cf4f31 100644 --- a/platform/javascript/SCsub +++ b/platform/javascript/SCsub @@ -3,7 +3,8 @@ Import('env') javascript_files = [ "os_javascript.cpp", "audio_driver_javascript.cpp", - "javascript_main.cpp" + "javascript_main.cpp", + "audio_server_javascript.cpp" ] #obj = env.SharedObject('godot_javascript.cpp') @@ -16,6 +17,8 @@ javascript_objects=[] for x in javascript_files: javascript_objects.append( env_javascript.Object( x ) ) +env.Append(LINKFLAGS=["-s","EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync']\""]) + prog = None #env_javascript.SharedLibrary("#platform/javascript/libgodot_javascript.so",[javascript_objects]) diff --git a/platform/javascript/audio_server_javascript.cpp b/platform/javascript/audio_server_javascript.cpp new file mode 100644 index 0000000000..fd505b8a8f --- /dev/null +++ b/platform/javascript/audio_server_javascript.cpp @@ -0,0 +1,805 @@ +#include "audio_server_javascript.h" + +#include "emscripten.h" + +AudioMixer *AudioServerJavascript::get_mixer() { + + return NULL; +} + +void AudioServerJavascript::audio_mixer_chunk_callback(int p_frames){ + + +} + + +RID AudioServerJavascript::sample_create(SampleFormat p_format, bool p_stereo, int p_length) { + + Sample *sample = memnew( Sample ); + sample->format=p_format; + sample->stereo=p_stereo; + sample->length=p_length; + sample->loop_begin=0; + sample->loop_end=p_length; + sample->loop_format=SAMPLE_LOOP_NONE; + sample->mix_rate=44100; + sample->index=-1; + + return sample_owner.make_rid(sample); + +} + +void AudioServerJavascript::sample_set_description(RID p_sample, const String& p_description){ + + +} +String AudioServerJavascript::sample_get_description(RID p_sample, const String& p_description) const{ + + return String(); +} + +AudioServerJavascript::SampleFormat AudioServerJavascript::sample_get_format(RID p_sample) const{ + + return SAMPLE_FORMAT_PCM8; +} +bool AudioServerJavascript::sample_is_stereo(RID p_sample) const{ + + const Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND_V(!sample,false); + return sample->stereo; + +} +int AudioServerJavascript::sample_get_length(RID p_sample) const{ + const Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND_V(!sample,0); + return sample->length; +} +const void* AudioServerJavascript::sample_get_data_ptr(RID p_sample) const{ + + return NULL; +} + +void AudioServerJavascript::sample_set_data(RID p_sample, const DVector<uint8_t>& p_buffer){ + + Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND(!sample); + int chans = sample->stereo?2:1; + + Vector<float> buffer; + buffer.resize(sample->length*chans); + DVector<uint8_t>::Read r=p_buffer.read(); + if (sample->format==SAMPLE_FORMAT_PCM8) { + const int8_t*ptr = (const int8_t*)r.ptr(); + for(int i=0;i<sample->length*chans;i++) { + buffer[i]=ptr[i]/128.0; + } + } else if (sample->format==SAMPLE_FORMAT_PCM16){ + const int16_t*ptr = (const int16_t*)r.ptr(); + for(int i=0;i<sample->length*chans;i++) { + buffer[i]=ptr[i]/32768.0; + } + } else { + ERR_EXPLAIN("Unsupported for now"); + ERR_FAIL(); + } + + sample->tmp_data=buffer; + + + +} +const DVector<uint8_t> AudioServerJavascript::sample_get_data(RID p_sample) const{ + + + return DVector<uint8_t>(); +} + +void AudioServerJavascript::sample_set_mix_rate(RID p_sample,int p_rate){ + Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND(!sample); + sample->mix_rate=p_rate; + +} + +int AudioServerJavascript::sample_get_mix_rate(RID p_sample) const{ + const Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND_V(!sample,0); + return sample->mix_rate; +} + + +void AudioServerJavascript::sample_set_loop_format(RID p_sample,SampleLoopFormat p_format){ + + Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND(!sample); + sample->loop_format=p_format; + +} + +AudioServerJavascript::SampleLoopFormat AudioServerJavascript::sample_get_loop_format(RID p_sample) const { + + const Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND_V(!sample,SAMPLE_LOOP_NONE); + return sample->loop_format; +} + +void AudioServerJavascript::sample_set_loop_begin(RID p_sample,int p_pos){ + + Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND(!sample); + sample->loop_begin=p_pos; + +} +int AudioServerJavascript::sample_get_loop_begin(RID p_sample) const{ + + const Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND_V(!sample,0); + return sample->loop_begin; +} + +void AudioServerJavascript::sample_set_loop_end(RID p_sample,int p_pos){ + + Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND(!sample); + sample->loop_end=p_pos; + +} +int AudioServerJavascript::sample_get_loop_end(RID p_sample) const{ + + const Sample *sample = sample_owner.get(p_sample); + ERR_FAIL_COND_V(!sample,0); + return sample->loop_end; +} + + +/* VOICE API */ + +RID AudioServerJavascript::voice_create(){ + + Voice *voice = memnew( Voice ); + + voice->index=voice_base; + voice->volume=1.0; + voice->pan=0.0; + voice->pan_depth=.0; + voice->pan_height=0.0; + voice->chorus=0; + voice->reverb_type=REVERB_SMALL; + voice->reverb=0; + voice->mix_rate=-1; + voice->positional=false; + voice->active=false; + + EM_ASM_( { + _as_voices[$0]=null; + _as_voice_gain[$0]=_as_audioctx.createGain(); + _as_voice_pan[$0]=_as_audioctx.createStereoPanner(); + _as_voice_gain[$0].connect(_as_voice_pan[$0]); + _as_voice_pan[$0].connect(_as_audioctx.destination); + + },voice_base); + + voice_base++; + + return voice_owner.make_rid( voice ); +} + +void AudioServerJavascript::voice_play(RID p_voice, RID p_sample){ + + Voice* voice=voice_owner.get(p_voice); + ERR_FAIL_COND(!voice); + Sample *sample=sample_owner.get(p_sample); + ERR_FAIL_COND(!sample); + + // due to how webaudio works, sample cration is deferred until used + // sorry! WebAudio absolutely sucks + + + if (sample->index==-1) { + //create sample if not created + ERR_FAIL_COND(sample->tmp_data.size()==0); + sample->index=sample_base; + EM_ASM_( { + _as_samples[$0]=_as_audioctx.createBuffer($1,$2,$3); + },sample_base,sample->stereo?2:1,sample->length,sample->mix_rate); + + sample_base++; + int chans = sample->stereo?2:1; + + + for(int i=0;i<chans;i++) { + + + EM_ASM_({ + _as_edited_buffer=_as_samples[$0].getChannelData($1); + },sample->index,i); + + + for(int j=0;j<sample->length;j++) { + + EM_ASM_({ + _as_edited_buffer[$0]=$1; + },j,sample->tmp_data[j*chans+i]); + } + } + + sample->tmp_data.clear(); + } + + + voice->sample_mix_rate=sample->mix_rate; + if (voice->mix_rate==-1) { + voice->mix_rate=voice->sample_mix_rate; + } + + float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0); + int detune = int(freq_diff*1200.0); + + EM_ASM_( { + if (_as_voices[$0]!==null) { + _as_voices[$0].stop(); //stop and byebye + } + _as_voices[$0]=_as_audioctx.createBufferSource(); + _as_voices[$0].connect(_as_voice_gain[$0]); + _as_voices[$0].buffer=_as_samples[$1]; + _as_voices[$0].loopStart.value=$1; + _as_voices[$0].loopEnd.value=$2; + _as_voices[$0].loop.value=$3; + _as_voices[$0].detune.value=$6; + _as_voice_pan[$0].pan.value=$4; + _as_voice_gain[$0].gain.value=$5; + _as_voices[$0].start(); + _as_voices[$0].onended=function() { + _as_voices[$0].disconnect(_as_voice_gain[$0]); + _as_voices[$0]=null; + } + + },voice->index,sample->index,sample->mix_rate*sample->loop_begin,sample->mix_rate*sample->loop_end,sample->loop_format!=SAMPLE_LOOP_NONE,voice->pan,voice->volume*fx_volume_scale,detune); + + voice->active=true; +} + +void AudioServerJavascript::voice_set_volume(RID p_voice, float p_gain){ + + Voice* voice=voice_owner.get(p_voice); + ERR_FAIL_COND(!voice); + + voice->volume=p_gain; + + if (voice->active) { + EM_ASM_( { + + _as_voice_gain[$0].gain.value=$1; + + },voice->index,voice->volume*fx_volume_scale); + } + +} +void AudioServerJavascript::voice_set_pan(RID p_voice, float p_pan, float p_depth,float height){ + + Voice* voice=voice_owner.get(p_voice); + ERR_FAIL_COND(!voice); + + voice->pan=p_pan; + voice->pan_depth=p_depth; + voice->pan_height=height; + + if (voice->active) { + EM_ASM_( { + + _as_voice_pan[$0].pan.value=$1; + + },voice->index,voice->pan); + } +} +void AudioServerJavascript::voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain){ + +} +void AudioServerJavascript::voice_set_chorus(RID p_voice, float p_chorus ){ + +} +void AudioServerJavascript::voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb){ + +} +void AudioServerJavascript::voice_set_mix_rate(RID p_voice, int p_mix_rate){ + + Voice* voice=voice_owner.get(p_voice); + ERR_FAIL_COND(!voice); + + voice->mix_rate=p_mix_rate; + + if (voice->active) { + + float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0); + int detune = int(freq_diff*1200.0); + EM_ASM_( { + + _as_voices[$0].detune.value=$1; + + },voice->index,detune); + } +} +void AudioServerJavascript::voice_set_positional(RID p_voice, bool p_positional){ + +} + +float AudioServerJavascript::voice_get_volume(RID p_voice) const{ + + Voice* voice=voice_owner.get(p_voice); + ERR_FAIL_COND_V(!voice,0); + + return voice->volume; +} +float AudioServerJavascript::voice_get_pan(RID p_voice) const{ + + Voice* voice=voice_owner.get(p_voice); + ERR_FAIL_COND_V(!voice,0); + + return voice->pan; +} +float AudioServerJavascript::voice_get_pan_depth(RID p_voice) const{ + Voice* voice=voice_owner.get(p_voice); + ERR_FAIL_COND_V(!voice,0); + + return voice->pan_depth; +} +float AudioServerJavascript::voice_get_pan_height(RID p_voice) const{ + + Voice* voice=voice_owner.get(p_voice); + ERR_FAIL_COND_V(!voice,0); + + return voice->pan_height; +} +AudioServerJavascript::FilterType AudioServerJavascript::voice_get_filter_type(RID p_voice) const{ + + return FILTER_NONE; +} +float AudioServerJavascript::voice_get_filter_cutoff(RID p_voice) const{ + + return 0; +} +float AudioServerJavascript::voice_get_filter_resonance(RID p_voice) const{ + + return 0; +} +float AudioServerJavascript::voice_get_chorus(RID p_voice) const{ + + return 0; +} +AudioServerJavascript::ReverbRoomType AudioServerJavascript::voice_get_reverb_type(RID p_voice) const{ + + return REVERB_SMALL; +} +float AudioServerJavascript::voice_get_reverb(RID p_voice) const{ + + return 0; +} + +int AudioServerJavascript::voice_get_mix_rate(RID p_voice) const{ + + return 44100; +} + +bool AudioServerJavascript::voice_is_positional(RID p_voice) const{ + + return false; +} + +void AudioServerJavascript::voice_stop(RID p_voice){ + + Voice* voice=voice_owner.get(p_voice); + ERR_FAIL_COND(!voice); + + if (voice->active) { + + EM_ASM_( { + if (_as_voices[$0]!==null) { + _as_voices[$0].stop(); + _as_voices[$0].disconnect(_as_voice_gain[$0]); + _as_voices[$0]=null; + } + },voice->index); + + voice->active=false; + } + + +} +bool AudioServerJavascript::voice_is_active(RID p_voice) const{ + Voice* voice=voice_owner.get(p_voice); + ERR_FAIL_COND_V(!voice,false); + + return voice->active; +} + +/* STREAM API */ + +RID AudioServerJavascript::audio_stream_create(AudioStream *p_stream) { + + + Stream *s = memnew(Stream); + s->audio_stream=p_stream; + s->event_stream=NULL; + s->active=false; + s->E=NULL; + s->volume_scale=1.0; + p_stream->set_mix_rate(webaudio_mix_rate); + + return stream_owner.make_rid(s); +} + +RID AudioServerJavascript::event_stream_create(EventStream *p_stream) { + + + Stream *s = memnew(Stream); + s->audio_stream=NULL; + s->event_stream=p_stream; + s->active=false; + s->E=NULL; + s->volume_scale=1.0; + //p_stream->set_mix_rate(AudioDriverJavascript::get_singleton()->get_mix_rate()); + + return stream_owner.make_rid(s); + + +} + + +void AudioServerJavascript::stream_set_active(RID p_stream, bool p_active) { + + + Stream *s = stream_owner.get(p_stream); + ERR_FAIL_COND(!s); + + if (s->active==p_active) + return; + + s->active=p_active; + if (p_active) + s->E=active_audio_streams.push_back(s); + else { + active_audio_streams.erase(s->E); + s->E=NULL; + } +} + +bool AudioServerJavascript::stream_is_active(RID p_stream) const { + + Stream *s = stream_owner.get(p_stream); + ERR_FAIL_COND_V(!s,false); + return s->active; +} + +void AudioServerJavascript::stream_set_volume_scale(RID p_stream, float p_scale) { + + Stream *s = stream_owner.get(p_stream); + ERR_FAIL_COND(!s); + s->volume_scale=p_scale; + +} + +float AudioServerJavascript::stream_set_volume_scale(RID p_stream) const { + + Stream *s = stream_owner.get(p_stream); + ERR_FAIL_COND_V(!s,0); + return s->volume_scale; + +} + + +/* Audio Physics API */ + +void AudioServerJavascript::free(RID p_id){ + + if (voice_owner.owns(p_id)) { + Voice* voice=voice_owner.get(p_id); + ERR_FAIL_COND(!voice); + + if (voice->active) { + EM_ASM_( { + if (_as_voices[$0]!==null) { + _as_voices[$0].stop(); + _as_voices[$0].disconnect(_as_voice_gain[$0]); + } + },voice->index); + } + + EM_ASM_( { + delete _as_voices[$0]; + _as_voice_gain[$0].disconnect(_as_voice_pan[$0]); + delete _as_voice_gain[$0]; + _as_voice_pan[$0].disconnect(_as_audioctx.destination); + delete _as_voice_pan[$0]; + + },voice->index); + + voice_owner.free(p_id); + memdelete(voice); + + } else if (sample_owner.owns(p_id)) { + + Sample *sample = sample_owner.get(p_id); + ERR_FAIL_COND(!sample); + + EM_ASM_( { + delete _as_samples[$0]; + + },sample->index); + + sample_owner.free(p_id); + memdelete(sample); + + } else if (stream_owner.owns(p_id)) { + + + Stream *s=stream_owner.get(p_id); + + if (s->active) { + stream_set_active(p_id,false); + } + + memdelete(s); + stream_owner.free(p_id); + } +} + +extern "C" { + + +void audio_server_mix_function(int p_frames) { + + //print_line("MIXI! "+itos(p_frames)); + static_cast<AudioServerJavascript*>(AudioServerJavascript::get_singleton())->mix_to_js(p_frames); +} + +} + +void AudioServerJavascript::mix_to_js(int p_frames) { + + + //process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE + int todo=p_frames; + int offset=0; + + while(todo) { + + int tomix=MIN(todo,INTERNAL_BUFFER_SIZE); + driver_process_chunk(tomix); + + + EM_ASM_({ + + var data = HEAPF32.subarray($0/4, $0/4 + $2*2); + + for (var channel = 0; channel < _as_output_buffer.numberOfChannels; channel++) { + var outputData = _as_output_buffer.getChannelData(channel); + // Loop through samples + for (var sample = 0; sample < $2; sample++) { + // make output equal to the same as the input + outputData[sample+$1] = data[sample*2+channel]; + } + } + + },internal_buffer,offset,tomix); + + todo-=tomix; + offset+=tomix; + } +} + +void AudioServerJavascript::init(){ + + //EM_ASM( +// console.log('server is '+audio_server); +// ); + + + //int latency = GLOBAL_DEF("javascript/audio_latency",16384); + + internal_buffer_channels=2; + internal_buffer = memnew_arr(float,INTERNAL_BUFFER_SIZE*internal_buffer_channels); + stream_buffer = memnew_arr(int32_t,INTERNAL_BUFFER_SIZE*4); //max 4 channels + + stream_volume=0.3; + + int buffer_latency=16384; + + EM_ASM_( { + + _as_script_node = _as_audioctx.createScriptProcessor($0, 0, 2); + _as_script_node.connect(_as_audioctx.destination); + console.log(_as_script_node.bufferSize); + + + _as_script_node.onaudioprocess = function(audioProcessingEvent) { + // The output buffer contains the samples that will be modified and played + _as_output_buffer = audioProcessingEvent.outputBuffer; + audio_server_mix_function(_as_output_buffer.getChannelData(0).length); + } + },buffer_latency); + + +} + +void AudioServerJavascript::finish(){ + +} +void AudioServerJavascript::update(){ + + for(List<Stream*>::Element *E=active_audio_streams.front();E;) { //stream might be removed durnig this callback + + List<Stream*>::Element *N=E->next(); + + if (E->get()->audio_stream) + E->get()->audio_stream->update(); + + E=N; + } +} + +/* MISC config */ + +void AudioServerJavascript::lock(){ + +} +void AudioServerJavascript::unlock(){ + +} +int AudioServerJavascript::get_default_channel_count() const{ + + return 1; +} +int AudioServerJavascript::get_default_mix_rate() const{ + + return 44100; +} + +void AudioServerJavascript::set_stream_global_volume_scale(float p_volume){ + + stream_volume_scale=p_volume; +} +void AudioServerJavascript::set_fx_global_volume_scale(float p_volume){ + + fx_volume_scale=p_volume; +} +void AudioServerJavascript::set_event_voice_global_volume_scale(float p_volume){ + +} + +float AudioServerJavascript::get_stream_global_volume_scale() const{ + return 1; +} +float AudioServerJavascript::get_fx_global_volume_scale() const{ + + return 1; +} +float AudioServerJavascript::get_event_voice_global_volume_scale() const{ + + return 1; +} + +uint32_t AudioServerJavascript::read_output_peak() const{ + + return 0; +} + +AudioServerJavascript *AudioServerJavascript::singleton=NULL; + +AudioServer *AudioServerJavascript::get_singleton() { + return singleton; +} + +double AudioServerJavascript::get_mix_time() const{ + + return 0; +} +double AudioServerJavascript::get_output_delay() const { + + return 0; +} + + +void AudioServerJavascript::driver_process_chunk(int p_frames) { + + + + int samples=p_frames*internal_buffer_channels; + + for(int i=0;i<samples;i++) { + internal_buffer[i]=0; + } + + + for(List<Stream*>::Element *E=active_audio_streams.front();E;E=E->next()) { + + ERR_CONTINUE(!E->get()->active); // bug? + + + AudioStream *as=E->get()->audio_stream; + if (!as) + continue; + + int channels=as->get_channel_count(); + if (channels==0) + continue; // does not want mix + if (!as->mix(stream_buffer,p_frames)) + continue; //nothing was mixed!! + + int32_t stream_vol_scale=(stream_volume*stream_volume_scale*E->get()->volume_scale)*(1<<STREAM_SCALE_BITS); + +#define STRSCALE(m_val) ((((m_val>>STREAM_SCALE_BITS)*stream_vol_scale)>>8)/8388608.0) + switch(channels) { + case 1: { + + for(int i=0;i<p_frames;i++) { + + internal_buffer[(i<<1)+0]+=STRSCALE(stream_buffer[i]); + internal_buffer[(i<<1)+1]+=STRSCALE(stream_buffer[i]); + } + } break; + case 2: { + + for(int i=0;i<p_frames*2;i++) { + + internal_buffer[i]+=STRSCALE(stream_buffer[i]); + } + } break; + case 4: { + + for(int i=0;i<p_frames;i++) { + + internal_buffer[(i<<2)+0]+=STRSCALE((stream_buffer[(i<<2)+0]+stream_buffer[(i<<2)+2])>>1); + internal_buffer[(i<<2)+1]+=STRSCALE((stream_buffer[(i<<2)+1]+stream_buffer[(i<<2)+3])>>1); + } + } break; + + + } + +#undef STRSCALE + } +} + + +/*void AudioServerSW::driver_process(int p_frames,int32_t *p_buffer) { + + + _output_delay=p_frames/double(AudioDriverSW::get_singleton()->get_mix_rate()); + //process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE + int todo=p_frames; + while(todo) { + + int tomix=MIN(todo,INTERNAL_BUFFER_SIZE); + driver_process_chunk(tomix,p_buffer); + p_buffer+=tomix; + todo-=tomix; + } + + +}*/ + +AudioServerJavascript::AudioServerJavascript() { + + singleton=this; + sample_base=1; + voice_base=1; + EM_ASM( + _as_samples={}; + _as_voices={}; + _as_voice_pan={}; + _as_voice_gain={}; + + _as_audioctx = new (window.AudioContext || window.webkitAudioContext)(); + + audio_server_mix_function = Module.cwrap('audio_server_mix_function', 'void', ['number']); + ); + + webaudio_mix_rate = EM_ASM_INT_V( + return _as_audioctx.sampleRate; + ); + print_line("WEBAUDIO MIX RATE: "+itos(webaudio_mix_rate)); + event_voice_scale=1.0; + fx_volume_scale=1.0; + stream_volume_scale=1.0; + +} diff --git a/platform/javascript/audio_server_javascript.h b/platform/javascript/audio_server_javascript.h new file mode 100644 index 0000000000..bdab171b45 --- /dev/null +++ b/platform/javascript/audio_server_javascript.h @@ -0,0 +1,198 @@ +#ifndef AUDIO_SERVER_JAVASCRIPT_H +#define AUDIO_SERVER_JAVASCRIPT_H + + +#include "servers/audio_server.h" + +class AudioServerJavascript : public AudioServer { + + OBJ_TYPE(AudioServerJavascript,AudioServer); + + enum { + INTERNAL_BUFFER_SIZE=4096, + STREAM_SCALE_BITS=12 + + }; + + AudioMixer *get_mixer(); + void audio_mixer_chunk_callback(int p_frames); + + struct Sample { + SampleFormat format; + SampleLoopFormat loop_format; + int loop_begin; + int loop_end; + int length; + int index; + int mix_rate; + bool stereo; + + Vector<float> tmp_data; + }; + + mutable RID_Owner<Sample> sample_owner; + int sample_base; + + struct Voice { + int index; + float volume; + float pan; + float pan_depth; + float pan_height; + + float chorus; + ReverbRoomType reverb_type; + float reverb; + + int mix_rate; + int sample_mix_rate; + bool positional; + + bool active; + + }; + + mutable RID_Owner<Voice> voice_owner; + + int voice_base; + + struct Stream { + bool active; + List<Stream*>::Element *E; + AudioStream *audio_stream; + EventStream *event_stream; + float volume_scale; + }; + + List<Stream*> active_audio_streams; + + //List<Stream*> event_streams; + + float * internal_buffer; + int internal_buffer_channels; + int32_t * stream_buffer; + + mutable RID_Owner<Stream> stream_owner; + + float stream_volume; + float stream_volume_scale; + + float event_voice_scale; + float fx_volume_scale; + + + void driver_process_chunk(int p_frames); + + int webaudio_mix_rate; + + + static AudioServerJavascript *singleton; +public: + + void mix_to_js(int p_frames); + /* SAMPLE API */ + + virtual RID sample_create(SampleFormat p_format, bool p_stereo, int p_length); + + virtual void sample_set_description(RID p_sample, const String& p_description); + virtual String sample_get_description(RID p_sample, const String& p_description) const; + + virtual SampleFormat sample_get_format(RID p_sample) const; + virtual bool sample_is_stereo(RID p_sample) const; + virtual int sample_get_length(RID p_sample) const; + virtual const void* sample_get_data_ptr(RID p_sample) const; + + + virtual void sample_set_data(RID p_sample, const DVector<uint8_t>& p_buffer); + virtual const DVector<uint8_t> sample_get_data(RID p_sample) const; + + virtual void sample_set_mix_rate(RID p_sample,int p_rate); + virtual int sample_get_mix_rate(RID p_sample) const; + + virtual void sample_set_loop_format(RID p_sample,SampleLoopFormat p_format); + virtual SampleLoopFormat sample_get_loop_format(RID p_sample) const; + + virtual void sample_set_loop_begin(RID p_sample,int p_pos); + virtual int sample_get_loop_begin(RID p_sample) const; + + virtual void sample_set_loop_end(RID p_sample,int p_pos); + virtual int sample_get_loop_end(RID p_sample) const; + + + /* VOICE API */ + + virtual RID voice_create(); + + virtual void voice_play(RID p_voice, RID p_sample); + + virtual void voice_set_volume(RID p_voice, float p_gain); + virtual void voice_set_pan(RID p_voice, float p_pan, float p_depth=0,float height=0); //pan and depth go from -1 to 1 + virtual void voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain=0); + virtual void voice_set_chorus(RID p_voice, float p_chorus ); + virtual void voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb); + virtual void voice_set_mix_rate(RID p_voice, int p_mix_rate); + virtual void voice_set_positional(RID p_voice, bool p_positional); + + virtual float voice_get_volume(RID p_voice) const; + virtual float voice_get_pan(RID p_voice) const; //pan and depth go from -1 to 1 + virtual float voice_get_pan_depth(RID p_voice) const; //pan and depth go from -1 to 1 + virtual float voice_get_pan_height(RID p_voice) const; //pan and depth go from -1 to 1 + virtual FilterType voice_get_filter_type(RID p_voice) const; + virtual float voice_get_filter_cutoff(RID p_voice) const; + virtual float voice_get_filter_resonance(RID p_voice) const; + virtual float voice_get_chorus(RID p_voice) const; + virtual ReverbRoomType voice_get_reverb_type(RID p_voice) const; + virtual float voice_get_reverb(RID p_voice) const; + + virtual int voice_get_mix_rate(RID p_voice) const; + virtual bool voice_is_positional(RID p_voice) const; + + virtual void voice_stop(RID p_voice); + virtual bool voice_is_active(RID p_voice) const; + + /* STREAM API */ + + virtual RID audio_stream_create(AudioStream *p_stream); + virtual RID event_stream_create(EventStream *p_stream); + + virtual void stream_set_active(RID p_stream, bool p_active); + virtual bool stream_is_active(RID p_stream) const; + + virtual void stream_set_volume_scale(RID p_stream, float p_scale); + virtual float stream_set_volume_scale(RID p_stream) const; + + /* Audio Physics API */ + + virtual void free(RID p_id); + + virtual void init(); + virtual void finish(); + virtual void update(); + + /* MISC config */ + + virtual void lock(); + virtual void unlock(); + virtual int get_default_channel_count() const; + virtual int get_default_mix_rate() const; + + virtual void set_stream_global_volume_scale(float p_volume); + virtual void set_fx_global_volume_scale(float p_volume); + virtual void set_event_voice_global_volume_scale(float p_volume); + + virtual float get_stream_global_volume_scale() const; + virtual float get_fx_global_volume_scale() const; + virtual float get_event_voice_global_volume_scale() const; + + virtual uint32_t read_output_peak() const; + + static AudioServer *get_singleton(); + + virtual double get_mix_time() const; //useful for video -> audio sync + virtual double get_output_delay() const; + + + AudioServerJavascript(); +}; + +#endif // AUDIO_SERVER_JAVASCRIPT_H diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 947a637fb9..104cede3f1 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -30,7 +30,6 @@ def get_flags(): ('theora', 'no'), ('tools', 'no'), ('nedmalloc', 'no'), - ('vorbis', 'no'), ('musepack', 'no'), ('squirrel', 'no'), ('squish', 'no'), diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index b262684a59..c38035e64a 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -144,12 +144,16 @@ static void _fix_html(Vector<uint8_t>& html,const String& name,int max_memory) { str.parse_utf8((const char*)html.ptr(),html.size()); Vector<String> lines=str.split("\n"); for(int i=0;i<lines.size();i++) { - if (lines[i].find("godot.js")!=-1) { - strnew+="<script type=\"text/javascript\" src=\""+name+"_filesystem.js\"></script>\n"; - strnew+="<script async type=\"text/javascript\" src=\""+name+".js\"></script>\n"; - } else if (lines[i].find("var Module")!=-1) { - strnew+=lines[i]; - strnew+="TOTAL_MEMORY:"+itos(max_memory*1024*1024)+","; + + if (lines[i].find("$GODOTTMEM")!=-1) { + + strnew+=lines[i].replace("$GODOTTMEM",itos(max_memory*1024*1024))+"\n"; + } else if (lines[i].find("$GODOTFS")!=-1) { + strnew+=lines[i].replace("$GODOTFS",name+"fs.js")+"\n"; + } else if (lines[i].find("$GODOTMEM")!=-1) { + strnew+=lines[i].replace("$GODOTMEM",name+".mem")+"\n"; + } else if (lines[i].find("$GODOTJS")!=-1) { + strnew+=lines[i].replace("$GODOTJS",name+".js")+"\n"; } else { strnew+=lines[i]+"\n"; } @@ -267,10 +271,10 @@ Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool _fix_html(data,p_path.get_file().basename(),1<<(max_memory+5)); file=p_path.get_file(); } - if (file=="filesystem.js") { + if (file=="godotfs.js") { _fix_files(data,len); - file=p_path.get_file().basename()+"_filesystem.js"; + file=p_path.get_file().basename()+"fs.js"; } if (file=="godot.js") { @@ -278,6 +282,12 @@ Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool file=p_path.get_file().basename()+".js"; } + if (file=="godot.mem") { + + //_fix_godot(data); + file=p_path.get_file().basename()+".mem"; + } + String dst = p_path.get_base_dir().plus_file(file); FileAccess *f=FileAccess::open(dst,FileAccess::WRITE); if (!f) { diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp index 5be6c5b647..fb87dc848e 100644 --- a/platform/javascript/javascript_main.cpp +++ b/platform/javascript/javascript_main.cpp @@ -31,6 +31,9 @@ #include "main/main.h" #include "io/resource_loader.h" #include "os/keyboard.h" +#include "emscripten.h" +#include <string.h> + OS_JavaScript *os=NULL; static void _gfx_init(void *ud,bool gl2,int w, int h,bool fs) { @@ -196,15 +199,39 @@ static void _gfx_idle() { glutPostRedisplay(); } +int start_step=0; + static void _godot_draw(void) { - os->main_loop_iterate(); + if (start_step==1) { + start_step=2; + Main::start(); + os->main_loop_begin(); + } + + if (start_step==2) { + os->main_loop_iterate(); + } + glutSwapBuffers(); } + + +extern "C" { + +void main_after_fs_sync(int value) { + + start_step=1; + printf("FS SYNCHED!\n"); +} + +} + int main(int argc, char *argv[]) { - /* Initialize the window */ + + /* Initialize the window */ printf("let it go!\n"); glutInit(&argc, argv); os = new OS_JavaScript(_gfx_init,NULL,NULL,NULL,NULL); @@ -218,7 +245,7 @@ int main(int argc, char *argv[]) { #endif ResourceLoader::set_abort_on_missing_resources(false); //ease up compatibility - Main::start(); + glutSpecialUpFunc(_glut_skey_up); glutSpecialFunc(_glut_skey_down); @@ -236,10 +263,32 @@ int main(int argc, char *argv[]) { // glutReshapeFunc(gears_reshape); glutDisplayFunc(_godot_draw); //glutSpecialFunc(gears_special); - os->main_loop_begin(); + + + + //mount persistent filesystem + EM_ASM( + FS.mkdir('/userfs'); + FS.mount(IDBFS, {}, '/userfs'); + + + + // sync from persisted state into memory and then + // run the 'test' function + FS.syncfs(true, function (err) { + assert(!err); + console.log("done syncinc!"); + _after_sync_cb = Module.cwrap('main_after_fs_sync', 'void',['number']); + _after_sync_cb(0); + + }); + + ); glutMainLoop(); + + return 0; } diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index a422f77b4b..ae97bf990b 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -37,6 +37,7 @@ #include "main/main.h" #include "core/globals.h" +#include "emscripten.h" int OS_JavaScript::get_video_driver_count() const { @@ -104,21 +105,21 @@ void OS_JavaScript::initialize(const VideoMode& p_desired,int p_video_driver,int visual_server->init(); visual_server->cursor_set_visible(false, 0); - AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton(); + /*AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton(); if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) { ERR_PRINT("Initializing audio failed."); - } + }*/ print_line("Init SM"); - sample_manager = memnew( SampleManagerMallocSW ); - audio_server = memnew( AudioServerSW(sample_manager) ); + //sample_manager = memnew( SampleManagerMallocSW ); + audio_server = memnew( AudioServerJavascript ); print_line("Init Mixer"); - audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false); + //audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false); audio_server->init(); print_line("Init SoundServer"); @@ -270,6 +271,32 @@ bool OS_JavaScript::main_loop_iterate() { if (!main_loop) return false; + + if (time_to_save_sync>=0) { + int64_t newtime = get_ticks_msec(); + int64_t elapsed = newtime - last_sync_time; + last_sync_time=newtime; + + time_to_save_sync-=elapsed; + + print_line("elapsed "+itos(elapsed)+" tts "+itos(time_to_save_sync)); + + if (time_to_save_sync<0) { + //time to sync, for real + // run 'success' + print_line("DOING SYNCH!"); + EM_ASM( + FS.syncfs(function (err) { + assert(!err); + console.log("Synched!"); + //ccall('success', 'v'); + }); + ); + } + + + } + return Main::iteration(); } @@ -562,14 +589,21 @@ String OS_JavaScript::get_locale() const { String OS_JavaScript::get_data_dir() const { - if (get_data_dir_func) - return get_data_dir_func(); - return "/"; + //if (get_data_dir_func) + // return get_data_dir_func(); + return "/userfs"; //return Globals::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir"); }; +void OS_JavaScript::_close_notification_funcs(const String& p_file,int p_flags) { + print_line("close "+p_file+" flags "+itos(p_flags)); + if (p_file.begins_with("/userfs") && p_flags&FileAccess::WRITE) { + static_cast<OS_JavaScript*>(get_singleton())->last_sync_time=OS::get_singleton()->get_ticks_msec(); + static_cast<OS_JavaScript*>(get_singleton())->time_to_save_sync=5000; //five seconds since last save + } +} OS_JavaScript::OS_JavaScript(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func,GetLocaleFunc p_get_locale_func) { @@ -589,6 +623,9 @@ OS_JavaScript::OS_JavaScript(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, Ope open_uri_func=p_open_uri_func; get_data_dir_func=p_get_data_dir_func; get_locale_func=p_get_locale_func; + FileAccessUnix::close_notification_func=_close_notification_funcs; + + time_to_save_sync=-1; } diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 81bb474401..55ac7cdae4 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -38,7 +38,7 @@ #include "servers/audio/audio_server_sw.h" #include "servers/physics_2d/physics_2d_server_sw.h" #include "servers/visual/rasterizer.h" - +#include "audio_server_javascript.h" #include "audio_driver_javascript.h" typedef void (*GFXInitFunc)(void *ud,bool gl2,int w, int h, bool fs); @@ -65,10 +65,13 @@ private: bool use_gl2; + int64_t time_to_save_sync; + int64_t last_sync_time; + Rasterizer *rasterizer; VisualServer *visual_server; - AudioServerSW *audio_server; - SampleManagerMallocSW *sample_manager; + AudioServerJavascript *audio_server; + //SampleManagerMallocSW *sample_manager; SpatialSoundServerSW *spatial_sound_server; SpatialSound2DServerSW *spatial_sound_2d_server; PhysicsServer *physics_server; @@ -84,6 +87,8 @@ private: GetDataDirFunc get_data_dir_func; GetLocaleFunc get_locale_func; + static void _close_notification_funcs(const String& p_file,int p_flags); + public: // functions used by main to initialize/deintialize the OS @@ -106,7 +111,7 @@ public: typedef int64_t ProcessID; - static OS* get_singleton(); + //static OS* get_singleton(); virtual void vprint(const char* p_format, va_list p_list, bool p_stderr=false); virtual void print(const char *p_format, ... ); diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 5703cbc546..4a20ca80c1 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -11,15 +11,17 @@ def get_name(): def can_build(): - if (sys.platform != "darwin"): - return False + if (sys.platform == "darwin" or os.environ.has_key("OSXCROSS_ROOT")): + return True - return True # osx enabled + + return False def get_opts(): return [ ('force_64_bits','Force 64 bits binary','no'), + ('osxcross_sdk','OSXCross SDK version','darwin14'), ] @@ -29,6 +31,7 @@ def get_flags(): ('opengl', 'no'), ('legacygl', 'yes'), ('builtin_zlib', 'no'), + ("theora","no"), ('freetype','builtin'), #use builtin freetype ] @@ -59,12 +62,31 @@ def configure(env): env.Append(CPPPATH=['#tools/freetype']) env.Append(CPPPATH=['#tools/freetype/freetype/include']) - if (env["bits"]=="64"): - env.Append(CCFLAGS=['-arch', 'x86_64']) - env.Append(LINKFLAGS=['-arch', 'x86_64']) + + + if (not os.environ.has_key("OSXCROSS_ROOT")): + #regular native build + if (env["bits"]=="64"): + env.Append(CCFLAGS=['-arch', 'x86_64']) + env.Append(LINKFLAGS=['-arch', 'x86_64']) + else: + env.Append(CCFLAGS=['-arch', 'i386']) + env.Append(LINKFLAGS=['-arch', 'i386']) else: - env.Append(CCFLAGS=['-arch', 'i386']) - env.Append(LINKFLAGS=['-arch', 'i386']) + #osxcross build + root=os.environ.get("OSXCROSS_ROOT",0) + if env["bits"]=="64": + basecmd=root+"/target/bin/x86_64-apple-"+env["osxcross_sdk"]+"-" + else: + basecmd=root+"/target/bin/i386-apple-"+env["osxcross_sdk"]+"-" + + + env['CC'] = basecmd+"cc" + env['CXX'] = basecmd+"c++" + env['AR'] = basecmd+"ar" + env['RANLIB'] = basecmd+"ranlib" + env['AS'] = basecmd+"as" + # env.Append(CPPPATH=['#platform/osx/include/freetype2', '#platform/osx/include']) # env.Append(LIBPATH=['#platform/osx/lib']) diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 144037b1cb..869997f190 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -170,7 +170,7 @@ public: virtual int get_screen_count() const; virtual int get_current_screen() const; virtual void set_current_screen(int p_screen); - virtual Point2 get_screen_position(int p_screen=0); + virtual Point2 get_screen_position(int p_screen=0) const; virtual Point2 get_window_position() const; virtual void set_window_position(const Point2& p_position); virtual void set_window_size(const Size2 p_size); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 72699366c4..abfe42beda 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1279,7 +1279,7 @@ void OS_OSX::set_current_screen(int p_screen) { current_screen = p_screen; }; -Point2 OS_OSX::get_screen_position(int p_screen) { +Point2 OS_OSX::get_screen_position(int p_screen) const { ERR_FAIL_INDEX_V(p_screen, screens.size(), Point2()); return screens[p_screen].pos; diff --git a/platform/x11/detect.py b/platform/x11/detect.py index ff85e286db..33e8fd03e2 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -126,11 +126,22 @@ def configure(env): env.ParseConfig('pkg-config x11 --cflags --libs') env.ParseConfig('pkg-config xinerama --cflags --libs') env.ParseConfig('pkg-config xcursor --cflags --libs') - env.ParseConfig('pkg-config openssl --cflags --libs') + + if (env["openssl"]=="yes"): + env.ParseConfig('pkg-config openssl --cflags --libs') + + + if (env["freetype"]=="yes"): + env.ParseConfig('pkg-config freetype2 --cflags --libs') + + + if (env["freetype"]!="no"): + env.Append(CCFLAGS=['-DFREETYPE_ENABLED']) + if (env["freetype"]=="builtin"): + env.Append(CPPPATH=['#tools/freetype']) + env.Append(CPPPATH=['#tools/freetype/freetype/include']) - env.ParseConfig('pkg-config freetype2 --cflags --libs') - env.Append(CCFLAGS=['-DFREETYPE_ENABLED']) env.Append(CPPFLAGS=['-DOPENGL_ENABLED','-DGLEW_ENABLED']) diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index b34d1ba7c8..51f4392eb4 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -441,6 +441,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False); + //printf("got map notify\n"); } @@ -504,6 +505,23 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) { mouse_mode=p_mode; if (mouse_mode==MOUSE_MODE_CAPTURED) { + + while(true) { + //flush pending motion events + + if (XPending(x11_display) > 0) { + XEvent event; + XPeekEvent(x11_display, &event); + if (event.type==MotionNotify) { + XNextEvent(x11_display,&event); + } else { + break; + } + } else { + break; + } + } + if (XGrabPointer(x11_display, x11_window, True, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, @@ -518,6 +536,8 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) { 0,0,0,0, (int)center.x, (int)center.y); input->set_mouse_pos(center); + } else { + do_mouse_warp=false; } } @@ -652,17 +672,24 @@ void OS_X11::set_current_screen(int p_screen) { } Point2 OS_X11::get_screen_position(int p_screen) const { + // Using Xinerama Extension int event_base, error_base; const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base); - if( !ext_okay ) return Point2i(0,0); + if( !ext_okay ) { + return Point2i(0,0); + } int count; XineramaScreenInfo* xsi = XineramaQueryScreens(x11_display, &count); - if( p_screen >= count ) return Point2i(0,0); + if( p_screen >= count ) { + return Point2i(0,0); + } Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org); + XFree(xsi); + return position; } @@ -696,6 +723,7 @@ Point2 OS_X11::get_window_position() const { void OS_X11::set_window_position(const Point2& p_position) { // Using EWMH -- Extended Window Manager Hints // to get the size of the decoration +#if 0 Atom property = XInternAtom(x11_display,"_NET_FRAME_EXTENTS", True); Atom type; int format; @@ -738,6 +766,9 @@ void OS_X11::set_window_position(const Point2& p_position) { top -= screen_position.y; XMoveWindow(x11_display,x11_window,p_position.x - left,p_position.y - top); +#else + XMoveWindow(x11_display,x11_window,p_position.x,p_position.y); +#endif } Size2 OS_X11::get_window_size() const { @@ -1131,7 +1162,7 @@ void OS_X11::process_xevents() { //printf("checking events %i\n", XPending(x11_display)); - bool do_mouse_warp=false; + do_mouse_warp=false; while (XPending(x11_display) > 0) { XEvent event; @@ -1244,8 +1275,38 @@ void OS_X11::process_xevents() { } break; case MotionNotify: { - + + // FUCK YOU X11 API YOU SERIOUSLY GROSS ME OUT + // YOU ARE AS GROSS AS LOOKING AT A PUTRID PILE + // OF POOP STICKING OUT OF A CLOGGED TOILET + // HOW THE FUCK I AM SUPPOSED TO KNOW WHICH ONE + // OF THE MOTION NOTIFY EVENTS IS THE ONE GENERATED + // BY WARPING THE MOUSE POINTER? + // YOU ARE FORCING ME TO FILTER ONE BY ONE TO FIND IT + // PLEASE DO ME A FAVOR AND DIE DROWNED IN A FECAL + // MOUNTAIN BECAUSE THAT'S WHERE YOU BELONG. + + while(true) { + if (mouse_mode==MOUSE_MODE_CAPTURED && event.xmotion.x==current_videomode.width/2 && event.xmotion.y==current_videomode.height/2) { + //this is likely the warp event since it was warped here + center=Vector2(event.xmotion.x,event.xmotion.y); + break; + } + + if (XPending(x11_display) > 0) { + XEvent tevent; + XPeekEvent(x11_display, &tevent); + if (tevent.type==MotionNotify) { + XNextEvent(x11_display,&event); + } else { + break; + } + } else { + break; + } + } + last_timestamp=event.xmotion.time; // Motion is also simple. diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 261a54dd25..12f0aec611 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -114,6 +114,7 @@ class OS_X11 : public OS_Unix { bool minimized; int dpad_last[2]; + bool do_mouse_warp; const char *cursor_theme; int cursor_size; diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 92d5088b81..49229ba500 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -1172,6 +1172,14 @@ Matrix32 CanvasItem::get_viewport_transform() const { } +void CanvasItem::set_notify_local_transform(bool p_enable) { + notify_local_transform=p_enable; +} + +bool CanvasItem::is_local_transform_notification_enabled() const { + return notify_local_transform; +} + CanvasItem::CanvasItem() : xform_change(this) { @@ -1191,6 +1199,7 @@ CanvasItem::CanvasItem() : xform_change(this) { canvas_layer=NULL; use_parent_material=false; global_invalid=true; + notify_local_transform=false; light_mask=1; C=NULL; diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 6d8308dbe4..4885256c64 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -126,6 +126,7 @@ private: bool block_transform_notify; bool behind; bool use_parent_material; + bool notify_local_transform; Ref<CanvasItemMaterial> material; @@ -155,7 +156,7 @@ private: protected: - _FORCE_INLINE_ void _notify_transform() { if (!is_inside_tree()) return; _notify_transform(this); if (!block_transform_notify) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); } + _FORCE_INLINE_ void _notify_transform() { if (!is_inside_tree()) return; _notify_transform(this); if (!block_transform_notify && notify_local_transform) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); } void item_rect_changed(); @@ -263,6 +264,10 @@ public: Vector2 get_global_mouse_pos() const; Vector2 get_local_mouse_pos() const; + void set_notify_local_transform(bool p_enable); + bool is_local_transform_notification_enabled() const; + + CanvasItem(); ~CanvasItem(); }; diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index ceea41d1c8..8a5e2f51d1 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -33,7 +33,7 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { - if (unparenting) + if (unparenting || !can_update_body) return; CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>(); @@ -49,6 +49,7 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { //here comes the sun, lalalala //decompose concave into multiple convex polygons and add them Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon); + shape_from=co->get_shape_count(); for(int i=0;i<decomp.size();i++) { Ref<ConvexPolygonShape2D> convex = memnew( ConvexPolygonShape2D ); convex->set_points(decomp[i]); @@ -57,6 +58,11 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { co->set_shape_as_trigger(co->get_shape_count()-1,true); } + shape_to=co->get_shape_count()-1; + if (shape_to<shape_from) { + shape_from=-1; + shape_to=-1; + } } else { @@ -78,6 +84,9 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { if (trigger) co->set_shape_as_trigger(co->get_shape_count()-1,true); + shape_from=co->get_shape_count()-1; + shape_to=co->get_shape_count()-1; + } @@ -86,6 +95,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { void CollisionPolygon2D::_update_parent() { + if (!can_update_body) + return; Node *parent = get_parent(); if (!parent) return; @@ -101,12 +112,24 @@ void CollisionPolygon2D::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_TREE: { unparenting=false; + can_update_body=get_tree()->is_editor_hint(); + } break; + case NOTIFICATION_EXIT_TREE: { + can_update_body=false; } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (!is_inside_tree()) break; - _update_parent(); + if (can_update_body) { + _update_parent(); + } else if (shape_from>=0 && shape_to>=0) { + CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); + for(int i=shape_from;i<=shape_to;i++) { + co->set_shape_transform(i,get_transform()); + } + } + } break; @@ -141,20 +164,22 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2>& p_polygon) { polygon=p_polygon; - for(int i=0;i<polygon.size();i++) { - if (i==0) - aabb=Rect2(polygon[i],Size2()); - else - aabb.expand_to(polygon[i]); - } - if (aabb==Rect2()) { + if (can_update_body) { + for(int i=0;i<polygon.size();i++) { + if (i==0) + aabb=Rect2(polygon[i],Size2()); + else + aabb.expand_to(polygon[i]); + } + if (aabb==Rect2()) { - aabb=Rect2(-10,-10,20,20); - } else { - aabb.pos-=aabb.size*0.3; - aabb.size+=aabb.size*0.6; + aabb=Rect2(-10,-10,20,20); + } else { + aabb.pos-=aabb.size*0.3; + aabb.size+=aabb.size*0.6; + } + _update_parent(); } - _update_parent(); update(); } @@ -184,6 +209,13 @@ void CollisionPolygon2D::set_trigger(bool p_trigger) { trigger=p_trigger; _update_parent(); + if (!can_update_body && is_inside_tree() && shape_from>=0 && shape_to>=0) { + CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); + for(int i=shape_from;i<=shape_to;i++) { + co->set_shape_as_trigger(i,p_trigger); + } + + } } bool CollisionPolygon2D::is_trigger() const{ @@ -192,6 +224,17 @@ bool CollisionPolygon2D::is_trigger() const{ } +void CollisionPolygon2D::_set_shape_range(const Vector2& p_range) { + + shape_from=p_range.x; + shape_to=p_range.y; +} + +Vector2 CollisionPolygon2D::_get_shape_range() const { + + return Vector2(shape_from,shape_to); +} + void CollisionPolygon2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon2D::_add_to_collision_object); @@ -204,9 +247,17 @@ void CollisionPolygon2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_trigger"),&CollisionPolygon2D::set_trigger); ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionPolygon2D::is_trigger); + ObjectTypeDB::bind_method(_MD("_set_shape_range","shape_range"),&CollisionPolygon2D::_set_shape_range); + ObjectTypeDB::bind_method(_MD("_get_shape_range"),&CollisionPolygon2D::_get_shape_range); + + ObjectTypeDB::bind_method(_MD("get_collision_object_first_shape"),&CollisionPolygon2D::get_collision_object_first_shape); + ObjectTypeDB::bind_method(_MD("get_collision_object_last_shape"),&CollisionPolygon2D::get_collision_object_last_shape); + ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Solids,Segments"),_SCS("set_build_mode"),_SCS("get_build_mode")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"shape_range",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_shape_range"),_SCS("_get_shape_range")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); + } CollisionPolygon2D::CollisionPolygon2D() { @@ -215,6 +266,9 @@ CollisionPolygon2D::CollisionPolygon2D() { build_mode=BUILD_SOLIDS; trigger=false; unparenting=false; - + shape_from=-1; + shape_to=-1; + can_update_body=false; + set_notify_local_transform(true); } diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index 4e78868082..4bc9713c8a 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -56,6 +56,14 @@ protected: void _add_to_collision_object(Object *p_obj); void _update_parent(); + bool can_update_body; + int shape_from; + int shape_to; + + void _set_shape_range(const Vector2& p_range); + Vector2 _get_shape_range() const; + + protected: void _notification(int p_what); @@ -72,6 +80,10 @@ public: Vector<Point2> get_polygon() const; virtual Rect2 get_item_rect() const; + + int get_collision_object_first_shape() const { return shape_from; } + int get_collision_object_last_shape() const { return shape_to; } + CollisionPolygon2D(); }; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index 5012c54b17..a0a015a99e 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -44,10 +44,12 @@ void CollisionShape2D::_add_to_collision_object(Object *p_obj) { CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>(); ERR_FAIL_COND(!co); + update_shape_index=co->get_shape_count(); co->add_shape(shape,get_transform()); if (trigger) co->set_shape_as_trigger(co->get_shape_count()-1,true); + } void CollisionShape2D::_shape_changed() { @@ -74,12 +76,27 @@ void CollisionShape2D::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { unparenting=false; + can_update_body=get_tree()->is_editor_hint(); + } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (!is_inside_tree()) break; - _update_parent(); + if (can_update_body) { + _update_parent(); + } else if (update_shape_index>=0){ + + CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); + if (co) { + co->set_shape_transform(update_shape_index,get_transform()); + } + + } + + } break; + case NOTIFICATION_EXIT_TREE: { + can_update_body=false; } break; /* @@ -92,6 +109,9 @@ void CollisionShape2D::_notification(int p_what) { } break;*/ case NOTIFICATION_DRAW: { + if (!get_tree()->is_editor_hint()) + return; + rect=Rect2(); Color draw_col=Color(0,0.6,0.7,0.5); @@ -209,7 +229,14 @@ void CollisionShape2D::set_shape(const Ref<Shape2D>& p_shape) { shape->disconnect("changed",this,"_shape_changed"); shape=p_shape; update(); - _update_parent(); + if (is_inside_tree() && can_update_body) + _update_parent(); + if (is_inside_tree() && !can_update_body && update_shape_index>=0) { + CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); + if (co) { + co->set_shape(update_shape_index,p_shape); + } + } if (shape.is_valid()) shape->connect("changed",this,"_shape_changed"); @@ -228,7 +255,14 @@ Rect2 CollisionShape2D::get_item_rect() const { void CollisionShape2D::set_trigger(bool p_trigger) { trigger=p_trigger; - _update_parent(); + if (can_update_body) { + _update_parent(); + } else if (is_inside_tree() && update_shape_index>=0){ + CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); + if (co) { + co->set_shape_as_trigger(update_shape_index,p_trigger); + } + } } bool CollisionShape2D::is_trigger() const{ @@ -236,6 +270,19 @@ bool CollisionShape2D::is_trigger() const{ return trigger; } + +void CollisionShape2D::_set_update_shape_index(int p_index) { + + + update_shape_index=p_index; +} + +int CollisionShape2D::_get_update_shape_index() const{ + + return update_shape_index; +} + + void CollisionShape2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_shape","shape"),&CollisionShape2D::set_shape); @@ -245,14 +292,23 @@ void CollisionShape2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_trigger","enable"),&CollisionShape2D::set_trigger); ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionShape2D::is_trigger); + ObjectTypeDB::bind_method(_MD("_set_update_shape_index","index"),&CollisionShape2D::_set_update_shape_index); + ObjectTypeDB::bind_method(_MD("_get_update_shape_index"),&CollisionShape2D::_get_update_shape_index); + + ObjectTypeDB::bind_method(_MD("get_collision_object_shape_index"),&CollisionShape2D::get_collision_object_shape_index); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D"),_SCS("set_shape"),_SCS("get_shape")); ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "_update_shape_index", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_NOEDITOR), _SCS("_set_update_shape_index"), _SCS("_get_update_shape_index")); + } CollisionShape2D::CollisionShape2D() { rect=Rect2(-Point2(10,10),Point2(20,20)); - + set_notify_local_transform(true); trigger=false; unparenting = false; + can_update_body = false; + update_shape_index=-1; } diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index 507912d31e..82e1137174 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -39,7 +39,13 @@ class CollisionShape2D : public Node2D { Rect2 rect; bool trigger; bool unparenting; + bool can_update_body; void _shape_changed(); + int update_shape_index; + + void _set_update_shape_index(int p_index); + int _get_update_shape_index() const; + protected: void _update_parent(); @@ -55,6 +61,8 @@ public: void set_trigger(bool p_trigger); bool is_trigger() const; + int get_collision_object_shape_index() const { return _get_update_shape_index(); } + CollisionShape2D(); }; diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index c521952f9b..6705cebf37 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -322,8 +322,8 @@ void Sprite::_bind_methods() { ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v")); - ADD_PROPERTYNO( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes")); - ADD_PROPERTYNO( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes")); + ADD_PROPERTYNO( PropertyInfo( Variant::INT, "vframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_vframes"),_SCS("get_vframes")); + ADD_PROPERTYNO( PropertyInfo( Variant::INT, "hframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_hframes"),_SCS("get_hframes")); ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region")); diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index 58cbbdba22..ff35837bc0 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -83,15 +83,25 @@ real_t Area::get_gravity() const{ return gravity; } +void Area::set_linear_damp(real_t p_linear_damp){ -void Area::set_density(real_t p_density){ + linear_damp=p_linear_damp; + PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_LINEAR_DAMP,p_linear_damp); +} +real_t Area::get_linear_damp() const{ + + return linear_damp; +} - density=p_density; - PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_DENSITY,p_density); +void Area::set_angular_damp(real_t p_angular_damp){ + + angular_damp=p_angular_damp; + PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_ANGULAR_DAMP,p_angular_damp); } -real_t Area::get_density() const{ - return density; +real_t Area::get_angular_damp() const{ + + return angular_damp; } void Area::set_priority(real_t p_priority){ @@ -533,8 +543,11 @@ void Area::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&Area::set_gravity); ObjectTypeDB::bind_method(_MD("get_gravity"),&Area::get_gravity); - ObjectTypeDB::bind_method(_MD("set_density","density"),&Area::set_density); - ObjectTypeDB::bind_method(_MD("get_density"),&Area::get_density); + ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&Area::set_angular_damp); + ObjectTypeDB::bind_method(_MD("get_angular_damp"),&Area::get_angular_damp); + + ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&Area::set_linear_damp); + ObjectTypeDB::bind_method(_MD("get_linear_damp"),&Area::get_linear_damp); ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area::set_priority); ObjectTypeDB::bind_method(_MD("get_priority"),&Area::get_priority); @@ -571,7 +584,8 @@ void Area::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"gravity_vec"),_SCS("set_gravity_vector"),_SCS("get_gravity_vector")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_gravity"),_SCS("get_gravity")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"density",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_density"),_SCS("get_density")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"linear_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_linear_damp"),_SCS("get_linear_damp")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_angular_damp"),_SCS("get_angular_damp")); ADD_PROPERTY( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable")); @@ -586,7 +600,8 @@ Area::Area() : CollisionObject(PhysicsServer::get_singleton()->area_create(),tru set_gravity_vector(Vector3(0,-1,0)); gravity_is_point=false; gravity_distance_scale=0; - density=0.1; + linear_damp=0.1; + angular_damp=1; priority=0; monitoring=false; set_ray_pickable(false); diff --git a/scene/3d/area.h b/scene/3d/area.h index fa7500c47c..f03955d1e7 100644 --- a/scene/3d/area.h +++ b/scene/3d/area.h @@ -50,7 +50,8 @@ private: real_t gravity; bool gravity_is_point; real_t gravity_distance_scale; - real_t density; + real_t angular_damp; + real_t linear_damp; int priority; bool monitoring; bool monitorable; @@ -139,8 +140,11 @@ public: void set_gravity(real_t p_gravity); real_t get_gravity() const; - void set_density(real_t p_density); - real_t get_density() const; + void set_angular_damp(real_t p_angular_damp); + real_t get_angular_damp() const; + + void set_linear_damp(real_t p_linear_damp); + real_t get_linear_damp() const; void set_priority(real_t p_priority); real_t get_priority() const; diff --git a/scene/3d/body_shape.cpp b/scene/3d/body_shape.cpp index c49d1b028c..709a79a5f4 100644 --- a/scene/3d/body_shape.cpp +++ b/scene/3d/body_shape.cpp @@ -43,7 +43,10 @@ void CollisionShape::_update_body() { - + if (!get_tree() || !can_update_body) + return; + if (!get_tree()->is_editor_hint()) + return; if (get_parent() && get_parent()->cast_to<CollisionObject>()) get_parent()->cast_to<CollisionObject>()->_update_shapes_from_children(); @@ -310,10 +313,13 @@ void CollisionShape::_add_to_collision_object(Object* p_cshape) { if (shape.is_valid()) { + update_shape_index=co->get_shape_count(); co->add_shape(shape,get_transform()); - if (trigger) - co->set_shape_as_trigger( co->get_shape_count() -1, true ); - } + if (trigger) + co->set_shape_as_trigger( co->get_shape_count() -1, true ); + } else { + update_shape_index=-1; + } } void CollisionShape::_notification(int p_what) { @@ -322,12 +328,14 @@ void CollisionShape::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { unparenting=false; + can_update_body=get_tree()->is_editor_hint(); + set_notify_local_transform(!can_update_body); //indicator_instance = VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario()); } break; case NOTIFICATION_TRANSFORM_CHANGED: { // VisualServer::get_singleton()->instance_set_transform(indicator_instance,get_global_transform()); - if (updating_body) { + if (can_update_body && updating_body) { _update_body(); } } break; @@ -336,16 +344,30 @@ void CollisionShape::_notification(int p_what) { VisualServer::get_singleton()->free(indicator_instance); indicator_instance=RID(); }*/ + can_update_body=false; + set_notify_local_transform(false); } break; case NOTIFICATION_UNPARENTED: { unparenting=true; - if (updating_body) + if (can_update_body && updating_body) _update_body(); } break; case NOTIFICATION_PARENTED: { - if (updating_body) + if (can_update_body && updating_body) _update_body(); } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + + if (!can_update_body && update_shape_index>=0) { + + CollisionObject *co = get_parent()->cast_to<CollisionObject>(); + if (co) { + co->set_shape_transform(update_shape_index,get_transform()); + } + } + + } break; + } } @@ -357,6 +379,18 @@ void CollisionShape::resource_changed(RES res) { } +void CollisionShape::_set_update_shape_index(int p_index) { + + + update_shape_index=p_index; +} + +int CollisionShape::_get_update_shape_index() const{ + + return update_shape_index; +} + + void CollisionShape::_bind_methods() { //not sure if this should do anything @@ -368,10 +402,14 @@ void CollisionShape::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionShape::is_trigger); ObjectTypeDB::bind_method(_MD("make_convex_from_brothers"),&CollisionShape::make_convex_from_brothers); ObjectTypeDB::set_method_flags("CollisionShape","make_convex_from_brothers",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + ObjectTypeDB::bind_method(_MD("_set_update_shape_index","index"),&CollisionShape::_set_update_shape_index); + ObjectTypeDB::bind_method(_MD("_get_update_shape_index"),&CollisionShape::_get_update_shape_index); + ObjectTypeDB::bind_method(_MD("get_collision_object_shape_index"),&CollisionShape::get_collision_object_shape_index); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), _SCS("set_shape"), _SCS("get_shape")); - ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "_update_shape_index", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_NOEDITOR), _SCS("_set_update_shape_index"), _SCS("_get_update_shape_index")); } @@ -383,8 +421,15 @@ void CollisionShape::set_shape(const Ref<Shape> &p_shape) { if (!shape.is_null()) shape->register_owner(this); update_gizmo(); - if (updating_body) + if (updating_body) { _update_body(); + } else if (can_update_body && update_shape_index>=0 && is_inside_tree()){ + CollisionObject *co = get_parent()->cast_to<CollisionObject>(); + if (co) { + co->set_shape(update_shape_index,p_shape); + } + + } } Ref<Shape> CollisionShape::get_shape() const { @@ -405,8 +450,14 @@ bool CollisionShape::is_updating_body() const { void CollisionShape::set_trigger(bool p_trigger) { trigger=p_trigger; - if (updating_body) + if (updating_body) { _update_body(); + } else if (can_update_body && update_shape_index>=0 && is_inside_tree()){ + CollisionObject *co = get_parent()->cast_to<CollisionObject>(); + if (co) { + co->set_shape_as_trigger(update_shape_index,p_trigger); + } + } } bool CollisionShape::is_trigger() const{ @@ -419,7 +470,9 @@ CollisionShape::CollisionShape() { //indicator = VisualServer::get_singleton()->mesh_create(); updating_body=true; unparenting=false; - trigger=false; + update_shape_index=-1; + trigger=false; + can_update_body=false; } CollisionShape::~CollisionShape() { diff --git a/scene/3d/body_shape.h b/scene/3d/body_shape.h index b3c0006d79..c1ebf806a9 100644 --- a/scene/3d/body_shape.h +++ b/scene/3d/body_shape.h @@ -56,8 +56,16 @@ class CollisionShape : public Spatial { bool unparenting; bool trigger; + bool can_update_body; + + int update_shape_index; + void _update_body(); void _add_to_collision_object(Object* p_cshape); + + void _set_update_shape_index(int p_index); + int _get_update_shape_index() const; + protected: void _notification(int p_what); @@ -73,8 +81,10 @@ public: void set_updating_body(bool p_update); bool is_updating_body() const; - void set_trigger(bool p_trigger); - bool is_trigger() const; + void set_trigger(bool p_trigger); + bool is_trigger() const; + + int get_collision_object_shape_index() const { return _get_update_shape_index(); } CollisionShape(); ~CollisionShape(); diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp index 4ab1a1a1ab..c857b4851a 100644 --- a/scene/3d/collision_polygon.cpp +++ b/scene/3d/collision_polygon.cpp @@ -6,6 +6,8 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) { + if (!can_update_body) + return; CollisionObject *co = p_obj->cast_to<CollisionObject>(); ERR_FAIL_COND(!co); @@ -23,6 +25,7 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) { //here comes the sun, lalalala //decompose concave into multiple convex polygons and add them + shape_from=co->get_shape_count(); for(int i=0;i<decomp.size();i++) { Ref<ConvexPolygonShape> convex = memnew( ConvexPolygonShape ); DVector<Vector3> cp; @@ -43,6 +46,11 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) { co->add_shape(convex,get_transform()); } + shape_to=co->get_shape_count()-1; + if (shape_to<shape_from) { + shape_from=-1; + shape_to=-1; + } } else { #if 0 @@ -71,6 +79,9 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) { void CollisionPolygon::_update_parent() { + if (!can_update_body) + return; + Node *parent = get_parent(); if (!parent) return; @@ -80,15 +91,50 @@ void CollisionPolygon::_update_parent() { co->_update_shapes_from_children(); } +void CollisionPolygon::_set_shape_range(const Vector2& p_range) { + + shape_from=p_range.x; + shape_to=p_range.y; +} + +Vector2 CollisionPolygon::_get_shape_range() const { + + return Vector2(shape_from,shape_to); +} + void CollisionPolygon::_notification(int p_what) { switch(p_what) { + case NOTIFICATION_ENTER_TREE: { + can_update_body=get_tree()->is_editor_hint(); + set_notify_local_transform(!can_update_body); + + //indicator_instance = VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario()); + } break; + case NOTIFICATION_EXIT_TREE: { + can_update_body=false; + set_notify_local_transform(false); + } break; case NOTIFICATION_TRANSFORM_CHANGED: { if (!is_inside_tree()) break; - _update_parent(); + if (can_update_body) { + _update_parent(); + } + + } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (!can_update_body && shape_from>=0 && shape_from>=0) { + + CollisionObject *co = get_parent()->cast_to<CollisionObject>(); + if (co) { + for(int i=shape_from;i<=shape_to;i++) { + co->set_shape_transform(i,get_transform()); + } + } + } } break; #if 0 @@ -119,29 +165,31 @@ void CollisionPolygon::_notification(int p_what) { void CollisionPolygon::set_polygon(const Vector<Point2>& p_polygon) { polygon=p_polygon; + if (can_update_body) { - for(int i=0;i<polygon.size();i++) { + for(int i=0;i<polygon.size();i++) { - Vector3 p1(polygon[i].x,polygon[i].y,depth*0.5); + Vector3 p1(polygon[i].x,polygon[i].y,depth*0.5); - if (i==0) - aabb=AABB(p1,Vector3()); - else - aabb.expand_to(p1); + if (i==0) + aabb=AABB(p1,Vector3()); + else + aabb.expand_to(p1); - Vector3 p2(polygon[i].x,polygon[i].y,-depth*0.5); - aabb.expand_to(p2); + Vector3 p2(polygon[i].x,polygon[i].y,-depth*0.5); + aabb.expand_to(p2); - } - if (aabb==AABB()) { + } + if (aabb==AABB()) { - aabb=AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); - } else { - aabb.pos-=aabb.size*0.3; - aabb.size+=aabb.size*0.6; + aabb=AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); + } else { + aabb.pos-=aabb.size*0.3; + aabb.size+=aabb.size*0.6; + } + _update_parent(); } - _update_parent(); update_gizmo(); } @@ -154,6 +202,8 @@ void CollisionPolygon::set_build_mode(BuildMode p_mode) { ERR_FAIL_INDEX(p_mode,2); build_mode=p_mode; + if (!can_update_body) + return; _update_parent(); } @@ -170,6 +220,8 @@ AABB CollisionPolygon::get_item_rect() const { void CollisionPolygon::set_depth(float p_depth) { depth=p_depth; + if (!can_update_body) + return; _update_parent(); update_gizmo(); } @@ -183,22 +235,34 @@ float CollisionPolygon::get_depth() const { void CollisionPolygon::_bind_methods() { ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon::_add_to_collision_object); - ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&CollisionPolygon::set_polygon); - ObjectTypeDB::bind_method(_MD("get_polygon"),&CollisionPolygon::get_polygon); + + ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon::set_build_mode); + ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon::get_build_mode); ObjectTypeDB::bind_method(_MD("set_depth","depth"),&CollisionPolygon::set_depth); ObjectTypeDB::bind_method(_MD("get_depth"),&CollisionPolygon::get_depth); - ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon::set_build_mode); - ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon::get_build_mode); + ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&CollisionPolygon::set_polygon); + ObjectTypeDB::bind_method(_MD("get_polygon"),&CollisionPolygon::get_polygon); + + ObjectTypeDB::bind_method(_MD("_set_shape_range","shape_range"),&CollisionPolygon::_set_shape_range); + ObjectTypeDB::bind_method(_MD("_get_shape_range"),&CollisionPolygon::_get_shape_range); + + ObjectTypeDB::bind_method(_MD("get_collision_object_first_shape"),&CollisionPolygon::get_collision_object_first_shape); + ObjectTypeDB::bind_method(_MD("get_collision_object_last_shape"),&CollisionPolygon::get_collision_object_last_shape); ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Solids,Triangles"),_SCS("set_build_mode"),_SCS("get_build_mode")); - ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"depth"),_SCS("set_depth"),_SCS("get_depth")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"shape_range",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_shape_range"),_SCS("_get_shape_range")); } CollisionPolygon::CollisionPolygon() { + shape_from=-1; + shape_to=-1; + can_update_body=false; + aabb=AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); build_mode=BUILD_SOLIDS; depth=1.0; diff --git a/scene/3d/collision_polygon.h b/scene/3d/collision_polygon.h index efb3666778..9b9afea34f 100644 --- a/scene/3d/collision_polygon.h +++ b/scene/3d/collision_polygon.h @@ -24,9 +24,17 @@ protected: BuildMode build_mode; Vector<Point2> polygon; + void _add_to_collision_object(Object *p_obj); void _update_parent(); + bool can_update_body; + int shape_from; + int shape_to; + + void _set_shape_range(const Vector2& p_range); + Vector2 _get_shape_range() const; + protected: void _notification(int p_what); @@ -43,6 +51,10 @@ public: Vector<Point2> get_polygon() const; virtual AABB get_item_rect() const; + + int get_collision_object_first_shape() const { return shape_from; } + int get_collision_object_last_shape() const { return shape_to; } + CollisionPolygon(); }; diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 3d5091f667..d61859a3d0 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -133,6 +133,8 @@ real_t StaticBody::get_bounce() const{ return bounce; } + + void StaticBody::set_constant_linear_velocity(const Vector3& p_vel) { constant_linear_velocity=p_vel; @@ -494,6 +496,42 @@ real_t RigidBody::get_bounce() const{ return bounce; } + +void RigidBody::set_gravity_scale(real_t p_gravity_scale){ + + gravity_scale=p_gravity_scale; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_GRAVITY_SCALE,gravity_scale); + +} +real_t RigidBody::get_gravity_scale() const{ + + return gravity_scale; +} + +void RigidBody::set_linear_damp(real_t p_linear_damp){ + + ERR_FAIL_COND(p_linear_damp<-1); + linear_damp=p_linear_damp; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_LINEAR_DAMP,linear_damp); + +} +real_t RigidBody::get_linear_damp() const{ + + return linear_damp; +} + +void RigidBody::set_angular_damp(real_t p_angular_damp){ + + ERR_FAIL_COND(p_angular_damp<-1); + angular_damp=p_angular_damp; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_ANGULAR_DAMP,angular_damp); + +} +real_t RigidBody::get_angular_damp() const{ + + return angular_damp; +} + void RigidBody::set_axis_velocity(const Vector3& p_axis) { Vector3 v = state? state->get_linear_velocity() : linear_velocity; @@ -685,6 +723,16 @@ void RigidBody::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_angular_velocity","angular_velocity"),&RigidBody::set_angular_velocity); ObjectTypeDB::bind_method(_MD("get_angular_velocity"),&RigidBody::get_angular_velocity); + ObjectTypeDB::bind_method(_MD("set_gravity_scale","gravity_scale"),&RigidBody::set_gravity_scale); + ObjectTypeDB::bind_method(_MD("get_gravity_scale"),&RigidBody::get_gravity_scale); + + ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&RigidBody::set_linear_damp); + ObjectTypeDB::bind_method(_MD("get_linear_damp"),&RigidBody::get_linear_damp); + + ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&RigidBody::set_angular_damp); + ObjectTypeDB::bind_method(_MD("get_angular_damp"),&RigidBody::get_angular_damp); + + ObjectTypeDB::bind_method(_MD("set_max_contacts_reported","amount"),&RigidBody::set_max_contacts_reported); ObjectTypeDB::bind_method(_MD("get_max_contacts_reported"),&RigidBody::get_max_contacts_reported); @@ -722,6 +770,7 @@ void RigidBody::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::REAL,"weight",PROPERTY_HINT_EXP_RANGE,"0.01,65535,0.01",PROPERTY_USAGE_EDITOR),_SCS("set_weight"),_SCS("get_weight")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_friction"),_SCS("get_friction")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_bounce"),_SCS("get_bounce")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_scale",PROPERTY_HINT_RANGE,"-128,128,0.01"),_SCS("set_gravity_scale"),_SCS("get_gravity_scale")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"custom_integrator"),_SCS("set_use_custom_integrator"),_SCS("is_using_custom_integrator")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"continuous_cd"),_SCS("set_use_continuous_collision_detection"),_SCS("is_using_continuous_collision_detection")); ADD_PROPERTY( PropertyInfo(Variant::INT,"contacts_reported"),_SCS("set_max_contacts_reported"),_SCS("get_max_contacts_reported")); @@ -731,6 +780,8 @@ void RigidBody::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::INT,"axis_lock",PROPERTY_HINT_ENUM,"Disabled,Lock X,Lock Y,Lock Z"),_SCS("set_axis_lock"),_SCS("get_axis_lock")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"velocity/linear"),_SCS("set_linear_velocity"),_SCS("get_linear_velocity")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"velocity/angular"),_SCS("set_angular_velocity"),_SCS("get_angular_velocity")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"damp_override/linear",PROPERTY_HINT_RANGE,"-1,128,0.01"),_SCS("set_linear_damp"),_SCS("get_linear_damp")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"damp_override/angular",PROPERTY_HINT_RANGE,"-1,128,0.01"),_SCS("set_angular_damp"),_SCS("get_angular_damp")); ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape"))); ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape"))); @@ -753,6 +804,10 @@ RigidBody::RigidBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) { max_contacts_reported=0; state=NULL; + gravity_scale=1; + linear_damp=-1; + angular_damp=-1; + //angular_velocity=0; sleeping=false; ccd=false; diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 0ff3b360af..66490ba925 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -129,6 +129,10 @@ private: Vector3 linear_velocity; Vector3 angular_velocity; + real_t gravity_scale; + real_t linear_damp; + real_t angular_damp; + bool sleeping; bool ccd; @@ -217,6 +221,16 @@ public: void set_angular_velocity(const Vector3&p_velocity); Vector3 get_angular_velocity() const; + void set_gravity_scale(real_t p_gravity_scale); + real_t get_gravity_scale() const; + + void set_linear_damp(real_t p_linear_damp); + real_t get_linear_damp() const; + + void set_angular_damp(real_t p_angular_damp); + real_t get_angular_damp() const; + + void set_use_custom_integrator(bool p_enable); bool is_using_custom_integrator(); diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 7117c59176..a65f68ed2c 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -231,6 +231,11 @@ void Spatial::set_transform(const Transform& p_transform) { _change_notify("transform/rotation"); _change_notify("transform/scale"); _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } + + } @@ -335,6 +340,9 @@ void Spatial::set_translation(const Vector3& p_translation) { data.local_transform.origin=p_translation; _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } } @@ -348,6 +356,9 @@ void Spatial::set_rotation(const Vector3& p_euler){ data.rotation=p_euler; data.dirty|=DIRTY_LOCAL; _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } } void Spatial::set_scale(const Vector3& p_scale){ @@ -360,6 +371,9 @@ void Spatial::set_scale(const Vector3& p_scale){ data.scale=p_scale; data.dirty|=DIRTY_LOCAL; _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } } @@ -685,6 +699,13 @@ void Spatial::look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, con } +void Spatial::set_notify_local_transform(bool p_enable) { + data.notify_local_transform=p_enable; +} + +bool Spatial::is_local_transform_notification_enabled() const { + return data.notify_local_transform; +} void Spatial::_bind_methods() { @@ -725,6 +746,9 @@ void Spatial::_bind_methods() { ObjectTypeDB::bind_method(_MD("_set_visible_"), &Spatial::_set_visible_); ObjectTypeDB::bind_method(_MD("_is_visible_"), &Spatial::_is_visible_); + ObjectTypeDB::bind_method(_MD("set_notify_local_transform","enable"), &Spatial::set_notify_local_transform); + ObjectTypeDB::bind_method(_MD("is_local_transform_notification_enabled"), &Spatial::is_local_transform_notification_enabled); + void rotate(const Vector3& p_normal,float p_radians); void rotate_x(float p_radians); void rotate_y(float p_radians); @@ -783,6 +807,7 @@ Spatial::Spatial() : xform_change(this) data.gizmo_disabled=false; data.gizmo_dirty=false; #endif + data.notify_local_transform=false; data.parent=NULL; data.C=NULL; diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 8b40786fb8..7fa6099d7a 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -91,6 +91,7 @@ class Spatial : public Node { List<Spatial*>::Element *C; bool ignore_notification; + bool notify_local_transform; bool visible; @@ -134,6 +135,7 @@ public: NOTIFICATION_ENTER_WORLD=41, NOTIFICATION_EXIT_WORLD=42, NOTIFICATION_VISIBILITY_CHANGED=43, + NOTIFICATION_LOCAL_TRANSFORM_CHANGED=44, }; Spatial *get_parent_spatial() const; @@ -179,6 +181,9 @@ public: void look_at(const Vector3& p_target, const Vector3& p_up_normal); void look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, const Vector3& p_up_normal); + void set_notify_local_transform(bool p_enable); + bool is_local_transform_notification_enabled() const; + void orthonormalize(); void set_identity(); diff --git a/scene/3d/spatial_stream_player.cpp b/scene/3d/spatial_stream_player.cpp index 84e68bf418..b81d98e8bf 100644 --- a/scene/3d/spatial_stream_player.cpp +++ b/scene/3d/spatial_stream_player.cpp @@ -30,21 +30,79 @@ -void SpatialStreamPlayer::_notification(int p_what) { +int SpatialStreamPlayer::InternalStream::get_channel_count() const { - switch(p_what) { + return player->sp_get_channel_count(); +} +void SpatialStreamPlayer::InternalStream::set_mix_rate(int p_rate){ - case NOTIFICATION_ENTER_WORLD: { + return player->sp_set_mix_rate(p_rate); +} +bool SpatialStreamPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){ + + return player->sp_mix(p_buffer,p_frames); +} +void SpatialStreamPlayer::InternalStream::update(){ + + player->sp_update(); +} + + +int SpatialStreamPlayer::sp_get_channel_count() const { + + return playback->get_channels(); +} + +void SpatialStreamPlayer::sp_set_mix_rate(int p_rate){ + + server_mix_rate=p_rate; +} + +bool SpatialStreamPlayer::sp_mix(int32_t *p_buffer,int p_frames) { + + if (resampler.is_ready()) { + return resampler.mix(p_buffer,p_frames); + } + + return false; +} + +void SpatialStreamPlayer::sp_update() { + + _THREAD_SAFE_METHOD_ + if (!paused && resampler.is_ready() && playback.is_valid()) { + + if (!playback->is_playing()) { + //stream depleted data, but there's still audio in the ringbuffer + //check that all this audio has been flushed before stopping the stream + int to_mix = resampler.get_total() - resampler.get_todo(); + if (to_mix==0) { + stop(); + return; + } + + return; + } + + int todo =resampler.get_todo(); + int wrote = playback->mix(resampler.get_write_buffer(),todo); + resampler.write(wrote); + } +} -// set_idle_process(false); //don't annoy - } break; - case NOTIFICATION_PROCESS: { -// if (!stream.is_null()) -// stream->update(); +void SpatialStreamPlayer::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_TREE: { + + //set_idle_process(false); //don't annoy + if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint()) + play(); } break; - case NOTIFICATION_EXIT_WORLD: { + case NOTIFICATION_EXIT_TREE: { stop(); //wathever it may be doing, stop } break; @@ -58,12 +116,20 @@ void SpatialStreamPlayer::set_stream(const Ref<AudioStream> &p_stream) { stop(); stream=p_stream; - if (!stream.is_null()) { - stream->set_loop(loops); + if (!stream.is_null()) { + playback=stream->instance_playback(); + playback->set_loop(loops); + playback->set_loop_restart_time(loop_point); + AudioServer::get_singleton()->lock(); + resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,playback->get_minimum_buffer_size()); + AudioServer::get_singleton()->unlock(); + } else { + AudioServer::get_singleton()->lock(); + resampler.clear(); + playback.unref(); + AudioServer::get_singleton()->unlock(); } - - } Ref<AudioStream> SpatialStreamPlayer::get_stream() const { @@ -72,18 +138,25 @@ Ref<AudioStream> SpatialStreamPlayer::get_stream() const { } -void SpatialStreamPlayer::play() { +void SpatialStreamPlayer::play(float p_from_offset) { - if (!is_inside_tree()) + ERR_FAIL_COND(!is_inside_tree()); + if (playback.is_null()) return; - if (stream.is_null()) - return; - if (stream->is_playing()) + if (playback->is_playing()) stop(); - stream->play(); - SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),stream->get_audio_stream()); - //if (stream->get_update_mode()!=AudioStream::UPDATE_NONE) - // set_idle_process(true); + + _THREAD_SAFE_METHOD_ + playback->play(p_from_offset); + //feed the ringbuffer as long as no update callback is going on + sp_update(); + + SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),&internal_stream); + +// AudioServer::get_singleton()->stream_set_active(stream_rid,true); +// AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume); +// if (stream->get_update_mode()!=AudioStream::UPDATE_NONE) +// set_idle_process(true); } @@ -91,28 +164,30 @@ void SpatialStreamPlayer::stop() { if (!is_inside_tree()) return; - if (stream.is_null()) + if (playback.is_null()) return; + _THREAD_SAFE_METHOD_ + //AudioServer::get_singleton()->stream_set_active(stream_rid,false); SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),NULL); - stream->stop(); + playback->stop(); //set_idle_process(false); } bool SpatialStreamPlayer::is_playing() const { - if (stream.is_null()) + if (playback.is_null()) return false; - return stream->is_playing(); + return playback->is_playing(); } void SpatialStreamPlayer::set_loop(bool p_enable) { loops=p_enable; - if (stream.is_null()) + if (playback.is_null()) return; - stream->set_loop(loops); + playback->set_loop(loops); } bool SpatialStreamPlayer::has_loop() const { @@ -120,6 +195,46 @@ bool SpatialStreamPlayer::has_loop() const { return loops; } +void SpatialStreamPlayer::set_volume(float p_vol) { + + volume=p_vol; + if (stream_rid.is_valid()) + AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume); +} + +float SpatialStreamPlayer::get_volume() const { + + return volume; +} + +void SpatialStreamPlayer::set_loop_restart_time(float p_secs) { + + loop_point=p_secs; + if (playback.is_valid()) + playback->set_loop_restart_time(p_secs); +} + +float SpatialStreamPlayer::get_loop_restart_time() const { + + return loop_point; +} + + +void SpatialStreamPlayer::set_volume_db(float p_db) { + + if (p_db<-79) + set_volume(0); + else + set_volume(Math::db2linear(p_db)); +} + +float SpatialStreamPlayer::get_volume_db() const { + + if (volume==0) + return -80; + else + return Math::linear2db(volume); +} String SpatialStreamPlayer::get_stream_name() const { @@ -132,27 +247,85 @@ String SpatialStreamPlayer::get_stream_name() const { int SpatialStreamPlayer::get_loop_count() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_loop_count(); + return playback->get_loop_count(); } float SpatialStreamPlayer::get_pos() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_pos(); + return playback->get_pos(); + +} + +float SpatialStreamPlayer::get_length() const { + if (playback.is_null()) + return 0; + return playback->get_length(); } void SpatialStreamPlayer::seek_pos(float p_time) { - if (stream.is_null()) + if (playback.is_null()) return; - return stream->seek_pos(p_time); + return playback->seek_pos(p_time); + +} + +void SpatialStreamPlayer::set_autoplay(bool p_enable) { + + autoplay=p_enable; +} + +bool SpatialStreamPlayer::has_autoplay() const { + + return autoplay; +} + +void SpatialStreamPlayer::set_paused(bool p_paused) { + + paused=p_paused; + //if (stream.is_valid()) + // stream->set_paused(p_paused); +} + +bool SpatialStreamPlayer::is_paused() const { + return paused; } +void SpatialStreamPlayer::_set_play(bool p_play) { + + _play=p_play; + if (is_inside_tree()) { + if(_play) + play(); + else + stop(); + } + +} + +bool SpatialStreamPlayer::_get_play() const{ + + return _play; +} + +void SpatialStreamPlayer::set_buffering_msec(int p_msec) { + + buffering_ms=p_msec; +} + +int SpatialStreamPlayer::get_buffering_msec() const{ + + return buffering_ms; +} + + + void SpatialStreamPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&SpatialStreamPlayer::set_stream); @@ -163,28 +336,67 @@ void SpatialStreamPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_playing"),&SpatialStreamPlayer::is_playing); + ObjectTypeDB::bind_method(_MD("set_paused","paused"),&SpatialStreamPlayer::set_paused); + ObjectTypeDB::bind_method(_MD("is_paused"),&SpatialStreamPlayer::is_paused); + ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&SpatialStreamPlayer::set_loop); ObjectTypeDB::bind_method(_MD("has_loop"),&SpatialStreamPlayer::has_loop); + ObjectTypeDB::bind_method(_MD("set_volume","volume"),&SpatialStreamPlayer::set_volume); + ObjectTypeDB::bind_method(_MD("get_volume"),&SpatialStreamPlayer::get_volume); + + ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&SpatialStreamPlayer::set_volume_db); + ObjectTypeDB::bind_method(_MD("get_volume_db"),&SpatialStreamPlayer::get_volume_db); + + ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&SpatialStreamPlayer::set_buffering_msec); + ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&SpatialStreamPlayer::get_buffering_msec); + + ObjectTypeDB::bind_method(_MD("set_loop_restart_time","secs"),&SpatialStreamPlayer::set_loop_restart_time); + ObjectTypeDB::bind_method(_MD("get_loop_restart_time"),&SpatialStreamPlayer::get_loop_restart_time); + ObjectTypeDB::bind_method(_MD("get_stream_name"),&SpatialStreamPlayer::get_stream_name); ObjectTypeDB::bind_method(_MD("get_loop_count"),&SpatialStreamPlayer::get_loop_count); ObjectTypeDB::bind_method(_MD("get_pos"),&SpatialStreamPlayer::get_pos); ObjectTypeDB::bind_method(_MD("seek_pos","time"),&SpatialStreamPlayer::seek_pos); - ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"),_SCS("get_stream") ); - ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"),_SCS("has_loop") ); + ObjectTypeDB::bind_method(_MD("set_autoplay","enabled"),&SpatialStreamPlayer::set_autoplay); + ObjectTypeDB::bind_method(_MD("has_autoplay"),&SpatialStreamPlayer::has_autoplay); + ObjectTypeDB::bind_method(_MD("get_length"),&SpatialStreamPlayer::get_length); + + ObjectTypeDB::bind_method(_MD("_set_play","play"),&SpatialStreamPlayer::_set_play); + ObjectTypeDB::bind_method(_MD("_get_play"),&SpatialStreamPlayer::_get_play); + + ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"), _SCS("get_stream") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/play"), _SCS("_set_play"), _SCS("_get_play") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"), _SCS("has_loop") ); + ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") ); + ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/loop_restart_time"), _SCS("set_loop_restart_time"), _SCS("get_loop_restart_time") ); + ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/buffering_ms"), _SCS("set_buffering_msec"), _SCS("get_buffering_msec") ); } SpatialStreamPlayer::SpatialStreamPlayer() { + volume=1; loops=false; + paused=false; + autoplay=false; + _play=false; + server_mix_rate=1; + internal_stream.player=this; + stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream); + buffering_ms=500; + loop_point=0; + } SpatialStreamPlayer::~SpatialStreamPlayer() { - -} + AudioServer::get_singleton()->free(stream_rid); + resampler.clear(); +} diff --git a/scene/3d/spatial_stream_player.h b/scene/3d/spatial_stream_player.h index 7e639a7232..f2775a4982 100644 --- a/scene/3d/spatial_stream_player.h +++ b/scene/3d/spatial_stream_player.h @@ -31,16 +31,48 @@ #include "scene/resources/audio_stream.h" #include "scene/3d/spatial_player.h" - +#include "servers/audio/audio_rb_resampler.h" class SpatialStreamPlayer : public SpatialPlayer { OBJ_TYPE(SpatialStreamPlayer,SpatialPlayer); + _THREAD_SAFE_CLASS_ + + struct InternalStream : public AudioServer::AudioStream { + SpatialStreamPlayer *player; + virtual int get_channel_count() const; + virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate + virtual bool mix(int32_t *p_buffer,int p_frames); + virtual void update(); + }; + + + InternalStream internal_stream; + Ref<AudioStreamPlayback> playback; Ref<AudioStream> stream; + + int sp_get_channel_count() const; + void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate + bool sp_mix(int32_t *p_buffer,int p_frames); + void sp_update(); + + int server_mix_rate; + + RID stream_rid; + bool paused; + bool autoplay; bool loops; -protected: + float volume; + float loop_point; + int buffering_ms; + AudioRBResampler resampler; + + bool _play; + void _set_play(bool p_play); + bool _get_play() const; +protected: void _notification(int p_what); static void _bind_methods(); @@ -49,21 +81,37 @@ public: void set_stream(const Ref<AudioStream> &p_stream); Ref<AudioStream> get_stream() const; - void play(); + void play(float p_from_offset=0); void stop(); bool is_playing() const; + void set_paused(bool p_paused); + bool is_paused() const; + void set_loop(bool p_enable); bool has_loop() const; + void set_volume(float p_vol); + float get_volume() const; + + void set_loop_restart_time(float p_secs); + float get_loop_restart_time() const; + + void set_volume_db(float p_db); + float get_volume_db() const; String get_stream_name() const; - int get_loop_count() const; + int get_loop_count() const; float get_pos() const; void seek_pos(float p_time); + float get_length() const; + void set_autoplay(bool p_vol); + bool has_autoplay() const; + void set_buffering_msec(int p_msec); + int get_buffering_msec() const; SpatialStreamPlayer(); ~SpatialStreamPlayer(); diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index e9da95f3fb..c7d1249a07 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -578,8 +578,8 @@ void Sprite3D::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_hframes"),&Sprite3D::get_hframes); 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, "vframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_vframes"),_SCS("get_vframes")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_hframes"),_SCS("get_hframes")); 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")); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index f8b58b5cb5..c2ea1c8bb6 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -857,6 +857,11 @@ void AnimationPlayer::clear_queue() { queued.clear(); }; +void AnimationPlayer::play_backwards(const StringName& p_name,float p_custom_blend) { + + play(p_name,p_custom_blend,-1,true); +} + void AnimationPlayer::play(const StringName& p_name, float p_custom_blend, float p_custom_scale,bool p_from_end) { //printf("animation is %ls\n", String(p_name).c_str()); @@ -1216,6 +1221,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("play_backwards","name","custom_blend"),&AnimationPlayer::play_backwards,DEFVAL(""),DEFVAL(-1)); 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); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 3fddc283ae..1e3c37c4d6 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -258,6 +258,7 @@ public: float get_default_blend_time() const; void play(const StringName& p_name=StringName(),float p_custom_blend=-1,float p_custom_scale=1.0,bool p_from_end=false); + void play_backwards(const StringName& p_name=StringName(),float p_custom_blend=-1); void queue(const StringName& p_name); void clear_queue(); void stop(bool p_reset=true); diff --git a/scene/audio/stream_player.cpp b/scene/audio/stream_player.cpp index a097aacf19..699d068287 100644 --- a/scene/audio/stream_player.cpp +++ b/scene/audio/stream_player.cpp @@ -28,6 +28,67 @@ /*************************************************************************/ #include "stream_player.h" +int StreamPlayer::InternalStream::get_channel_count() const { + + return player->sp_get_channel_count(); +} +void StreamPlayer::InternalStream::set_mix_rate(int p_rate){ + + return player->sp_set_mix_rate(p_rate); +} +bool StreamPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){ + + return player->sp_mix(p_buffer,p_frames); +} +void StreamPlayer::InternalStream::update(){ + + player->sp_update(); +} + + +int StreamPlayer::sp_get_channel_count() const { + + return playback->get_channels(); +} + +void StreamPlayer::sp_set_mix_rate(int p_rate){ + + server_mix_rate=p_rate; +} + +bool StreamPlayer::sp_mix(int32_t *p_buffer,int p_frames) { + + if (resampler.is_ready()) { + return resampler.mix(p_buffer,p_frames); + } + + return false; +} + +void StreamPlayer::sp_update() { + + _THREAD_SAFE_METHOD_ + if (!paused && resampler.is_ready() && playback.is_valid()) { + + if (!playback->is_playing()) { + //stream depleted data, but there's still audio in the ringbuffer + //check that all this audio has been flushed before stopping the stream + int to_mix = resampler.get_total() - resampler.get_todo(); + if (to_mix==0) { + stop(); + return; + } + + return; + } + + int todo =resampler.get_todo(); + int wrote = playback->mix(resampler.get_write_buffer(),todo); + resampler.write(wrote); + } +} + + void StreamPlayer::_notification(int p_what) { @@ -52,19 +113,21 @@ void StreamPlayer::set_stream(const Ref<AudioStream> &p_stream) { stop(); - if (stream_rid.is_valid()) - AudioServer::get_singleton()->free(stream_rid); - stream_rid=RID(); - stream=p_stream; - if (!stream.is_null()) { - stream->set_loop(loops); - stream->set_paused(paused); - stream_rid=AudioServer::get_singleton()->audio_stream_create(stream->get_audio_stream()); + if (!stream.is_null()) { + playback=stream->instance_playback(); + playback->set_loop(loops); + playback->set_loop_restart_time(loop_point); + AudioServer::get_singleton()->lock(); + resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,playback->get_minimum_buffer_size()); + AudioServer::get_singleton()->unlock(); + } else { + AudioServer::get_singleton()->lock(); + resampler.clear(); + playback.unref(); + AudioServer::get_singleton()->unlock(); } - - } Ref<AudioStream> StreamPlayer::get_stream() const { @@ -73,15 +136,18 @@ Ref<AudioStream> StreamPlayer::get_stream() const { } -void StreamPlayer::play() { +void StreamPlayer::play(float p_from_offset) { ERR_FAIL_COND(!is_inside_tree()); - if (stream.is_null()) + if (playback.is_null()) return; - if (stream->is_playing()) + if (playback->is_playing()) stop(); - stream->play(); + _THREAD_SAFE_METHOD_ + playback->play(p_from_offset); + //feed the ringbuffer as long as no update callback is going on + sp_update(); AudioServer::get_singleton()->stream_set_active(stream_rid,true); AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume); // if (stream->get_update_mode()!=AudioStream::UPDATE_NONE) @@ -93,28 +159,29 @@ void StreamPlayer::stop() { if (!is_inside_tree()) return; - if (stream.is_null()) + if (playback.is_null()) return; + _THREAD_SAFE_METHOD_ AudioServer::get_singleton()->stream_set_active(stream_rid,false); - stream->stop(); + playback->stop(); //set_idle_process(false); } bool StreamPlayer::is_playing() const { - if (stream.is_null()) + if (playback.is_null()) return false; - return stream->is_playing(); + return playback->is_playing(); } void StreamPlayer::set_loop(bool p_enable) { loops=p_enable; - if (stream.is_null()) + if (playback.is_null()) return; - stream->set_loop(loops); + playback->set_loop(loops); } bool StreamPlayer::has_loop() const { @@ -134,6 +201,19 @@ float StreamPlayer::get_volume() const { return volume; } +void StreamPlayer::set_loop_restart_time(float p_secs) { + + loop_point=p_secs; + if (playback.is_valid()) + playback->set_loop_restart_time(p_secs); +} + +float StreamPlayer::get_loop_restart_time() const { + + return loop_point; +} + + void StreamPlayer::set_volume_db(float p_db) { if (p_db<-79) @@ -161,31 +241,31 @@ String StreamPlayer::get_stream_name() const { int StreamPlayer::get_loop_count() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_loop_count(); + return playback->get_loop_count(); } float StreamPlayer::get_pos() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_pos(); + return playback->get_pos(); } float StreamPlayer::get_length() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_length(); + return playback->get_length(); } void StreamPlayer::seek_pos(float p_time) { - if (stream.is_null()) + if (playback.is_null()) return; - return stream->seek_pos(p_time); + return playback->seek_pos(p_time); } @@ -202,8 +282,8 @@ bool StreamPlayer::has_autoplay() const { void StreamPlayer::set_paused(bool p_paused) { paused=p_paused; - if (stream.is_valid()) - stream->set_paused(p_paused); + //if (stream.is_valid()) + // stream->set_paused(p_paused); } bool StreamPlayer::is_paused() const { @@ -228,6 +308,17 @@ bool StreamPlayer::_get_play() const{ return _play; } +void StreamPlayer::set_buffering_msec(int p_msec) { + + buffering_ms=p_msec; +} + +int StreamPlayer::get_buffering_msec() const{ + + return buffering_ms; +} + + void StreamPlayer::_bind_methods() { @@ -251,6 +342,12 @@ void StreamPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&StreamPlayer::set_volume_db); ObjectTypeDB::bind_method(_MD("get_volume_db"),&StreamPlayer::get_volume_db); + ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&StreamPlayer::set_buffering_msec); + ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&StreamPlayer::get_buffering_msec); + + ObjectTypeDB::bind_method(_MD("set_loop_restart_time","secs"),&StreamPlayer::set_loop_restart_time); + ObjectTypeDB::bind_method(_MD("get_loop_restart_time"),&StreamPlayer::get_loop_restart_time); + ObjectTypeDB::bind_method(_MD("get_stream_name"),&StreamPlayer::get_stream_name); ObjectTypeDB::bind_method(_MD("get_loop_count"),&StreamPlayer::get_loop_count); @@ -271,6 +368,8 @@ void StreamPlayer::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") ); + ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/loop_restart_time"), _SCS("set_loop_restart_time"), _SCS("get_loop_restart_time") ); + ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/buffering_ms"), _SCS("set_buffering_msec"), _SCS("get_buffering_msec") ); } @@ -281,10 +380,17 @@ StreamPlayer::StreamPlayer() { paused=false; autoplay=false; _play=false; + server_mix_rate=1; + internal_stream.player=this; + stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream); + buffering_ms=500; + loop_point=0; + } StreamPlayer::~StreamPlayer() { - if (stream_rid.is_valid()) - AudioServer::get_singleton()->free(stream_rid); + AudioServer::get_singleton()->free(stream_rid); + resampler.clear(); + } diff --git a/scene/audio/stream_player.h b/scene/audio/stream_player.h index 21e2162188..b5aa943067 100644 --- a/scene/audio/stream_player.h +++ b/scene/audio/stream_player.h @@ -31,17 +31,43 @@ #include "scene/resources/audio_stream.h" #include "scene/main/node.h" +#include "servers/audio/audio_rb_resampler.h" class StreamPlayer : public Node { OBJ_TYPE(StreamPlayer,Node); + _THREAD_SAFE_CLASS_ + + struct InternalStream : public AudioServer::AudioStream { + StreamPlayer *player; + virtual int get_channel_count() const; + virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate + virtual bool mix(int32_t *p_buffer,int p_frames); + virtual void update(); + }; + + + InternalStream internal_stream; + Ref<AudioStreamPlayback> playback; Ref<AudioStream> stream; + + int sp_get_channel_count() const; + void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate + bool sp_mix(int32_t *p_buffer,int p_frames); + void sp_update(); + + int server_mix_rate; + RID stream_rid; bool paused; bool autoplay; bool loops; float volume; + float loop_point; + int buffering_ms; + + AudioRBResampler resampler; bool _play; void _set_play(bool p_play); @@ -55,7 +81,7 @@ public: void set_stream(const Ref<AudioStream> &p_stream); Ref<AudioStream> get_stream() const; - void play(); + void play(float p_from_offset=0); void stop(); bool is_playing() const; @@ -68,6 +94,9 @@ public: void set_volume(float p_vol); float get_volume() const; + void set_loop_restart_time(float p_secs); + float get_loop_restart_time() const; + void set_volume_db(float p_db); float get_volume_db() const; @@ -81,6 +110,8 @@ public: void set_autoplay(bool p_vol); bool has_autoplay() const; + void set_buffering_msec(int p_msec); + int get_buffering_msec() const; StreamPlayer(); ~StreamPlayer(); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 3ddf23fc4a..0c0f924f52 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -274,7 +274,7 @@ Button* AcceptDialog::add_button(const String& p_text,bool p_right,const String& } if (p_action!="") { - button->connect("pressed",this,"_custom_action",make_binds(p_action)); + button->connect("pressed",this,"_custom_action",varray(p_action)); } return button; diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index c29f6625d3..b7b2f061ea 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -187,6 +187,7 @@ void ItemList::select(int p_idx,bool p_single){ } current=p_idx; + ensure_selected_visible=false; } else { if (items[p_idx].selectable) { @@ -195,6 +196,7 @@ void ItemList::select(int p_idx,bool p_single){ } update(); + } void ItemList::unselect(int p_idx){ @@ -246,12 +248,14 @@ void ItemList::remove_item(int p_idx){ update(); shape_changed=true; + } void ItemList::clear(){ items.clear(); current=-1; + ensure_selected_visible=false; update(); } @@ -602,18 +606,8 @@ void ItemList::_input_event(const InputEvent& p_event) { void ItemList::ensure_current_is_visible() { - if (current>=0 && current <=items.size()) { - - Rect2 r = items[current].rect_cache; - int from = scroll_bar->get_val(); - int to = from + scroll_bar->get_page(); - - if (r.pos.y < from) { - scroll_bar->set_val(r.pos.y); - } else if (r.pos.y+r.size.y > to) { - scroll_bar->set_val(r.pos.y+r.size.y - (to-from)); - } - } + ensure_selected_visible=true; + update(); } void ItemList::_notification(int p_what) { @@ -928,6 +922,24 @@ void ItemList::_notification(int p_what) { draw_line(Vector2(bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),Vector2(size.width-bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),guide_color); } + + if (ensure_selected_visible && current>=0 && current <=items.size()) { + + Rect2 r = items[current].rect_cache; + int from = scroll_bar->get_val(); + int to = from + scroll_bar->get_page(); + + if (r.pos.y < from) { + scroll_bar->set_val(r.pos.y); + } else if (r.pos.y+r.size.y > to) { + scroll_bar->set_val(r.pos.y+r.size.y - (to-from)); + } + + + } + + ensure_selected_visible=false; + } } @@ -1095,6 +1107,7 @@ ItemList::ItemList() { set_focus_mode(FOCUS_ALL); current_columns=1; search_time_msec=0; + ensure_selected_visible=false; } diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 237079c428..7cf58a6426 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -41,6 +41,8 @@ private: bool shape_changed; + bool ensure_selected_visible; + Vector<Item> items; Vector<int> separators; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 68fcb4bda8..13ff7074ea 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -124,7 +124,7 @@ void MenuButton::_set_items(const Array& p_items) { void MenuButton::_bind_methods() { - ObjectTypeDB::bind_method(_MD("get_popup"),&MenuButton::get_popup); + ObjectTypeDB::bind_method(_MD("get_popup:PopupMenu"),&MenuButton::get_popup); ObjectTypeDB::bind_method(_MD("_unhandled_key_input"),&MenuButton::_unhandled_key_input); ObjectTypeDB::bind_method(_MD("_set_items"),&MenuButton::_set_items); ObjectTypeDB::bind_method(_MD("_get_items"),&MenuButton::_get_items); diff --git a/scene/gui/patch_9_frame.cpp b/scene/gui/patch_9_frame.cpp new file mode 100644 index 0000000000..b6e261714c --- /dev/null +++ b/scene/gui/patch_9_frame.cpp @@ -0,0 +1,132 @@ +#include "patch_9_frame.h" + +#include "servers/visual_server.h" + +void Patch9Frame::_notification(int p_what) { + + if (p_what==NOTIFICATION_DRAW) { + + if (texture.is_null()) + return; + + + Size2 s=get_size(); + RID ci = get_canvas_item(); + VS::get_singleton()->canvas_item_add_style_box(ci,Rect2(Point2(),s),texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center,modulate); +// draw_texture_rect(texture,Rect2(Point2(),s),false,modulate); + +/* + Vector<Point2> points; + points.resize(4); + points[0]=Point2(0,0); + points[1]=Point2(s.x,0); + points[2]=Point2(s.x,s.y); + points[3]=Point2(0,s.y); + Vector<Point2> uvs; + uvs.resize(4); + uvs[0]=Point2(0,0); + uvs[1]=Point2(1,0); + uvs[2]=Point2(1,1); + uvs[3]=Point2(0,1); + + VisualServer::get_singleton()->canvas_item_add_primitive(ci,points,Vector<Color>(),uvs,texture->get_rid()); +*/ + } +} + +Size2 Patch9Frame::get_minimum_size() const { + + return Size2(margin[MARGIN_LEFT]+margin[MARGIN_RIGHT],margin[MARGIN_TOP]+margin[MARGIN_BOTTOM]); +} +void Patch9Frame::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_texture","texture"), & Patch9Frame::set_texture ); + ObjectTypeDB::bind_method(_MD("get_texture"), & Patch9Frame::get_texture ); + ObjectTypeDB::bind_method(_MD("set_modulate","modulate"), & Patch9Frame::set_modulate ); + ObjectTypeDB::bind_method(_MD("get_modulate"), & Patch9Frame::get_modulate ); + ObjectTypeDB::bind_method(_MD("set_patch_margin","margin","value"), & Patch9Frame::set_patch_margin ); + ObjectTypeDB::bind_method(_MD("get_patch_margin","margin"), & Patch9Frame::get_patch_margin ); + ObjectTypeDB::bind_method(_MD("set_draw_center","draw_center"), & Patch9Frame::set_draw_center ); + ObjectTypeDB::bind_method(_MD("get_draw_center"), & Patch9Frame::get_draw_center ); + + ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") ); + ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") ); + ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "draw_center"), _SCS("set_draw_center"),_SCS("get_draw_center") ); + ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/left",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_LEFT ); + ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/top",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_TOP ); + ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/right",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_RIGHT ); + ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/bottom",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_BOTTOM ); + +} + + +void Patch9Frame::set_texture(const Ref<Texture>& p_tex) { + + texture=p_tex; + update(); + //if (texture.is_valid()) + // texture->set_flags(texture->get_flags()&(~Texture::FLAG_REPEAT)); //remove repeat from texture, it looks bad in sprites + minimum_size_changed(); +} + +Ref<Texture> Patch9Frame::get_texture() const { + + return texture; +} + +void Patch9Frame::set_modulate(const Color& p_tex) { + + modulate=p_tex; + update(); +} + +Color Patch9Frame::get_modulate() const{ + + return modulate; +} + + +void Patch9Frame::set_patch_margin(Margin p_margin,int p_size) { + + ERR_FAIL_INDEX(p_margin,4); + margin[p_margin]=p_size; + update(); + minimum_size_changed(); +} + +int Patch9Frame::get_patch_margin(Margin p_margin) const{ + + ERR_FAIL_INDEX_V(p_margin,4,0); + return margin[p_margin]; +} + +void Patch9Frame::set_draw_center(bool p_draw) { + + draw_center=p_draw; + update(); +} + +bool Patch9Frame::get_draw_center() const{ + + return draw_center; +} + +Patch9Frame::Patch9Frame() { + + + margin[MARGIN_LEFT]=0; + margin[MARGIN_RIGHT]=0; + margin[MARGIN_BOTTOM]=0; + margin[MARGIN_TOP]=0; + modulate=Color(1,1,1,1); + set_ignore_mouse(true); + draw_center=true; +} + + +Patch9Frame::~Patch9Frame() +{ +} + + diff --git a/scene/gui/patch_9_frame.h b/scene/gui/patch_9_frame.h new file mode 100644 index 0000000000..562a5b1d77 --- /dev/null +++ b/scene/gui/patch_9_frame.h @@ -0,0 +1,40 @@ +#ifndef PATCH_9_FRAME_H +#define PATCH_9_FRAME_H + +#include "scene/gui/control.h" +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class Patch9Frame : public Control { + + OBJ_TYPE(Patch9Frame,Control); + + bool draw_center; + int margin[4]; + Color modulate; + Ref<Texture> texture; +protected: + + void _notification(int p_what); + virtual Size2 get_minimum_size() const; + static void _bind_methods(); + +public: + + void set_texture(const Ref<Texture>& p_tex); + Ref<Texture> get_texture() const; + + void set_modulate(const Color& p_tex); + Color get_modulate() const; + + void set_patch_margin(Margin p_margin,int p_size); + int get_patch_margin(Margin p_margin) const; + + void set_draw_center(bool p_enable); + bool get_draw_center() const; + + Patch9Frame(); + ~Patch9Frame(); + +}; +#endif // PATCH_9_FRAME_H diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 41e775bbff..a48136f541 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -27,7 +27,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "spin_box.h" - +#include "os/input.h" Size2 SpinBox::get_minimum_size() const { @@ -62,6 +62,13 @@ LineEdit *SpinBox::get_line_edit() { } +void SpinBox::_line_edit_input(const InputEvent& p_event) { + + + +} + + void SpinBox::_input_event(const InputEvent& p_event) { if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed) { @@ -94,6 +101,48 @@ void SpinBox::_input_event(const InputEvent& p_event) { } break; } } + + if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) { + + //set_default_cursor_shape(CURSOR_VSIZE); + Vector2 cpos = Vector2(p_event.mouse_button.x,p_event.mouse_button.y); + drag.mouse_pos=cpos; + } + + if (p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) { + + //set_default_cursor_shape(CURSOR_ARROW); + if (drag.enabled) { + drag.enabled=false; + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + warp_mouse(drag.capture_pos); + } + } + + if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_button.button_mask&1) { + + Vector2 cpos = Vector2(p_event.mouse_motion.x,p_event.mouse_motion.y); + if (drag.enabled) { + + float diff_y = drag.mouse_pos.y - cpos.y; + diff_y=Math::pow(ABS(diff_y),1.8)*SGN(diff_y); + diff_y*=0.1; + + drag.mouse_pos=cpos; + drag.base_val=CLAMP(drag.base_val + get_step() * diff_y, get_min(), get_max()); + + set_val( drag.base_val); + + } else if (drag.mouse_pos.distance_to(cpos)>2) { + + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); + drag.enabled=true; + drag.base_val=get_val(); + drag.mouse_pos=cpos; + drag.capture_pos=cpos; + + } + } } @@ -177,6 +226,7 @@ void SpinBox::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_editable"),&SpinBox::is_editable); ObjectTypeDB::bind_method(_MD("_line_edit_focus_exit"),&SpinBox::_line_edit_focus_exit); ObjectTypeDB::bind_method(_MD("get_line_edit"),&SpinBox::get_line_edit); + ObjectTypeDB::bind_method(_MD("_line_edit_input"),&SpinBox::_line_edit_input); ADD_PROPERTY(PropertyInfo(Variant::BOOL,"editable"),_SCS("set_editable"),_SCS("is_editable")); @@ -196,4 +246,6 @@ SpinBox::SpinBox() { //connect("value_changed",this,"_value_changed"); line_edit->connect("text_entered",this,"_text_entered",Vector<Variant>(),CONNECT_DEFERRED); line_edit->connect("focus_exit",this,"_line_edit_focus_exit",Vector<Variant>(),CONNECT_DEFERRED); + line_edit->connect("input_event",this,"_line_edit_input"); + drag.enabled=false; } diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 6ebe14631e..4c8cb8432a 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -44,6 +44,18 @@ class SpinBox : public Range { String prefix; String suffix; + void _line_edit_input(const InputEvent& p_event); + + + struct Drag { + float base_val; + bool enabled; + Vector2 from; + Vector2 mouse_pos; + Vector2 capture_pos; + } drag; + + void _line_edit_focus_exit(); protected: diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 6c15f1cae4..e639b5cb05 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -31,7 +31,7 @@ #include "os/os.h" #include "os/keyboard.h" #include "globals.h" - +#include "os/input.h" @@ -70,6 +70,7 @@ Size2 TreeItem::Cell::get_icon_size() const { else return icon_region.size; } + void TreeItem::Cell::draw_icon(const RID& p_where, const Point2& p_pos, const Size2& p_size) const{ if (icon.is_null()) @@ -728,14 +729,20 @@ TreeItem::~TreeItem() { tree->root=0; } - if (tree && tree->popup_edited_item==this) + if (tree && tree->popup_edited_item==this) { tree->popup_edited_item=NULL; + tree->pressing_for_editor=false; + + } if (tree && tree->selected_item==this) tree->selected_item=NULL; - if (tree && tree->edited_item==this) + if (tree && tree->edited_item==this) { tree->edited_item=NULL; + tree->pressing_for_editor=false; + } + } @@ -1292,7 +1299,7 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col } else if (select_mode==SELECT_SINGLE || select_mode==SELECT_MULTI) { - if (&selected_cell==&c) { + if (!r_in_range && &selected_cell==&c) { if (!selected_cell.selected) { @@ -1301,6 +1308,7 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col selected_item=p_selected; selected_col=i; + emit_signal("cell_selected"); if (select_mode==SELECT_MULTI) emit_signal("multi_selected",p_current,i,true); @@ -1317,6 +1325,7 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col if (r_in_range && *r_in_range) { + if (!c.selected && c.selectable) { c.selected=true; emit_signal("multi_selected",p_current,i,true); @@ -1467,7 +1476,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ if (select_mode==SELECT_MULTI && p_mod.shift && selected_item && selected_item!=p_item) { bool inrange=false; - print_line("SELECT MULTI AND SHIFT AND ALL"); + select_single_item( p_item, root, col,selected_item,&inrange ); } else { select_single_item( p_item, root, col ); @@ -1490,7 +1499,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ /* editing */ - bool bring_up_editor=c.selected && already_selected; + bool bring_up_editor=c.selected;// && already_selected; bool bring_up_value_editor=false; String editor_text=c.text; @@ -1605,31 +1614,14 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ return -1; - click_handled=true; + + click_handled=true; popup_edited_item=p_item; popup_edited_item_col=col; - text_editor->set_pos(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset ); - text_editor->set_size( Size2(col_width,item_h)); - text_editor->clear(); - text_editor->set_text( editor_text ); - text_editor->select_all(); - if (bring_up_value_editor) { - - value_editor->set_pos(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset+Point2i(0,text_editor->get_size().height) ); - value_editor->set_size( Size2(col_width,1)); - value_editor->show_modal(); - updating_value_editor=true; - value_editor->set_min( c.min ); - value_editor->set_max( c.max ); - value_editor->set_step( c.step ); - value_editor->set_val( c.val ); - value_editor->set_exp_unit_value( c.expr ); - updating_value_editor=false; - } - - text_editor->show_modal(); - text_editor->grab_focus(); + pressing_item_rect=Rect2(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset,Size2(col_width,item_h)); + pressing_for_editor_text=editor_text; + pressing_for_editor=true; return -1; //select } else { @@ -2062,6 +2054,33 @@ void Tree::_input_event(InputEvent p_event) { update(); } + if (pressing_for_editor && popup_edited_item && popup_edited_item->get_cell_mode(popup_edited_item_col)==TreeItem::CELL_MODE_RANGE) { + //range drag + + if (!range_drag_enabled) { + + Vector2 cpos = Vector2(b.x,b.y); + if (cpos.distance_to(pressing_pos)>2) { + range_drag_enabled=true; + range_drag_capture_pos=cpos; + range_drag_base=popup_edited_item->get_range(popup_edited_item_col); + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); + } + } else { + + TreeItem::Cell &c=popup_edited_item->cells[popup_edited_item_col]; + float diff_y = -b.relative_y; + diff_y=Math::pow(ABS(diff_y),1.8)*SGN(diff_y); + diff_y*=0.1; + range_drag_base=CLAMP(range_drag_base + c.step * diff_y, c.min, c.max); + + popup_edited_item->set_range(popup_edited_item_col,range_drag_base); + item_edited(popup_edited_item_col,popup_edited_item); + + } + + } + if (drag_touching && ! drag_touching_deaccel) { @@ -2084,6 +2103,31 @@ void Tree::_input_event(InputEvent p_event) { if (b.button_index==BUTTON_LEFT) { + if (pressing_for_editor) { + + if (range_drag_enabled) { + + range_drag_enabled=false; + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + warp_mouse(range_drag_capture_pos); + } else { + text_editor->set_pos(pressing_item_rect.pos); + text_editor->set_size(pressing_item_rect.size); + + text_editor->clear(); + text_editor->set_text( pressing_for_editor_text ); + text_editor->select_all(); + + text_editor->show_modal(); + text_editor->grab_focus(); + + } + pressing_for_editor=false; + + } + + + if (cache.click_type==Cache::CLICK_BUTTON) { emit_signal("button_pressed",cache.click_item,cache.click_column,cache.click_id); @@ -2145,11 +2189,15 @@ void Tree::_input_event(InputEvent p_event) { break; click_handled=false; + pressing_for_editor=false; blocked++; bool handled = propagate_mouse_event(pos+cache.offset,0,0,b.doubleclick,root,b.button_index,b.mod); blocked--; + if (pressing_for_editor) { + pressing_pos=Point2(b.x,b.y); + } if (drag_touching) { @@ -2360,6 +2408,11 @@ void Tree::_notification(int p_what) { } } + if (p_what==NOTIFICATION_VISIBILITY_CHANGED) { + + drag_touching=false; + } + if (p_what==NOTIFICATION_ENTER_TREE) { update_cache();; @@ -2610,6 +2663,8 @@ void Tree::clear() { selected_item=NULL; edited_item=NULL; popup_edited_item=NULL; + selected_item=NULL; + pressing_for_editor=false; update(); }; @@ -3184,6 +3239,8 @@ Tree::Tree() { drag_speed=0; drag_touching=false; drag_touching_deaccel=false; + pressing_for_editor=false; + range_drag_enabled=false; } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 8ddddd0630..3fbd7c95d9 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -258,7 +258,18 @@ friend class TreeItem; TreeItem *popup_edited_item; TreeItem *selected_item; TreeItem *edited_item; + + int pressed_button; + bool pressing_for_editor; + String pressing_for_editor_text; + Vector2 pressing_pos; + Rect2 pressing_item_rect; + + float range_drag_base; + bool range_drag_enabled; + Vector2 range_drag_capture_pos; + //TreeItem *cursor_item; //int cursor_column; diff --git a/scene/io/resource_format_image.cpp b/scene/io/resource_format_image.cpp index 8527498fc2..f67d50b56c 100644 --- a/scene/io/resource_format_image.cpp +++ b/scene/io/resource_format_image.cpp @@ -31,9 +31,11 @@ #include "io/image_loader.h" #include "globals.h" #include "os/os.h" -RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_original_path) { - +RES ResourceFormatLoaderImage::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; + if (p_path.extension()=="cube") { // open as cubemap txture @@ -83,6 +85,8 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina memdelete(f); cubemap->set_name(p_path.get_file()); + if (r_error) + *r_error=OK; return cubemap; @@ -112,6 +116,8 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina ERR_EXPLAIN("Failed loading image: "+p_path); ERR_FAIL_COND_V(err, RES()); + if (r_error) + *r_error=ERR_FILE_CORRUPT; #ifdef DEBUG_ENABLED #ifdef TOOLS_ENABLED @@ -199,6 +205,9 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina print_line(" -make texture: "+rtos(total)); } + if (r_error) + *r_error=OK; + return RES( texture ); } diff --git a/scene/io/resource_format_image.h b/scene/io/resource_format_image.h index 1af65870f8..b5ec5a1200 100644 --- a/scene/io/resource_format_image.h +++ b/scene/io/resource_format_image.h @@ -40,7 +40,7 @@ class ResourceFormatLoaderImage : public ResourceFormatLoader { int max_texture_size; public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/io/resource_format_wav.cpp b/scene/io/resource_format_wav.cpp index 7c90a4b3cd..090348c933 100644 --- a/scene/io/resource_format_wav.cpp +++ b/scene/io/resource_format_wav.cpp @@ -31,13 +31,18 @@ #include "scene/resources/sample.h" -RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderWAV::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; Error err; FileAccess *file=FileAccess::open(p_path, FileAccess::READ,&err); ERR_FAIL_COND_V( err!=OK, RES() ); + if (r_error) + *r_error=ERR_FILE_CORRUPT; + /* CHECK RIFF */ char riff[5]; riff[4]=0; @@ -244,6 +249,9 @@ RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_ file->close(); memdelete(file); + if (r_error) + *r_error=OK; + return sample; } diff --git a/scene/io/resource_format_wav.h b/scene/io/resource_format_wav.h index 081a563d03..a74da041c1 100644 --- a/scene/io/resource_format_wav.h +++ b/scene/io/resource_format_wav.h @@ -33,7 +33,7 @@ class ResourceFormatLoaderWAV : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 717ed93b16..851de4a89f 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -52,6 +52,7 @@ #include "scene/gui/option_button.h" #include "scene/gui/color_picker.h" #include "scene/gui/texture_frame.h" +#include "scene/gui/patch_9_frame.h" #include "scene/gui/menu_button.h" #include "scene/gui/check_box.h" #include "scene/gui/check_button.h" @@ -302,6 +303,7 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init ObjectTypeDB::register_type<TextureFrame>(); + ObjectTypeDB::register_type<Patch9Frame>(); ObjectTypeDB::register_type<TabContainer>(); ObjectTypeDB::register_type<Tabs>(); ObjectTypeDB::register_virtual_type<Separator>(); @@ -456,7 +458,6 @@ void register_scene_types() { /* disable types by default, only editors should enable them */ - ObjectTypeDB::set_type_enabled("CollisionShape",false); //ObjectTypeDB::set_type_enabled("BodyVolumeSphere",false); //ObjectTypeDB::set_type_enabled("BodyVolumeBox",false); //ObjectTypeDB::set_type_enabled("BodyVolumeCapsule",false); @@ -490,9 +491,12 @@ void register_scene_types() { ObjectTypeDB::register_type<OccluderPolygon2D>(); ObjectTypeDB::register_type<YSort>(); ObjectTypeDB::register_type<BackBufferCopy>(); - - ObjectTypeDB::set_type_enabled("CollisionShape2D",false); - ObjectTypeDB::set_type_enabled("CollisionPolygon2D",false); + if (bool(GLOBAL_DEF("physics/remove_collision_helpers_at_runtime",false))) { + ObjectTypeDB::set_type_enabled("CollisionShape2D",false); + ObjectTypeDB::set_type_enabled("CollisionPolygon2D",false); + ObjectTypeDB::set_type_enabled("CollisionShape",false); + ObjectTypeDB::set_type_enabled("CollisionPolygon",false); + } OS::get_singleton()->yield(); //may take time to init @@ -576,7 +580,8 @@ void register_scene_types() { ObjectTypeDB::register_type<Sample>(); ObjectTypeDB::register_type<SampleLibrary>(); ObjectTypeDB::register_virtual_type<AudioStream>(); - ObjectTypeDB::register_type<AudioStreamGibberish>(); + ObjectTypeDB::register_virtual_type<AudioStreamPlayback>(); +// ObjectTypeDB::register_type<AudioStreamGibberish>(); ObjectTypeDB::register_virtual_type<VideoStream>(); OS::get_singleton()->yield(); //may take time to init diff --git a/scene/resources/audio_stream.cpp b/scene/resources/audio_stream.cpp index 7694b8ef79..569ed8620d 100644 --- a/scene/resources/audio_stream.cpp +++ b/scene/resources/audio_stream.cpp @@ -28,76 +28,34 @@ /*************************************************************************/ #include "audio_stream.h" +////////////////////////////// -int AudioStream::InternalAudioStream::get_channel_count() const { +void AudioStreamPlayback::_bind_methods() { - return owner->get_channel_count(); + ObjectTypeDB::bind_method(_MD("play","from_pos_sec"),&AudioStreamPlayback::play,DEFVAL(0)); + ObjectTypeDB::bind_method(_MD("stop"),&AudioStreamPlayback::stop); + ObjectTypeDB::bind_method(_MD("is_playing"),&AudioStreamPlayback::is_playing); -} - -void AudioStream::InternalAudioStream::set_mix_rate(int p_rate) { - - owner->_mix_rate=p_rate; -} - -bool AudioStream::InternalAudioStream::mix(int32_t *p_buffer,int p_frames) { - - return owner->mix(p_buffer,p_frames); -} - -bool AudioStream::InternalAudioStream::can_update_mt() const { + ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&AudioStreamPlayback::set_loop); + ObjectTypeDB::bind_method(_MD("has_loop"),&AudioStreamPlayback::has_loop); - return owner->get_update_mode()==UPDATE_THREAD; -} + ObjectTypeDB::bind_method(_MD("get_loop_count"),&AudioStreamPlayback::get_loop_count); -void AudioStream::InternalAudioStream::update() { + ObjectTypeDB::bind_method(_MD("seek_pos","pos"),&AudioStreamPlayback::seek_pos); + ObjectTypeDB::bind_method(_MD("get_pos"),&AudioStreamPlayback::get_pos); - owner->update(); -} + ObjectTypeDB::bind_method(_MD("get_length"),&AudioStreamPlayback::get_length); + ObjectTypeDB::bind_method(_MD("get_channels"),&AudioStreamPlayback::get_channels); + ObjectTypeDB::bind_method(_MD("get_mix_rate"),&AudioStreamPlayback::get_mix_rate); + ObjectTypeDB::bind_method(_MD("get_minimum_buffer_size"),&AudioStreamPlayback::get_minimum_buffer_size); -AudioServer::AudioStream *AudioStream::get_audio_stream() { - return internal_audio_stream; } void AudioStream::_bind_methods() { - ObjectTypeDB::bind_method(_MD("play"),&AudioStream::play); - ObjectTypeDB::bind_method(_MD("stop"),&AudioStream::stop); - ObjectTypeDB::bind_method(_MD("is_playing"),&AudioStream::is_playing); - - ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&AudioStream::set_loop); - ObjectTypeDB::bind_method(_MD("has_loop"),&AudioStream::has_loop); - - ObjectTypeDB::bind_method(_MD("get_stream_name"),&AudioStream::get_stream_name); - ObjectTypeDB::bind_method(_MD("get_loop_count"),&AudioStream::get_loop_count); - - ObjectTypeDB::bind_method(_MD("seek_pos","pos"),&AudioStream::seek_pos); - ObjectTypeDB::bind_method(_MD("get_pos"),&AudioStream::get_pos); - - ObjectTypeDB::bind_method(_MD("get_length"),&AudioStream::get_length); - - ObjectTypeDB::bind_method(_MD("get_update_mode"),&AudioStream::get_update_mode); - - ObjectTypeDB::bind_method(_MD("update"),&AudioStream::update); - - BIND_CONSTANT( UPDATE_NONE ); - BIND_CONSTANT( UPDATE_IDLE ); - BIND_CONSTANT( UPDATE_THREAD ); } -AudioStream::AudioStream() { - - _mix_rate=44100; - internal_audio_stream = memnew( InternalAudioStream ); - internal_audio_stream->owner=this; -} - - -AudioStream::~AudioStream() { - - memdelete(internal_audio_stream); -} diff --git a/scene/resources/audio_stream.h b/scene/resources/audio_stream.h index df33b64a4b..b16e62b8c7 100644 --- a/scene/resources/audio_stream.h +++ b/scene/resources/audio_stream.h @@ -31,72 +31,53 @@ #include "resource.h" #include "servers/audio_server.h" -#include "scene/resources/audio_stream.h" - -class AudioStream : public Resource { - - OBJ_TYPE( AudioStream, Resource ); - OBJ_SAVE_TYPE( AudioStream ); //children are all saved as AudioStream, so they can be exchanged - - friend class InternalAudioStream; - - struct InternalAudioStream : public AudioServer::AudioStream { - - ::AudioStream *owner; - virtual int get_channel_count() const; - virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate - virtual bool mix(int32_t *p_buffer,int p_frames); - virtual bool can_update_mt() const; - virtual void update(); - }; +class AudioStreamPlayback : public Reference { - int _mix_rate; - InternalAudioStream *internal_audio_stream; + OBJ_TYPE( AudioStreamPlayback, Reference ); protected: - - _FORCE_INLINE_ int get_mix_rate() const { return _mix_rate; } - virtual int get_channel_count() const=0; - virtual bool mix(int32_t *p_buffer, int p_frames)=0; - static void _bind_methods(); public: - enum UpdateMode { - UPDATE_NONE, - UPDATE_IDLE, - UPDATE_THREAD - }; - AudioServer::AudioStream *get_audio_stream(); - - virtual void play()=0; + virtual void play(float p_from_pos=0)=0; virtual void stop()=0; virtual bool is_playing() const=0; - virtual void set_paused(bool p_paused)=0; - virtual bool is_paused(bool p_paused) const=0; - virtual void set_loop(bool p_enable)=0; virtual bool has_loop() const=0; - virtual float get_length() const=0; - - virtual String get_stream_name() const=0; + virtual void set_loop_restart_time(float p_time)=0; virtual int get_loop_count() const=0; virtual float get_pos() const=0; virtual void seek_pos(float p_time)=0; - virtual UpdateMode get_update_mode() const=0; - virtual void update()=0; + virtual int mix(int16_t* p_bufer,int p_frames)=0; + + virtual float get_length() const=0; + virtual String get_stream_name() const=0; + + virtual int get_channels() const=0; + virtual int get_mix_rate() const=0; + virtual int get_minimum_buffer_size() const=0; - AudioStream(); - ~AudioStream(); }; +class AudioStream : public Resource { + + OBJ_TYPE( AudioStream, Resource ); + OBJ_SAVE_TYPE( AudioStream ); //children are all saved as AudioStream, so they can be exchanged + +protected: + static void _bind_methods(); +public: + + virtual Ref<AudioStreamPlayback> instance_playback()=0; + + +}; -VARIANT_ENUM_CAST( AudioStream::UpdateMode ); #endif // AUDIO_STREAM_H diff --git a/scene/resources/audio_stream_resampled.cpp b/scene/resources/audio_stream_resampled.cpp index 6317780bd3..edbca60bd3 100644 --- a/scene/resources/audio_stream_resampled.cpp +++ b/scene/resources/audio_stream_resampled.cpp @@ -28,6 +28,9 @@ /*************************************************************************/ #include "audio_stream_resampled.h" #include "globals.h" + + +#if 0 int AudioStreamResampled::get_channel_count() const { if (!rb) @@ -382,3 +385,4 @@ AudioStreamResampled::~AudioStreamResampled() { } +#endif diff --git a/scene/resources/audio_stream_resampled.h b/scene/resources/audio_stream_resampled.h index 33cfb17e3f..570c311878 100644 --- a/scene/resources/audio_stream_resampled.h +++ b/scene/resources/audio_stream_resampled.h @@ -31,6 +31,7 @@ #include "scene/resources/audio_stream.h" +#if 0 class AudioStreamResampled : public AudioStream { OBJ_TYPE(AudioStreamResampled,AudioStream); @@ -160,5 +161,5 @@ public: AudioStreamResampled(); ~AudioStreamResampled(); }; - +#endif #endif // AUDIO_STREAM_RESAMPLED_H diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp index ef056a6230..9a6452797a 100644 --- a/scene/resources/bit_mask.cpp +++ b/scene/resources/bit_mask.cpp @@ -205,7 +205,10 @@ BitMap::BitMap() { ////////////////////////////////////// -RES ResourceFormatLoaderBitMap::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderBitMap::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; BitMap* ptr = memnew(BitMap); Ref<BitMap> bitmap( ptr ); @@ -219,6 +222,8 @@ RES ResourceFormatLoaderBitMap::load(const String &p_path,const String& p_origin ERR_FAIL_COND_V(err, RES()); bitmap->create_from_image_alpha(image); + if (r_error) + *r_error=OK; return bitmap; diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h index 29b7bc66f4..a6b29bb919 100644 --- a/scene/resources/bit_mask.h +++ b/scene/resources/bit_mask.h @@ -66,7 +66,7 @@ class ResourceFormatLoaderBitMap : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index cd0e67f04d..f1e97fd626 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -297,7 +297,7 @@ void make_default_theme() { t->set_color("font_color_hover","MenuButton", control_font_color_hover ); t->set_color("font_color_disabled","MenuButton", Color(1,1,1,0.3) ); - t->set_constant("hseparation","MenuButton", 0 ); + t->set_constant("hseparation","MenuButton", 3 ); // CheckBox diff --git a/scene/resources/gibberish_stream.cpp b/scene/resources/gibberish_stream.cpp index 23b94c8f38..7af81bd992 100644 --- a/scene/resources/gibberish_stream.cpp +++ b/scene/resources/gibberish_stream.cpp @@ -29,6 +29,8 @@ #include "gibberish_stream.h" #include "servers/audio_server.h" +#if 0 + int AudioStreamGibberish::get_channel_count() const { return 1; @@ -328,3 +330,4 @@ AudioStreamGibberish::AudioStreamGibberish() { paused=false; active_voices=0; } +#endif diff --git a/scene/resources/gibberish_stream.h b/scene/resources/gibberish_stream.h index a52e629f83..77393db9f4 100644 --- a/scene/resources/gibberish_stream.h +++ b/scene/resources/gibberish_stream.h @@ -29,7 +29,7 @@ #ifndef GIBBERISH_STREAM_H #define GIBBERISH_STREAM_H - +#if 0 #include "scene/resources/audio_stream.h" #include "scene/resources/sample_library.h" class AudioStreamGibberish : public AudioStream { @@ -109,4 +109,6 @@ public: AudioStreamGibberish(); }; +#endif + #endif // GIBBERISH_STREAM_H diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 90598ee789..a9376faf62 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -219,7 +219,10 @@ Shader::~Shader() { -RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderShader::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; String fragment_code; String vertex_code; @@ -235,6 +238,8 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin ERR_FAIL_COND_V(err,RES()); String base_path = p_path.get_base_dir(); + if (r_error) + *r_error=ERR_FILE_CORRUPT; Ref<Shader> shader;//( memnew( Shader ) ); @@ -435,6 +440,8 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin f->close(); memdelete(f); + if (r_error) + *r_error=OK; return shader; } diff --git a/scene/resources/shader.h b/scene/resources/shader.h index b805cbec96..61a369c408 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -126,7 +126,7 @@ public: class ResourceFormatLoaderShader : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 3060fe41b4..651e234b49 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -601,7 +601,9 @@ Theme::~Theme() -RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderTheme::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -611,6 +613,8 @@ RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_origina String base_path = p_path.get_base_dir(); Ref<Theme> theme( memnew( Theme ) ); Map<StringName,Variant> library; + if (r_error) + *r_error=ERR_FILE_CORRUPT; bool reading_library=false; int line=0; @@ -1003,6 +1007,9 @@ RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_origina f->close(); memdelete(f); + if (r_error) + *r_error=OK; + return theme; } diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 802dcb099c..cfa0762595 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -124,7 +124,7 @@ public: class ResourceFormatLoaderTheme : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp new file mode 100644 index 0000000000..d07d55f1b5 --- /dev/null +++ b/servers/audio/audio_rb_resampler.cpp @@ -0,0 +1,356 @@ +#include "audio_rb_resampler.h" + + +int AudioRBResampler::get_channel_count() const { + + if (!rb) + return 0; + + return channels; +} + + +template<int C> +uint32_t AudioRBResampler::_resample(int32_t *p_dest,int p_todo,int32_t p_increment) { + + uint32_t read=offset&MIX_FRAC_MASK; + + for (int i=0;i<p_todo;i++) { + + offset = (offset + p_increment)&(((1<<(rb_bits+MIX_FRAC_BITS))-1)); + read+=p_increment; + uint32_t pos = offset >> MIX_FRAC_BITS; + uint32_t frac = offset & MIX_FRAC_MASK; +#ifndef FAST_AUDIO + ERR_FAIL_COND_V(pos>=rb_len,0); +#endif + uint32_t pos_next = (pos+1)&rb_mask; + //printf("rb pos %i\n",pos); + + // since this is a template with a known compile time value (C), conditionals go away when compiling. + if (C==1) { + + int32_t v0 = rb[pos]; + int32_t v0n=rb[pos_next]; +#ifndef FAST_AUDIO + v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS; +#endif + v0<<=16; + p_dest[i]=v0; + + } + if (C==2) { + + int32_t v0 = rb[(pos<<1)+0]; + int32_t v1 = rb[(pos<<1)+1]; + int32_t v0n=rb[(pos_next<<1)+0]; + int32_t v1n=rb[(pos_next<<1)+1]; + +#ifndef FAST_AUDIO + v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS; + v1+=(v1n-v1)*(int32_t)frac >> MIX_FRAC_BITS; +#endif + v0<<=16; + v1<<=16; + p_dest[(i<<1)+0]=v0; + p_dest[(i<<1)+1]=v1; + + } + + if (C==4) { + + int32_t v0 = rb[(pos<<2)+0]; + int32_t v1 = rb[(pos<<2)+1]; + int32_t v2 = rb[(pos<<2)+2]; + int32_t v3 = rb[(pos<<2)+3]; + int32_t v0n = rb[(pos_next<<2)+0]; + int32_t v1n=rb[(pos_next<<2)+1]; + int32_t v2n=rb[(pos_next<<2)+2]; + int32_t v3n=rb[(pos_next<<2)+3]; + +#ifndef FAST_AUDIO + v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS; + v1+=(v1n-v1)*(int32_t)frac >> MIX_FRAC_BITS; + v2+=(v2n-v2)*(int32_t)frac >> MIX_FRAC_BITS; + v3+=(v3n-v3)*(int32_t)frac >> MIX_FRAC_BITS; +#endif + v0<<=16; + v1<<=16; + v2<<=16; + v3<<=16; + p_dest[(i<<2)+0]=v0; + p_dest[(i<<2)+1]=v1; + p_dest[(i<<2)+2]=v2; + p_dest[(i<<2)+3]=v3; + + } + + if (C==6) { + + int32_t v0 = rb[(pos*6)+0]; + int32_t v1 = rb[(pos*6)+1]; + int32_t v2 = rb[(pos*6)+2]; + int32_t v3 = rb[(pos*6)+3]; + int32_t v4 = rb[(pos*6)+4]; + int32_t v5 = rb[(pos*6)+5]; + int32_t v0n = rb[(pos_next*6)+0]; + int32_t v1n=rb[(pos_next*6)+1]; + int32_t v2n=rb[(pos_next*6)+2]; + int32_t v3n=rb[(pos_next*6)+3]; + int32_t v4n=rb[(pos_next*6)+4]; + int32_t v5n=rb[(pos_next*6)+5]; + +#ifndef FAST_AUDIO + v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS; + v1+=(v1n-v1)*(int32_t)frac >> MIX_FRAC_BITS; + v2+=(v2n-v2)*(int32_t)frac >> MIX_FRAC_BITS; + v3+=(v3n-v3)*(int32_t)frac >> MIX_FRAC_BITS; + v4+=(v4n-v4)*(int32_t)frac >> MIX_FRAC_BITS; + v5+=(v5n-v5)*(int32_t)frac >> MIX_FRAC_BITS; +#endif + v0<<=16; + v1<<=16; + v2<<=16; + v3<<=16; + v4<<=16; + v5<<=16; + p_dest[(i*6)+0]=v0; + p_dest[(i*6)+1]=v1; + p_dest[(i*6)+2]=v2; + p_dest[(i*6)+3]=v3; + p_dest[(i*6)+4]=v4; + p_dest[(i*6)+5]=v5; + + } + + + } + + + return read>>MIX_FRAC_BITS;//rb_read_pos=offset>>MIX_FRAC_BITS; + +} + + +bool AudioRBResampler::mix(int32_t *p_dest, int p_frames) { + + + if (!rb) + return false; + + int write_pos_cache=rb_write_pos; + + int32_t increment=(src_mix_rate*MIX_FRAC_LEN)/target_mix_rate; + + int rb_todo; + + if (write_pos_cache==rb_read_pos) { + return false; //out of buffer + + } else if (rb_read_pos<write_pos_cache) { + + rb_todo=write_pos_cache-rb_read_pos; //-1? + } else { + + rb_todo=(rb_len-rb_read_pos)+write_pos_cache; //-1? + } + + int todo = MIN( ((int64_t(rb_todo)<<MIX_FRAC_BITS)/increment)+1, p_frames ); +#if 0 + if (int(src_mix_rate)==target_mix_rate) { + + + if (channels==6) { + + for(int i=0;i<p_frames;i++) { + + int from = ((rb_read_pos+i)&rb_mask)*6; + int to = i*6; + + p_dest[from+0]=int32_t(rb[to+0])<<16; + p_dest[from+1]=int32_t(rb[to+1])<<16; + p_dest[from+2]=int32_t(rb[to+2])<<16; + p_dest[from+3]=int32_t(rb[to+3])<<16; + p_dest[from+4]=int32_t(rb[to+4])<<16; + p_dest[from+5]=int32_t(rb[to+5])<<16; + } + + } else { + int len=p_frames*channels; + int from=rb_read_pos*channels; + int mask=0; + switch(channels) { + case 1: mask=rb_len-1; break; + case 2: mask=(rb_len*2)-1; break; + case 4: mask=(rb_len*4)-1; break; + } + + for(int i=0;i<len;i++) { + + p_dest[i]=int32_t(rb[(from+i)&mask])<<16; + } + } + + rb_read_pos = (rb_read_pos+p_frames)&rb_mask; + } else +#endif + { + + uint32_t read=0; + switch(channels) { + case 1: read=_resample<1>(p_dest,todo,increment); break; + case 2: read=_resample<2>(p_dest,todo,increment); break; + 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; + + rb_read_pos = (rb_read_pos+read)&rb_mask; + + + + + } + + return true; +} + + +Error AudioRBResampler::setup(int p_channels,int p_src_mix_rate,int p_target_mix_rate,int p_buffer_msec,int p_minbuff_needed) { + + ERR_FAIL_COND_V(p_channels!=1 && p_channels!=2 && p_channels!=4 && p_channels!=6,ERR_INVALID_PARAMETER); + + + //float buffering_sec = int(GLOBAL_DEF("audio/stream_buffering_ms",500))/1000.0; + int desired_rb_bits =nearest_shift(MAX((p_buffer_msec/1000.0)*p_src_mix_rate,p_minbuff_needed)); + + bool recreate=!rb; + + if (rb && (uint32_t(desired_rb_bits)!=rb_bits || channels!=uint32_t(p_channels))) { + //recreate + + memdelete_arr(rb); + memdelete_arr(read_buf); + recreate=true; + + } + + if (recreate) { + + channels=p_channels; + rb_bits=desired_rb_bits; + rb_len=(1<<rb_bits); + rb_mask=rb_len-1; + rb = memnew_arr( int16_t, rb_len * p_channels ); + read_buf = memnew_arr( int16_t, rb_len * p_channels ); + + } + + src_mix_rate=p_src_mix_rate; + target_mix_rate=p_target_mix_rate; + offset=0; + rb_read_pos=0; + rb_write_pos=0; + + //avoid maybe strange noises upon load + for (int i=0;i<(rb_len*channels);i++) { + + rb[i]=0; + read_buf[i]=0; + } + + return OK; + +} + +void AudioRBResampler::clear() { + + if (!rb) + return; + + //should be stopped at this point but just in case + if (rb) { + memdelete_arr(rb); + memdelete_arr(read_buf); + } + rb=NULL; + offset=0; + rb_read_pos=0; + rb_write_pos=0; + read_buf=NULL; +} + +AudioRBResampler::AudioRBResampler() { + + 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; + src_mix_rate=0; + target_mix_rate=0; + +} + +AudioRBResampler::~AudioRBResampler() { + + if (rb) { + memdelete_arr(rb); + memdelete_arr(read_buf); + } + +} + diff --git a/servers/audio/audio_rb_resampler.h b/servers/audio/audio_rb_resampler.h new file mode 100644 index 0000000000..3c686374f4 --- /dev/null +++ b/servers/audio/audio_rb_resampler.h @@ -0,0 +1,133 @@ +#ifndef AUDIO_RB_RESAMPLER_H +#define AUDIO_RB_RESAMPLER_H + +#include "typedefs.h" +#include "os/memory.h" + +struct AudioRBResampler { + + uint32_t rb_bits; + uint32_t rb_len; + uint32_t rb_mask; + uint32_t read_buff_len; + uint32_t channels; + uint32_t src_mix_rate; + uint32_t target_mix_rate; + + volatile int rb_read_pos; + volatile int rb_write_pos; + + int32_t offset; //contains the fractional remainder of the resampler + enum { + MIX_FRAC_BITS=13, + MIX_FRAC_LEN=(1<<MIX_FRAC_BITS), + MIX_FRAC_MASK=MIX_FRAC_LEN-1, + }; + + int16_t *read_buf; + int16_t *rb; + + + template<int C> + uint32_t _resample(int32_t *p_dest,int p_todo,int32_t p_increment); + + +public: + + _FORCE_INLINE_ void flush() { + rb_read_pos=0; + rb_write_pos=0; + } + + _FORCE_INLINE_ bool is_ready() const{ + return rb!=NULL; + } + + + _FORCE_INLINE_ int get_total() const { + + return rb_len-1; + } + + _FORCE_INLINE_ int get_todo() const { //return amount of frames to mix + + int todo; + int read_pos_cache=rb_read_pos; + + if (read_pos_cache==rb_write_pos) { + todo=rb_len-1; + } else if (read_pos_cache>rb_write_pos) { + + todo=read_pos_cache-rb_write_pos-1; + } else { + + todo=(rb_len-rb_write_pos)+read_pos_cache-1; + } + + return todo; + } + + _FORCE_INLINE_ int16_t *get_write_buffer() { return read_buf; } + _FORCE_INLINE_ void write(uint32_t p_frames) { + + ERR_FAIL_COND(p_frames >= rb_len); + + switch(channels) { + case 1: { + + for(uint32_t i=0;i<p_frames;i++) { + + rb[ rb_write_pos ] = read_buf[i]; + rb_write_pos=(rb_write_pos+1)&rb_mask; + } + } break; + case 2: { + + for(uint32_t i=0;i<p_frames;i++) { + + rb[ (rb_write_pos<<1)+0 ] = read_buf[(i<<1)+0]; + rb[ (rb_write_pos<<1)+1 ] = read_buf[(i<<1)+1]; + rb_write_pos=(rb_write_pos+1)&rb_mask; + } + } break; + case 4: { + + for(uint32_t i=0;i<p_frames;i++) { + + rb[ (rb_write_pos<<2)+0 ] = read_buf[(i<<2)+0]; + rb[ (rb_write_pos<<2)+1 ] = read_buf[(i<<2)+1]; + rb[ (rb_write_pos<<2)+2 ] = read_buf[(i<<2)+2]; + rb[ (rb_write_pos<<2)+3 ] = read_buf[(i<<2)+3]; + rb_write_pos=(rb_write_pos+1)&rb_mask; + } + } break; + case 6: { + + for(uint32_t i=0;i<p_frames;i++) { + + rb[ (rb_write_pos*6)+0 ] = read_buf[(i*6)+0]; + rb[ (rb_write_pos*6)+1 ] = read_buf[(i*6)+1]; + rb[ (rb_write_pos*6)+2 ] = read_buf[(i*6)+2]; + rb[ (rb_write_pos*6)+3 ] = read_buf[(i*6)+3]; + rb[ (rb_write_pos*6)+4 ] = read_buf[(i*6)+4]; + rb[ (rb_write_pos*6)+5 ] = read_buf[(i*6)+5]; + rb_write_pos=(rb_write_pos+1)&rb_mask; + } + } break; + + + } + + } + + int get_channel_count() const; + + Error setup(int p_channels, int p_src_mix_rate, int p_target_mix_rate, int p_buffer_msec, int p_minbuff_needed=-1); + void clear(); + bool mix(int32_t *p_dest, int p_frames); + + AudioRBResampler(); + ~AudioRBResampler(); +}; + +#endif // AUDIO_RB_RESAMPLER_H diff --git a/servers/audio/audio_server_sw.cpp b/servers/audio/audio_server_sw.cpp index 8a3ab7ce70..09cb4eca5f 100644 --- a/servers/audio/audio_server_sw.cpp +++ b/servers/audio/audio_server_sw.cpp @@ -830,10 +830,14 @@ void AudioServerSW::finish() { void AudioServerSW::_update_streams(bool p_thread) { _THREAD_SAFE_METHOD_ - for(List<Stream*>::Element *E=active_audio_streams.front();E;E=E->next()) { + for(List<Stream*>::Element *E=active_audio_streams.front();E;) { //stream might be removed durnig this callback + + List<Stream*>::Element *N=E->next(); if (E->get()->audio_stream && p_thread == E->get()->audio_stream->can_update_mt()) E->get()->audio_stream->update(); + + E=N; } } diff --git a/servers/physics/area_sw.cpp b/servers/physics/area_sw.cpp index 83be80f816..e78f0699cb 100644 --- a/servers/physics/area_sw.cpp +++ b/servers/physics/area_sw.cpp @@ -83,6 +83,10 @@ void AreaSW::set_monitor_callback(ObjectID p_id, const StringName& p_method) { _shape_changed(); + if (!moved_list.in_list() && get_space()) + get_space()->area_add_to_moved_list(&moved_list); + + } void AreaSW::set_area_monitor_callback(ObjectID p_id, const StringName& p_method) { @@ -103,6 +107,10 @@ void AreaSW::set_area_monitor_callback(ObjectID p_id, const StringName& p_method _shape_changed(); + if (!moved_list.in_list() && get_space()) + get_space()->area_add_to_moved_list(&moved_list); + + } @@ -123,7 +131,8 @@ void AreaSW::set_param(PhysicsServer::AreaParameter p_param, const Variant& p_va case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT: gravity_is_point=p_value; ; break; case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: gravity_distance_scale=p_value; ; break; case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: point_attenuation=p_value; ; break; - case PhysicsServer::AREA_PARAM_DENSITY: density=p_value; ; break; + case PhysicsServer::AREA_PARAM_LINEAR_DAMP: linear_damp=p_value; ; break; + case PhysicsServer::AREA_PARAM_ANGULAR_DAMP: angular_damp=p_value; ; break; case PhysicsServer::AREA_PARAM_PRIORITY: priority=p_value; ; break; } @@ -139,7 +148,8 @@ Variant AreaSW::get_param(PhysicsServer::AreaParameter p_param) const { case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT: return gravity_is_point; case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: return gravity_distance_scale; case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return point_attenuation; - case PhysicsServer::AREA_PARAM_DENSITY: return density; + case PhysicsServer::AREA_PARAM_LINEAR_DAMP: return linear_damp; + case PhysicsServer::AREA_PARAM_ANGULAR_DAMP: return angular_damp; case PhysicsServer::AREA_PARAM_PRIORITY: return priority; } @@ -248,7 +258,8 @@ AreaSW::AreaSW() : CollisionObjectSW(TYPE_AREA), monitor_query_list(this), move gravity_is_point=false; gravity_distance_scale=0; point_attenuation=1; - density=0.1; + angular_damp=1.0; + linear_damp=0.1; priority=0; set_ray_pickable(false); monitor_callback_id=0; diff --git a/servers/physics/area_sw.h b/servers/physics/area_sw.h index 26d6a177db..40ccdaf370 100644 --- a/servers/physics/area_sw.h +++ b/servers/physics/area_sw.h @@ -47,7 +47,8 @@ class AreaSW : public CollisionObjectSW{ bool gravity_is_point; float gravity_distance_scale; float point_attenuation; - float density; + float linear_damp; + float angular_damp; int priority; bool monitorable; @@ -145,8 +146,11 @@ public: _FORCE_INLINE_ void set_point_attenuation(float p_point_attenuation) { point_attenuation=p_point_attenuation; } _FORCE_INLINE_ float get_point_attenuation() const { return point_attenuation; } - _FORCE_INLINE_ void set_density(float p_density) { density=p_density; } - _FORCE_INLINE_ float get_density() const { return density; } + _FORCE_INLINE_ void set_linear_damp(float p_linear_damp) { linear_damp=p_linear_damp; } + _FORCE_INLINE_ float get_linear_damp() const { return linear_damp; } + + _FORCE_INLINE_ void set_angular_damp(float p_angular_damp) { angular_damp=p_angular_damp; } + _FORCE_INLINE_ float get_angular_damp() const { return angular_damp; } _FORCE_INLINE_ void set_priority(int p_priority) { priority=p_priority; } _FORCE_INLINE_ int get_priority() const { return priority; } @@ -202,6 +206,7 @@ void AreaSW::remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape,uint32 monitored_areas[bk].dec(); if (!monitor_query_list.in_list()) _queue_monitor_update(); + } diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index 5a528ecf94..8edbaf0b89 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -159,6 +159,17 @@ void BodySW::set_param(PhysicsServer::BodyParameter p_param, float p_value) { _update_inertia(); } break; + case PhysicsServer::BODY_PARAM_GRAVITY_SCALE: { + gravity_scale=p_value; + } break; + case PhysicsServer::BODY_PARAM_LINEAR_DAMP: { + + linear_damp=p_value; + } break; + case PhysicsServer::BODY_PARAM_ANGULAR_DAMP: { + + angular_damp=p_value; + } break; default:{} } } @@ -177,6 +188,18 @@ float BodySW::get_param(PhysicsServer::BodyParameter p_param) const { case PhysicsServer::BODY_PARAM_MASS: { return mass; } break; + case PhysicsServer::BODY_PARAM_GRAVITY_SCALE: { + return gravity_scale; + } break; + case PhysicsServer::BODY_PARAM_LINEAR_DAMP: { + + return linear_damp; + } break; + case PhysicsServer::BODY_PARAM_ANGULAR_DAMP: { + + return angular_damp; + } break; + default:{} } @@ -380,6 +403,8 @@ void BodySW::integrate_forces(real_t p_step) { return; AreaSW *def_area = get_space()->get_default_area(); + AreaSW *damp_area = def_area; + ERR_FAIL_COND(!def_area); int ac = areas.size(); @@ -388,7 +413,7 @@ void BodySW::integrate_forces(real_t p_step) { if (ac) { areas.sort(); const AreaCMP *aa = &areas[0]; - density = aa[ac-1].area->get_density(); + damp_area = aa[ac-1].area; for(int i=ac-1;i>=0;i--) { _compute_area_gravity(aa[i].area); if (aa[i].area->get_space_override_mode() == PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE) { @@ -396,13 +421,25 @@ void BodySW::integrate_forces(real_t p_step) { break; } } - } else { - density=def_area->get_density(); } + if( !replace ) { _compute_area_gravity(def_area); } + gravity*=gravity_scale; + + if (angular_damp>=0) + area_angular_damp=angular_damp; + else + area_angular_damp=damp_area->get_angular_damp(); + + if (linear_damp>=0) + area_linear_damp=linear_damp; + else + area_linear_damp=damp_area->get_linear_damp(); + + Vector3 motion; bool do_motion=false; @@ -431,12 +468,12 @@ void BodySW::integrate_forces(real_t p_step) { force+=applied_force; Vector3 torque=applied_torque; - real_t damp = 1.0 - p_step * density; + real_t damp = 1.0 - p_step * area_linear_damp; if (damp<0) // reached zero in the given time damp=0; - real_t angular_damp = 1.0 - p_step * density * get_space()->get_body_angular_velocity_damp_ratio(); + real_t angular_damp = 1.0 - p_step * area_angular_damp; if (angular_damp<0) // reached zero in the given time angular_damp=0; @@ -695,8 +732,12 @@ BodySW::BodySW() : CollisionObjectSW(TYPE_BODY), active_list(this), inertia_upda island_list_next=NULL; first_time_kinematic=false; _set_static(false); - density=0; + contact_count=0; + gravity_scale=1.0; + + area_angular_damp=0; + area_linear_damp=0; still_time=0; continuous_cd=false; diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h index 6491ba8f18..66d814bfd1 100644 --- a/servers/physics/body_sw.h +++ b/servers/physics/body_sw.h @@ -50,6 +50,10 @@ class BodySW : public CollisionObjectSW { real_t bounce; real_t friction; + real_t linear_damp; + real_t angular_damp; + real_t gravity_scale; + PhysicsServer::BodyAxisLock axis_lock; real_t _inv_mass; @@ -57,13 +61,16 @@ class BodySW : public CollisionObjectSW { Matrix3 _inv_inertia_tensor; Vector3 gravity; - real_t density; real_t still_time; Vector3 applied_force; Vector3 applied_torque; + float area_angular_damp; + float area_linear_damp; + + SelfList<BodySW> active_list; SelfList<BodySW> inertia_update_list; SelfList<BodySW> direct_state_query_list; @@ -233,7 +240,6 @@ public: _FORCE_INLINE_ Matrix3 get_inv_inertia_tensor() const { return _inv_inertia_tensor; } _FORCE_INLINE_ real_t get_friction() const { return friction; } _FORCE_INLINE_ Vector3 get_gravity() const { return gravity; } - _FORCE_INLINE_ real_t get_density() const { return density; } _FORCE_INLINE_ real_t get_bounce() const { return bounce; } _FORCE_INLINE_ void set_axis_lock(PhysicsServer::BodyAxisLock p_lock) { axis_lock=p_lock; } @@ -335,8 +341,9 @@ public: BodySW *body; real_t step; - virtual Vector3 get_total_gravity() const { return body->get_gravity(); } // get gravity vector working on this body space/area - virtual float get_total_density() const { return body->get_density(); } // get density of this body space/area + virtual Vector3 get_total_gravity() const { return body->gravity; } // get gravity vector working on this body space/area + virtual float get_total_angular_damp() const { return body->area_angular_damp; } // get density of this body space/area + virtual float get_total_linear_damp() const { return body->area_linear_damp; } // get density of this body space/area virtual float get_inverse_mass() const { return body->get_inv_mass(); } // get the mass virtual Vector3 get_inverse_inertia() const { return body->get_inv_inertia(); } // get density of this body space diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp index 1a41cda482..a5a132020a 100644 --- a/servers/physics_2d/area_2d_sw.cpp +++ b/servers/physics_2d/area_2d_sw.cpp @@ -82,6 +82,10 @@ void Area2DSW::set_monitor_callback(ObjectID p_id, const StringName& p_method) { _shape_changed(); + if (!moved_list.in_list() && get_space()) + get_space()->area_add_to_moved_list(&moved_list); + + } void Area2DSW::set_area_monitor_callback(ObjectID p_id, const StringName& p_method) { @@ -102,6 +106,10 @@ void Area2DSW::set_area_monitor_callback(ObjectID p_id, const StringName& p_meth _shape_changed(); + if (!moved_list.in_list() && get_space()) + get_space()->area_add_to_moved_list(&moved_list); + + } diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index c86bb51f1d..2fbfcaca60 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -337,9 +337,9 @@ public: Body2DSW *body; real_t step; - virtual Vector2 get_total_gravity() const { return body->get_gravity(); } // get gravity vector working on this body space/area - virtual float get_total_angular_damp() const { return body->get_angular_damp(); } // get density of this body space/area - virtual float get_total_linear_damp() const { return body->get_linear_damp(); } // get density of this body space/area + virtual Vector2 get_total_gravity() const { return body->gravity; } // get gravity vector working on this body space/area + virtual float get_total_angular_damp() const { return body->area_angular_damp; } // get density of this body space/area + virtual float get_total_linear_damp() const { return body->area_linear_damp; } // get density of this body space/area virtual float get_inverse_mass() const { return body->get_inv_mass(); } // get the mass virtual real_t get_inverse_inertia() const { return body->get_inv_inertia(); } // get density of this body space diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index e02601af41..53409acdfb 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -39,13 +39,18 @@ void PhysicsDirectBodyState::integrate_forces() { Vector3 av = get_angular_velocity(); - float damp = 1.0 - step * get_total_density(); + float linear_damp = 1.0 - step * get_total_linear_damp(); - if (damp<0) // reached zero in the given time - damp=0; + if (linear_damp<0) // reached zero in the given time + linear_damp=0; - lv*=damp; - av*=damp; + float angular_damp = 1.0 - step * get_total_angular_damp(); + + if (angular_damp<0) // reached zero in the given time + angular_damp=0; + + lv*=linear_damp; + av*=angular_damp; set_linear_velocity(lv); set_angular_velocity(av); @@ -70,7 +75,8 @@ PhysicsServer * PhysicsServer::get_singleton() { void PhysicsDirectBodyState::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_total_gravity"),&PhysicsDirectBodyState::get_total_gravity); - ObjectTypeDB::bind_method(_MD("get_total_density"),&PhysicsDirectBodyState::get_total_density); + ObjectTypeDB::bind_method(_MD("get_total_linear_damp"),&PhysicsDirectBodyState::get_total_linear_damp); + ObjectTypeDB::bind_method(_MD("get_total_angular_damp"),&PhysicsDirectBodyState::get_total_angular_damp); ObjectTypeDB::bind_method(_MD("get_inverse_mass"),&PhysicsDirectBodyState::get_inverse_mass); ObjectTypeDB::bind_method(_MD("get_inverse_inertia"),&PhysicsDirectBodyState::get_inverse_inertia); @@ -683,7 +689,8 @@ void PhysicsServer::_bind_methods() { BIND_CONSTANT( AREA_PARAM_GRAVITY_IS_POINT ); BIND_CONSTANT( AREA_PARAM_GRAVITY_DISTANCE_SCALE ); BIND_CONSTANT( AREA_PARAM_GRAVITY_POINT_ATTENUATION ); - BIND_CONSTANT( AREA_PARAM_DENSITY ); + BIND_CONSTANT( AREA_PARAM_LINEAR_DAMP ); + BIND_CONSTANT( AREA_PARAM_ANGULAR_DAMP ); BIND_CONSTANT( AREA_PARAM_PRIORITY ); BIND_CONSTANT( AREA_SPACE_OVERRIDE_COMBINE ); @@ -698,6 +705,9 @@ void PhysicsServer::_bind_methods() { BIND_CONSTANT( BODY_PARAM_BOUNCE ); BIND_CONSTANT( BODY_PARAM_FRICTION ); BIND_CONSTANT( BODY_PARAM_MASS ); + BIND_CONSTANT( BODY_PARAM_GRAVITY_SCALE ); + BIND_CONSTANT( BODY_PARAM_ANGULAR_DAMP ); + BIND_CONSTANT( BODY_PARAM_LINEAR_DAMP ); BIND_CONSTANT( BODY_PARAM_MAX ); BIND_CONSTANT( BODY_STATE_TRANSFORM ); diff --git a/servers/physics_server.h b/servers/physics_server.h index f66ea590b8..b82d4cf5da 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -41,8 +41,9 @@ protected: static void _bind_methods(); public: - virtual Vector3 get_total_gravity() const=0; // get gravity vector working on this body space/area - virtual float get_total_density() const=0; // get density of this body space/area + virtual Vector3 get_total_gravity() const=0; + virtual float get_total_angular_damp() const=0; + virtual float get_total_linear_damp() const=0; virtual float get_inverse_mass() const=0; // get the mass virtual Vector3 get_inverse_inertia() const=0; // get density of this body space @@ -300,7 +301,8 @@ public: AREA_PARAM_GRAVITY_IS_POINT, AREA_PARAM_GRAVITY_DISTANCE_SCALE, AREA_PARAM_GRAVITY_POINT_ATTENUATION, - AREA_PARAM_DENSITY, + AREA_PARAM_LINEAR_DAMP, + AREA_PARAM_ANGULAR_DAMP, AREA_PARAM_PRIORITY }; @@ -398,6 +400,9 @@ public: BODY_PARAM_BOUNCE, BODY_PARAM_FRICTION, BODY_PARAM_MASS, ///< unused for static, always infinite + BODY_PARAM_GRAVITY_SCALE, + BODY_PARAM_LINEAR_DAMP, + BODY_PARAM_ANGULAR_DAMP, BODY_PARAM_MAX, }; @@ -411,7 +416,7 @@ public: BODY_STATE_LINEAR_VELOCITY, BODY_STATE_ANGULAR_VELOCITY, BODY_STATE_SLEEPING, - BODY_STATE_CAN_SLEEP + BODY_STATE_CAN_SLEEP }; virtual void body_set_state(RID p_body, BodyState p_state, const Variant& p_variant)=0; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 0b115a4d1d..15c757665b 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -1022,6 +1022,7 @@ public: virtual bool has_feature(VS::Features p_feature) const=0; + virtual void restore_framebuffer()=0; virtual int get_render_info(VS::RenderInfo p_info)=0; diff --git a/servers/visual/rasterizer_dummy.cpp b/servers/visual/rasterizer_dummy.cpp index e32f47b3d8..c05438aef3 100644 --- a/servers/visual/rasterizer_dummy.cpp +++ b/servers/visual/rasterizer_dummy.cpp @@ -1948,6 +1948,9 @@ bool RasterizerDummy::has_feature(VS::Features p_feature) const { } +void RasterizerDummy::restore_framebuffer() { + +} RasterizerDummy::RasterizerDummy() { diff --git a/servers/visual/rasterizer_dummy.h b/servers/visual/rasterizer_dummy.h index cc3c1724a4..9249ad6256 100644 --- a/servers/visual/rasterizer_dummy.h +++ b/servers/visual/rasterizer_dummy.h @@ -779,6 +779,7 @@ public: virtual bool has_feature(VS::Features p_feature) const; + virtual void restore_framebuffer(); RasterizerDummy(); virtual ~RasterizerDummy(); diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index b51f59050d..155d10d85a 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -7351,6 +7351,8 @@ void VisualServerRaster::_draw_cursors_and_margins() { rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), 0, Rect2(), tex, Color(1, 1, 1, 1)); }; + + if (black_image[MARGIN_LEFT].is_valid()) { Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_LEFT]),rasterizer->texture_get_height(black_image[MARGIN_LEFT])); rasterizer->canvas_draw_rect(Rect2(0,0,black_margin[MARGIN_LEFT],window_h),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_LEFT],Color(1,1,1)); @@ -7362,10 +7364,22 @@ void VisualServerRaster::_draw_cursors_and_margins() { rasterizer->canvas_draw_rect(Rect2(window_w-black_margin[MARGIN_RIGHT],0,black_margin[MARGIN_RIGHT],window_h),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_RIGHT],Color(1,1,1)); } else if (black_margin[MARGIN_RIGHT]) rasterizer->canvas_draw_rect(Rect2(window_w-black_margin[MARGIN_RIGHT],0,black_margin[MARGIN_RIGHT],window_h),0,Rect2(0,0,1,1),RID(),Color(0,0,0)); - if (black_margin[MARGIN_TOP]) + + if (black_image[MARGIN_TOP].is_valid()) { + Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_TOP]),rasterizer->texture_get_height(black_image[MARGIN_TOP])); + rasterizer->canvas_draw_rect(Rect2(0,0,window_w,black_margin[MARGIN_TOP]),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_TOP],Color(1,1,1)); + + } else if (black_margin[MARGIN_TOP]) { rasterizer->canvas_draw_rect(Rect2(0,0,window_w,black_margin[MARGIN_TOP]),0,Rect2(0,0,1,1),RID(),Color(0,0,0)); - if (black_margin[MARGIN_BOTTOM]) + } + + if (black_image[MARGIN_BOTTOM].is_valid()) { + + Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_BOTTOM]),rasterizer->texture_get_height(black_image[MARGIN_BOTTOM])); + rasterizer->canvas_draw_rect(Rect2(0,window_h-black_margin[MARGIN_BOTTOM],window_w,black_margin[MARGIN_BOTTOM]),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_BOTTOM],Color(1,1,1)); + } else if (black_margin[MARGIN_BOTTOM]) { rasterizer->canvas_draw_rect(Rect2(0,window_h-black_margin[MARGIN_BOTTOM],window_w,black_margin[MARGIN_BOTTOM]),0,Rect2(0,0,1,1),RID(),Color(0,0,0)); + } rasterizer->canvas_end_rect(); }; @@ -7413,6 +7427,8 @@ void VisualServerRaster::set_boot_image(const Image& p_image, const Color& p_col if (p_image.empty()) return; + rasterizer->restore_framebuffer(); + rasterizer->begin_frame(); int window_w = OS::get_singleton()->get_video_mode(0).width; diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp index d431af6c8d..96bd1ed27d 100644 --- a/tools/editor/animation_editor.cpp +++ b/tools/editor/animation_editor.cpp @@ -33,6 +33,7 @@ #include "io/resource_saver.h" #include "pair.h" #include "scene/gui/separator.h" +#include "editor_node.h" /* Missing to fix: *Set @@ -634,9 +635,14 @@ void AnimationKeyEditor::_menu_track(int p_type) { last_menu_track_opt=p_type; switch(p_type) { - case TRACK_MENU_ADD_VALUE_TRACK: - case TRACK_MENU_ADD_TRANSFORM_TRACK: case TRACK_MENU_ADD_CALL_TRACK: { + if (root) { + call_select->popup_centered_ratio(); + break; + } + } break; + case TRACK_MENU_ADD_VALUE_TRACK: + case TRACK_MENU_ADD_TRANSFORM_TRACK: { undo_redo->create_action("Anim Add Track"); undo_redo->add_do_method(animation.ptr(),"add_track",p_type); @@ -2735,6 +2741,7 @@ void AnimationKeyEditor::_notification(int p_what) { } + call_select->connect("selected",this,"_add_call_track"); // rename_anim->set_icon( get_icon("Rename","EditorIcons") ); /* edit_anim->set_icon( get_icon("Edit","EditorIcons") ); @@ -3456,6 +3463,26 @@ void AnimationKeyEditor::_scale() { } +void AnimationKeyEditor::_add_call_track(const NodePath& p_base) { + + print_line("BASE IS "+String(p_base)); + Node* base = EditorNode::get_singleton()->get_edited_scene(); + if (!base) + return; + Node* from=base->get_node(p_base); + if (!from || !root) + return; + + NodePath path = root->get_path_to(from); + + undo_redo->create_action("Anim Add Call Track"); + undo_redo->add_do_method(animation.ptr(),"add_track",Animation::TYPE_METHOD); + undo_redo->add_do_method(animation.ptr(),"track_set_path",animation->get_track_count(),path); + undo_redo->add_undo_method(animation.ptr(),"remove_track",animation->get_track_count()); + undo_redo->commit_action(); + +} + void AnimationKeyEditor::cleanup() { set_animation(Ref<Animation>()); @@ -3503,6 +3530,7 @@ void AnimationKeyEditor::_bind_methods() { 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); + ObjectTypeDB::bind_method(_MD("_add_call_track"),&AnimationKeyEditor::_add_call_track); ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) ); @@ -3815,7 +3843,9 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h scale_dialog->connect("confirmed",this,"_scale"); add_child(scale_dialog); - + call_select = memnew( SceneTreeDialog ); + add_child(call_select); + call_select->set_title("Call Functions in Which Node?"); } diff --git a/tools/editor/animation_editor.h b/tools/editor/animation_editor.h index 35053fb6a3..4a1cc21154 100644 --- a/tools/editor/animation_editor.h +++ b/tools/editor/animation_editor.h @@ -44,7 +44,7 @@ #include "scene_tree_editor.h" #include "editor_data.h" #include "property_editor.h" - +#include "scene_tree_editor.h" class AnimationKeyEdit; class AnimationCurveEdit; @@ -206,6 +206,8 @@ class AnimationKeyEditor : public VBoxContainer { PropertyEditor *key_editor; + SceneTreeDialog *call_select; + Ref<Animation> animation; void _update_paths(); @@ -299,6 +301,8 @@ class AnimationKeyEditor : public VBoxContainer { void _toggle_edit_curves(); void _animation_len_update(); + void _add_call_track(const NodePath& p_base); + void _root_removed(); protected: diff --git a/tools/editor/array_property_edit.cpp b/tools/editor/array_property_edit.cpp new file mode 100644 index 0000000000..9cd443270b --- /dev/null +++ b/tools/editor/array_property_edit.cpp @@ -0,0 +1,231 @@ +#include "array_property_edit.h" + +#include "editor_node.h" + +#define ITEMS_PER_PAGE 100 + +Variant ArrayPropertyEdit::get_array() const{ + + Object*o = ObjectDB::get_instance(obj); + if (!o) + return Array(); + Variant arr=o->get(property); + if (!arr.is_array()) { + Variant::CallError ce; + arr=Variant::construct(default_type,NULL,0,ce); + } + return arr; +} + +void ArrayPropertyEdit::_notif_change() { + _change_notify(); +} +void ArrayPropertyEdit::_notif_changev(const String& p_v) { + + _change_notify(p_v.utf8().get_data()); +} + +void ArrayPropertyEdit::_set_size(int p_size) { + + Variant arr = get_array(); + arr.call("resize",p_size); + Object*o = ObjectDB::get_instance(obj); + if (!o) + return; + + o->set(property,arr); + +} + +void ArrayPropertyEdit::_set_value(int p_idx,const Variant& p_value) { + + Variant arr = get_array(); + arr.set(p_idx,p_value); + Object*o = ObjectDB::get_instance(obj); + if (!o) + return; + + o->set(property,arr); +} + +bool ArrayPropertyEdit::_set(const StringName& p_name, const Variant& p_value){ + + String pn=p_name; + + if (pn.begins_with("array/")) { + + if (pn=="array/size") { + + Variant arr = get_array(); + int size = arr.call("size"); + + int newsize=p_value; + if (newsize==size) + return true; + + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Resize Array"); + ur->add_do_method(this,"_set_size",newsize); + ur->add_undo_method(this,"_set_size",size); + if (newsize<size) { + for(int i=newsize;i<size;i++) { + ur->add_undo_method(this,"_set_value",i,arr.get(i)); + + } + } + ur->add_do_method(this,"_notif_change"); + ur->add_undo_method(this,"_notif_change"); + ur->commit_action(); + return true; + } + if (pn=="array/page") { + page=p_value; + _change_notify(); + return true; + } + } else if (pn.begins_with("indices")) { + + if (pn.find("_")!=-1) { + //type + int idx=pn.get_slicec('/',1).get_slicec('_',0).to_int(); + + int type = p_value; + + Variant arr = get_array(); + + Variant value = arr.get(idx); + if (value.get_type()!=type && type>=0 && type<Variant::VARIANT_MAX) { + Variant::CallError ce; + Variant new_value=Variant::construct(Variant::Type(type),NULL,0,ce); + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action("Change Array Value Type"); + ur->add_do_method(this,"_set_value",idx,new_value); + ur->add_undo_method(this,"_set_value",idx,value); + ur->add_do_method(this,"_notif_change"); + ur->add_undo_method(this,"_notif_change"); + ur->commit_action(); + + } + return true; + + } else { + int idx=pn.get_slicec('/',1).to_int(); + Variant arr = get_array(); + + Variant value = arr.get(idx); + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action("Change Array Value"); + ur->add_do_method(this,"_set_value",idx,p_value); + ur->add_undo_method(this,"_set_value",idx,value); + ur->add_do_method(this,"_notif_changev",p_name); + ur->add_undo_method(this,"_notif_changev",p_name); + ur->commit_action(); + return true; + } + } + + return false; +} + +bool ArrayPropertyEdit::_get(const StringName& p_name,Variant &r_ret) const { + + Variant arr = get_array(); + //int size = arr.call("size"); + + String pn=p_name; + if (pn.begins_with("array/")) { + + if (pn=="array/size") { + r_ret=arr.call("size"); + return true; + } + if (pn=="array/page") { + r_ret=page; + return true; + } + } else if (pn.begins_with("indices")) { + + if (pn.find("_")!=-1) { + //type + int idx=pn.get_slicec('/',1).get_slicec('_',0).to_int(); + bool valid; + r_ret=arr.get(idx,&valid); + if (valid) + r_ret=r_ret.get_type(); + return valid; + + } else { + int idx=pn.get_slicec('/',1).to_int(); + bool valid; + r_ret=arr.get(idx,&valid); + return valid; + } + } + + return false; +} + +void ArrayPropertyEdit::_get_property_list( List<PropertyInfo> *p_list) const{ + + Variant arr = get_array(); + int size = arr.call("size"); + + p_list->push_back( PropertyInfo(Variant::INT,"array/size",PROPERTY_HINT_RANGE,"0,100000,1") ); + int pages = size/ITEMS_PER_PAGE; + if (pages>0) + p_list->push_back( PropertyInfo(Variant::INT,"array/page",PROPERTY_HINT_RANGE,"0,"+itos(pages)+",1") ); + + int offset=page*ITEMS_PER_PAGE; + + int items=MIN(size-offset,ITEMS_PER_PAGE); + + + for(int i=0;i<items;i++) { + + Variant v=arr.get(i+offset); + if (arr.get_type()==Variant::ARRAY) { + p_list->push_back(PropertyInfo(Variant::INT,"indices/"+itos(i+offset)+"_type",PROPERTY_HINT_ENUM,vtypes)); + } + if (arr.get_type()!=Variant::ARRAY || v.get_type()!=Variant::NIL) { + PropertyInfo pi(v.get_type(),"indices/"+itos(i+offset)); + if (v.get_type()==Variant::OBJECT) { + pi.hint=PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string="Resource"; + } + p_list->push_back(pi); + } + } + +} + +void ArrayPropertyEdit::edit(Object* p_obj,const StringName& p_prop,Variant::Type p_deftype) { + + page=0; + property=p_prop; + obj=p_obj->get_instance_ID(); + default_type=p_deftype; + +} + +void ArrayPropertyEdit::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_set_size"),&ArrayPropertyEdit::_set_size); + ObjectTypeDB::bind_method(_MD("_set_value"),&ArrayPropertyEdit::_set_value); + ObjectTypeDB::bind_method(_MD("_notif_change"),&ArrayPropertyEdit::_notif_change); + ObjectTypeDB::bind_method(_MD("_notif_changev"),&ArrayPropertyEdit::_notif_changev); +} + +ArrayPropertyEdit::ArrayPropertyEdit() +{ + page=0; + for(int i=0;i<Variant::VARIANT_MAX;i++) { + + if (i>0) + vtypes+=","; + vtypes+=Variant::get_type_name( Variant::Type(i) ); + } + default_type=Variant::NIL; + +} diff --git a/tools/editor/array_property_edit.h b/tools/editor/array_property_edit.h new file mode 100644 index 0000000000..acfb8e68ed --- /dev/null +++ b/tools/editor/array_property_edit.h @@ -0,0 +1,36 @@ +#ifndef ARRAY_PROPERTY_EDIT_H +#define ARRAY_PROPERTY_EDIT_H + +#include "scene/main/node.h" + +class ArrayPropertyEdit : public Reference { + + OBJ_TYPE(ArrayPropertyEdit,Reference); + + int page; + ObjectID obj; + StringName property; + String vtypes; + Variant get_array() const; + Variant::Type default_type; + + void _notif_change(); + void _notif_changev(const String& p_v); + void _set_size(int p_size); + void _set_value(int p_idx,const Variant& p_value); + +protected: + + static void _bind_methods(); + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + +public: + + void edit(Object* p_obj, const StringName& p_prop, Variant::Type p_deftype); + + ArrayPropertyEdit(); +}; + +#endif // ARRAY_PROPERTY_EDIT_H diff --git a/tools/editor/dependency_editor.cpp b/tools/editor/dependency_editor.cpp new file mode 100644 index 0000000000..c04e82a08a --- /dev/null +++ b/tools/editor/dependency_editor.cpp @@ -0,0 +1,512 @@ +#include "dependency_editor.h" +#include "os/file_access.h" +#include "scene/gui/margin_container.h" +#include "io/resource_loader.h" +#include "editor_node.h" + +void DependencyEditor::_notification(int p_what){ + + +} + +void DependencyEditor::_searched(const String& p_path) { + + Map<String,String> dep_rename; + dep_rename[replacing]=p_path; + + + ResourceLoader::rename_dependencies(editing,dep_rename); + + _update_list(); + _update_file(); +} + +void DependencyEditor::_load_pressed(Object* p_item,int p_cell,int p_button){ + + TreeItem *ti=p_item->cast_to<TreeItem>(); + String fname = ti->get_text(0); + replacing = ti->get_text(1); + + search->set_title("Search Replacement For: "+replacing.get_file()); + + search->clear_filters(); + List<String> ext; + ResourceLoader::get_recognized_extensions_for_type(ti->get_metadata(0),&ext); + for (List<String>::Element *E=ext.front();E;E=E->next()) { + search->add_filter("*"+E->get()); + } + search->popup_centered_ratio(); + +} + +void DependencyEditor::_fix_and_find(EditorFileSystemDirectory *efsd, Map<String,Map<String,String> >& candidates){ + + for(int i=0;i<efsd->get_subdir_count();i++) { + _fix_and_find(efsd->get_subdir(i),candidates); + } + + for(int i=0;i<efsd->get_file_count();i++) { + + String file = efsd->get_file(i); + if (!candidates.has(file)) + continue; + + String path = efsd->get_file_path(i); + Map<String,String> &ss = candidates[file]; + + + for(Map<String,String>::Element *E=candidates[file].front();E;E=E->next()) { + + if (E->get()==String()) { + E->get()=path; + continue; + } + + //must match the best, using subdirs + String existing=E->get().replace_first("res://",""); + String current=path.replace_first("res://",""); + String lost=E->key().replace_first("res://",""); + + Vector<String> existingv=existing.split("/"); + existingv.invert(); + Vector<String> currentv=current.split("/"); + currentv.invert(); + Vector<String> lostv=lost.split("/"); + lostv.invert(); + + int existing_score=0; + int current_score=0; + + for(int j=0;j<lostv.size();j++) { + + if (j<existingv.size() && lostv[j]==existingv[j]) { + existing_score++; + } + if (j<currentv.size() && lostv[j]==currentv[j]) { + current_score++; + } + } + + if (current_score > existing_score) { + + //if it was the same, could track distance to new path but.. + + E->get()=path; //replace by more accurate + } + + } + + } + +} + + +void DependencyEditor::_fix_all(){ + + if (!EditorFileSystem::get_singleton()->get_filesystem()) + return; + + Map<String,Map<String,String> > candidates; + + for (List<String>::Element *E=missing.front();E;E=E->next()) { + + String base = E->get().get_file(); + if (!candidates.has(base)) { + candidates[base]=Map<String,String>(); + } + + candidates[base][E->get()]=""; + } + + _fix_and_find(EditorFileSystem::get_singleton()->get_filesystem(),candidates); + + Map<String,String> remaps; + + for (Map<String,Map<String,String> >::Element *E=candidates.front();E;E=E->next()) { + + for (Map<String,String>::Element *F=E->get().front();F;F=F->next()) { + + if (F->get()!=String()) { + remaps[F->key()]=F->get(); + } + } + + } + + if (remaps.size()) { + + ResourceLoader::rename_dependencies(editing,remaps); + + _update_list(); + _update_file(); + } +} + +void DependencyEditor::_update_file() { + + EditorFileSystem::get_singleton()->update_file(editing); + +} + +void DependencyEditor::_update_list() { + + List<String> deps; + ResourceLoader::get_dependencies(editing,&deps,true); + + tree->clear(); + missing.clear(); + + TreeItem *root = tree->create_item(); + + Ref<Texture> folder = get_icon("folder","FileDialog"); + + bool broken=false; + + for(List<String>::Element *E=deps.front();E;E=E->next()) { + + TreeItem *item = tree->create_item(root); + + String n = E->get(); + String path; + String type; + + if (n.find("::")!=-1) { + path = n.get_slice("::",0); + type = n.get_slice("::",1); + } else { + path=n; + type="Resource"; + } + String name = path.get_file(); + + Ref<Texture> icon; + if (has_icon(type,"EditorIcons")) { + icon=get_icon(type,"EditorIcons"); + } else { + icon=get_icon("Object","EditorIcons"); + } + item->set_text(0,name); + item->set_icon(0,icon); + item->set_metadata(0,type); + item->set_text(1,path); + + if (!FileAccess::exists(path)) { + item->set_custom_color(1,Color(1,0.4,0.3)); + missing.push_back(path); + broken=true; + } + + item->add_button(1,folder,0); + } + + fixdeps->set_disabled(!broken); + +} + + + +void DependencyEditor::edit(const String& p_path) { + + + editing=p_path; + set_title("Dependencies For: "+p_path.get_file()); + + _update_list(); + popup_centered_ratio(); + + if (EditorNode::get_singleton()->is_scene_open(p_path)) { + EditorNode::get_singleton()->show_warning("Scene '"+p_path.get_file()+"' is currently being edited.\nChanges will not take effect unless reloaded."); + } else if (ResourceCache::has(p_path)) { + EditorNode::get_singleton()->show_warning("Resource '"+p_path.get_file()+"' is in use.\nChanges will take effect when reloaded."); + } +} + + +void DependencyEditor::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_searched"),&DependencyEditor::_searched); + ObjectTypeDB::bind_method(_MD("_load_pressed"),&DependencyEditor::_load_pressed); + ObjectTypeDB::bind_method(_MD("_fix_all"),&DependencyEditor::_fix_all); + +} + +DependencyEditor::DependencyEditor() { + + VBoxContainer *vb = memnew( VBoxContainer ); + vb->set_name("Dependencies"); + add_child(vb); + set_child_rect(vb); + + tree = memnew( Tree ); + tree->set_columns(2); + tree->set_column_titles_visible(true); + tree->set_column_title(0,"Resource"); + tree->set_column_title(1,"Path"); + tree->set_hide_root(true); + tree->connect("button_pressed",this,"_load_pressed"); + + HBoxContainer *hbc = memnew( HBoxContainer ); + Label *label = memnew( Label("Dependencies:")); + hbc->add_child(label); + hbc->add_spacer(); + fixdeps = memnew( Button("Fix Broken")); + hbc->add_child(fixdeps); + fixdeps->connect("pressed",this,"_fix_all"); + + vb->add_child(hbc); + + MarginContainer *mc = memnew( MarginContainer ); + mc->set_v_size_flags(SIZE_EXPAND_FILL); + + mc->add_child(tree); + vb->add_child(mc); + + set_title("Dependency Editor"); + search = memnew( EditorFileDialog ); + search->connect("file_selected",this,"_searched"); + search->set_mode(EditorFileDialog::MODE_OPEN_FILE); + search->set_title("Search Replacement Resource:"); + add_child(search); + +} + +///////////////////////////////////// + + + +void DependencyEditorOwners::_fill_owners(EditorFileSystemDirectory *efsd) { + + if (!efsd) + return; + + for(int i=0;i<efsd->get_subdir_count();i++) { + _fill_owners(efsd->get_subdir(i)); + } + + for(int i=0;i<efsd->get_file_count();i++) { + + Vector<String> deps = efsd->get_file_deps(i); + //print_line(":::"+efsd->get_file_path(i)); + bool found=false; + for(int j=0;j<deps.size();j++) { + //print_line("\t"+deps[j]+" vs "+editing); + if (deps[j]==editing) { + //print_line("found"); + found=true; + break; + } + } + if (!found) + continue; + + Ref<Texture> icon; + String type=efsd->get_file_type(i); + if (!has_icon(type,"EditorIcons")) { + icon=get_icon("Object","EditorIcons"); + } else { + icon=get_icon(type,"EditorIcons"); + } + + owners->add_item(efsd->get_file_path(i),icon); + } + +} + +void DependencyEditorOwners::show(const String& p_path) { + + editing=p_path; + owners->clear(); + _fill_owners(EditorFileSystem::get_singleton()->get_filesystem()); + popup_centered_ratio(); + + set_title("Owners Of: "+p_path.get_file()); + +} + +DependencyEditorOwners::DependencyEditorOwners() { + + + owners = memnew( ItemList ); + add_child(owners); + set_child_rect(owners); + + +} + +/////////////////////// + + +void DependencyRemoveDialog::_fill_owners(EditorFileSystemDirectory *efsd) { + + if (!efsd) + return; + + for(int i=0;i<efsd->get_subdir_count();i++) { + _fill_owners(efsd->get_subdir(i)); + } + + for(int i=0;i<efsd->get_file_count();i++) { + + Vector<String> deps = efsd->get_file_deps(i); + //print_line(":::"+efsd->get_file_path(i)); + Set<String> met; + for(int j=0;j<deps.size();j++) { + if (files.has(deps[j])) { + met.insert(deps[j]); + } + } + if (!met.size()) + continue; + + exist=true; + + Ref<Texture> icon; + String type=efsd->get_file_type(i); + if (!has_icon(type,"EditorIcons")) { + icon=get_icon("Object","EditorIcons"); + } else { + icon=get_icon(type,"EditorIcons"); + } + + + for(Set<String>::Element *E=met.front();E;E=E->next()) { + + String which = E->get(); + if (!files[which]) { + TreeItem *ti=owners->create_item(owners->get_root()); + ti->set_text(0,which.get_file()); + files[which]=ti; + + } + TreeItem *ti=owners->create_item(files[which]); + ti->set_text(0,efsd->get_file_path(i)); + ti->set_icon(0,icon); + } + + } + +} + +void DependencyRemoveDialog::show(const Vector<String> &to_erase) { + + exist=false; + owners->clear(); + files.clear(); + TreeItem *root=owners->create_item(); + for(int i=0;i<to_erase.size();i++) { + files[to_erase[i]]=NULL; + } + + _fill_owners(EditorFileSystem::get_singleton()->get_filesystem()); + + if (exist) { + owners->show(); + text->set_text("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (no undo)"); + popup_centered_minsize(Size2(500,220)); + } else { + owners->hide(); + text->set_text("Remove selected files from the project? (no undo)"); + popup_centered_minsize(Size2(400,100)); + } + +} + +void DependencyRemoveDialog::ok_pressed() { + + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + for (Map<String,TreeItem*>::Element *E=files.front();E;E=E->next()) { + + da->remove(E->key()); + EditorFileSystem::get_singleton()->update_file(E->key()); + } + memdelete(da); + +} + +DependencyRemoveDialog::DependencyRemoveDialog() { + + VBoxContainer *vb = memnew( VBoxContainer ); + add_child(vb); + set_child_rect(vb); + + text = memnew( Label ); + vb->add_child(text); + + owners = memnew( Tree ); + owners->set_hide_root(true); + vb->add_child(owners); + owners->set_v_size_flags(SIZE_EXPAND_FILL); + get_ok()->set_text("Remove"); +} + + +////////////// + + +void DependencyErrorDialog::show(const String& p_for_file,const Vector<String> &report) { + + + for_file=p_for_file; + set_title("Error loading: "+p_for_file.get_file()); + files->clear(); + + TreeItem *root = files->create_item(NULL); + for(int i=0;i<report.size();i++) { + + String dep; + String type="Object"; + dep=report[i].get_slice("::",0); + if (report[i].get_slice_count("::")>0) + type=report[i].get_slice("::",1); + + Ref<Texture> icon; + if (!has_icon(type,"EditorIcons")) { + icon=get_icon("Object","EditorIcons"); + } else { + icon=get_icon(type,"EditorIcons"); + } + + TreeItem *ti=files->create_item(root); + ti->set_text(0,dep); + ti->set_icon(0,icon); + + } + + popup_centered_minsize(Size2(500,220)); + +} + +void DependencyErrorDialog::ok_pressed() { + + EditorNode::get_singleton()->load_scene(for_file,true); +} + +void DependencyErrorDialog::custom_action(const String&) { + + EditorNode::get_singleton()->fix_dependencies(for_file); +} + +DependencyErrorDialog::DependencyErrorDialog() { + + VBoxContainer *vb = memnew( VBoxContainer ); + add_child(vb); + set_child_rect(vb); + + + files = memnew( Tree ); + files->set_hide_root(true); + vb->add_margin_child("Scene failed to load due to missing dependencies:",files,true); + files->set_v_size_flags(SIZE_EXPAND_FILL); + get_ok()->set_text("Open Anyway"); + + text = memnew( Label ); + vb->add_child(text); + text->set_text("Which action should be taken?"); + + + fdep=add_button("Fix Dependencies",true,"fixdeps"); + + set_title("Errors loading!"); + +} diff --git a/tools/editor/dependency_editor.h b/tools/editor/dependency_editor.h new file mode 100644 index 0000000000..1c328e7a93 --- /dev/null +++ b/tools/editor/dependency_editor.h @@ -0,0 +1,94 @@ +#ifndef DEPENDENCY_EDITOR_H +#define DEPENDENCY_EDITOR_H + +#include "scene/gui/dialogs.h" +#include "scene/gui/tree.h" +#include "scene/gui/tab_container.h" +#include "editor_file_dialog.h" + +class EditorFileSystemDirectory; + +class DependencyEditor : public AcceptDialog { + OBJ_TYPE(DependencyEditor,AcceptDialog); + + + Tree *tree; + Button *fixdeps; + + EditorFileDialog *search; + + String replacing; + String editing; + List<String> missing; + + + void _fix_and_find(EditorFileSystemDirectory *efsd, Map<String,Map<String,String> >& candidates); + + void _searched(const String& p_path); + void _load_pressed(Object* p_item,int p_cell,int p_button); + void _fix_all(); + void _update_list(); + + void _update_file(); + +protected: + + static void _bind_methods(); + void _notification(int p_what); +public: + + + void edit(const String& p_path); + DependencyEditor(); +}; + +class DependencyEditorOwners : public AcceptDialog { + OBJ_TYPE(DependencyEditorOwners,AcceptDialog); + + ItemList *owners; + String editing; + void _fill_owners(EditorFileSystemDirectory *efsd); + +public: + + void show(const String& p_path); + DependencyEditorOwners(); +}; + +class DependencyRemoveDialog : public ConfirmationDialog { + OBJ_TYPE(DependencyRemoveDialog,ConfirmationDialog); + + + Label *text; + Tree *owners; + bool exist; + Map<String,TreeItem*> files; + void _fill_owners(EditorFileSystemDirectory *efsd); + + void ok_pressed(); + +public: + + void show(const Vector<String> &to_erase); + DependencyRemoveDialog(); +}; + + +class DependencyErrorDialog : public ConfirmationDialog { + OBJ_TYPE(DependencyErrorDialog,ConfirmationDialog); + + + String for_file; + Button *fdep; + Label *text; + Tree *files; + void ok_pressed(); + void custom_action(const String&); + +public: + + void show(const String& p_for,const Vector<String> &report); + DependencyErrorDialog(); +}; + +#endif // DEPENDENCY_EDITOR_H diff --git a/tools/editor/editor_data.cpp b/tools/editor/editor_data.cpp index 7f42f19a9b..673ee30adb 100644 --- a/tools/editor/editor_data.cpp +++ b/tools/editor/editor_data.cpp @@ -39,7 +39,7 @@ void EditorHistory::_cleanup_history() { bool fail=false; for(int j=0;j<history[i].path.size();j++) { - if (!history[i].path[j].res.is_null()) + if (!history[i].path[j].ref.is_null()) continue; if (ObjectDB::get_instance(history[i].path[j].object)) @@ -70,10 +70,10 @@ void EditorHistory::_add_object(ObjectID p_object,const String& p_property,int p Object *obj = ObjectDB::get_instance(p_object); ERR_FAIL_COND(!obj); - Resource *r = obj->cast_to<Resource>(); + Reference *r = obj->cast_to<Reference>(); Obj o; if (r) - o.res=RES(r); + o.ref=REF(r); o.object=p_object; o.property=p_property; @@ -123,6 +123,27 @@ void EditorHistory::add_object(ObjectID p_object,int p_relevel){ _add_object(p_object,"",p_relevel); } +int EditorHistory::get_history_len() { + return history.size(); +} +int EditorHistory::get_history_pos() { + return current; +} + +ObjectID EditorHistory::get_history_obj(int p_obj) const { + ERR_FAIL_INDEX_V(p_obj,history.size(),0); + ERR_FAIL_INDEX_V(history[p_obj].level,history[p_obj].path.size(),0); + return history[p_obj].path[history[p_obj].level].object; +} + +bool EditorHistory::is_at_begining() const { + return current<=0; +} +bool EditorHistory::is_at_end() const { + + return ((current+1)>=history.size()); +} + bool EditorHistory::next() { @@ -523,7 +544,7 @@ Ref<Script> EditorData::get_scene_root_script(int p_idx) const { if (!edited_scene[p_idx].root) return Ref<Script>(); Ref<Script> s=edited_scene[p_idx].root->get_script(); - if (!s.is_valid()) { + if (!s.is_valid() && edited_scene[p_idx].root->get_child_count()) { Node *n = edited_scene[p_idx].root->get_child(0); while(!s.is_valid() && n && n->get_filename()==String()) { s=n->get_script(); diff --git a/tools/editor/editor_data.h b/tools/editor/editor_data.h index cbec2295f6..c5ee83ae63 100644 --- a/tools/editor/editor_data.h +++ b/tools/editor/editor_data.h @@ -45,7 +45,7 @@ class EditorHistory { struct Obj { - RES res; + REF ref; ObjectID object; String property; }; @@ -75,10 +75,17 @@ friend class EditorData; public: + bool is_at_begining() const; + bool is_at_end() const; + void add_object(ObjectID p_object); void add_object(ObjectID p_object,const String& p_subprop); void add_object(ObjectID p_object,int p_relevel); + int get_history_len(); + int get_history_pos(); + ObjectID get_history_obj(int p_obj) const; + bool next(); bool previous(); ObjectID get_current(); diff --git a/tools/editor/editor_file_dialog.cpp b/tools/editor/editor_file_dialog.cpp index b1bbd71f7b..c62347d129 100644 --- a/tools/editor/editor_file_dialog.cpp +++ b/tools/editor/editor_file_dialog.cpp @@ -190,7 +190,7 @@ void EditorFileDialog::_thumbnail_done(const String& p_path,const 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); + //print_line("want file "+p_path); set_process(true); preview_waiting=true; preview_wheel_timeout=0; @@ -359,7 +359,7 @@ void EditorFileDialog::_item_dc_selected(int p_item) { if (d["dir"]) { - print_line("change dir: "+String(d["name"])); + //print_line("change dir: "+String(d["name"])); dir_access->change_dir(d["name"]); if (mode==MODE_OPEN_FILE || mode==MODE_OPEN_FILES || mode==MODE_OPEN_DIR) file->set_text(""); @@ -536,6 +536,7 @@ void EditorFileDialog::update_file_list() { if (get_icon_func) { + Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get())); //ti->set_icon(0,icon); if (display_mode==DISPLAY_THUMBNAILS) { diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp index d741087a9f..33e4a15c85 100644 --- a/tools/editor/editor_file_system.cpp +++ b/tools/editor/editor_file_system.cpp @@ -94,6 +94,12 @@ bool EditorFileSystemDirectory::get_file_meta(int p_idx) const { return files[p_idx].meta.enabled; } +Vector<String> EditorFileSystemDirectory::get_file_deps(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>()); + return files[p_idx].meta.deps; + +} Vector<String> EditorFileSystemDirectory::get_missing_sources(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>()); @@ -118,7 +124,7 @@ bool EditorFileSystemDirectory::is_missing_sources(int p_idx) const { return false; } -String EditorFileSystemDirectory::get_file_type(int p_idx) const { +StringName EditorFileSystemDirectory::get_file_type(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),""); return files[p_idx].type; @@ -198,6 +204,13 @@ EditorFileSystemDirectory::ImportMeta EditorFileSystem::_get_meta(const String& } m.import_editor=imd->get_editor(); } + + List<String> deps; + ResourceLoader::get_dependencies(p_path,&deps); + for(List<String>::Element *E=deps.front();E;E=E->next()) { + m.deps.push_back(E->get()); + } + return m; } @@ -358,7 +371,7 @@ void EditorFileSystem::_scan_scenes() { String project=Globals::get_singleton()->get_resource_path(); - String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("file_cache"); + String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache"); FileAccess *f =FileAccess::open(fscache,FileAccess::READ); if (f) { @@ -397,7 +410,7 @@ void EditorFileSystem::_scan_scenes() { } else { Vector<String> split = l.split("::"); - ERR_CONTINUE( split.size() != 4); + ERR_CONTINUE( split.size() != 5); String name = split[0]; String file; @@ -429,6 +442,15 @@ void EditorFileSystem::_scan_scenes() { } } + String deps = split[4].strip_edges(); + if (deps.length()) { + Vector<String> dp = deps.split("<>"); + for(int i=0;i<dp.size();i++) { + String path=dp[i]; + fc.meta.deps.push_back(path); + } + } + file_cache[name]=fc; ERR_CONTINUE(!dc); @@ -530,6 +552,7 @@ void EditorFileSystem::scan() { thread = Thread::create(_thread_func,this,s); //tree->hide(); //progress->show(); + } @@ -798,6 +821,14 @@ void EditorFileSystem::_save_type_cache_fs(DirItem *p_dir,FileAccess *p_file) { } } + s+="::"; + for(int j=0;j<p_dir->files[i]->meta.deps.size();j++) { + + if (j>0) + s+="<>"; + s+=p_dir->files[i]->meta.deps[j]; + } + p_file->store_line(s); } @@ -1037,6 +1068,13 @@ void EditorFileSystem::update_file(const String& p_file) { return; } + if (!FileAccess::exists(p_file)) { + //was removed + fs->files.remove(cpos); + call_deferred("emit_signal","filesystem_changed"); //update later + return; + + } String type = ResourceLoader::get_resource_type(p_file); diff --git a/tools/editor/editor_file_system.h b/tools/editor/editor_file_system.h index 3f413292fe..f79dd209ef 100644 --- a/tools/editor/editor_file_system.h +++ b/tools/editor/editor_file_system.h @@ -59,13 +59,14 @@ class EditorFileSystemDirectory : public Object { Vector<Source> sources; String import_editor; + Vector<String> deps; bool enabled; }; struct FileInfo { String file; - String type; + StringName type; uint64_t modified_time; ImportMeta meta; @@ -87,10 +88,11 @@ public: int get_file_count() const; String get_file(int p_idx) const; String get_file_path(int p_idx) const; - String get_file_type(int p_idx) const; + StringName get_file_type(int p_idx) const; bool get_file_meta(int p_idx) const; bool is_missing_sources(int p_idx) const; Vector<String> get_missing_sources(int p_idx) const; + Vector<String> get_file_deps(int p_idx) const; EditorFileSystemDirectory *get_parent(); @@ -120,7 +122,7 @@ class EditorFileSystem : public Node { String path; String name; Vector<DirItem*> dirs; - Vector<SceneItem*> files; + Vector<SceneItem*> files; ~DirItem(); }; @@ -149,6 +151,7 @@ class EditorFileSystem : public Node { String type; uint64_t modification_time; EditorFileSystemDirectory::ImportMeta meta; + Vector<String> deps; }; struct DirCache { diff --git a/tools/editor/editor_import_export.cpp b/tools/editor/editor_import_export.cpp index b28b349c86..84fc14d2ec 100644 --- a/tools/editor/editor_import_export.cpp +++ b/tools/editor/editor_import_export.cpp @@ -255,7 +255,16 @@ static void _add_filter_to_list(Set<StringName>& r_list,const String& p_filter) } +Vector<uint8_t> EditorExportPlatform::get_exported_file_default(String& p_fname) const { + FileAccess *f = FileAccess::open(p_fname,FileAccess::READ); + ERR_FAIL_COND_V(!f,Vector<uint8_t>()); + Vector<uint8_t> ret; + ret.resize(f->get_len()); + int rbs = f->get_buffer(ret.ptr(),ret.size()); + memdelete(f); + return ret; +} Vector<uint8_t> EditorExportPlatform::get_exported_file(String& p_fname) const { @@ -270,13 +279,9 @@ Vector<uint8_t> EditorExportPlatform::get_exported_file(String& p_fname) const { } - FileAccess *f = FileAccess::open(p_fname,FileAccess::READ); - ERR_FAIL_COND_V(!f,Vector<uint8_t>()); - Vector<uint8_t> ret; - ret.resize(f->get_len()); - int rbs = f->get_buffer(ret.ptr(),ret.size()); - memdelete(f); - return ret; + return get_exported_file_default(p_fname); + + } Vector<StringName> EditorExportPlatform::get_dependencies(bool p_bundles) const { @@ -557,6 +562,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func group_shrink*=EditorImportExport::get_singleton()->get_export_image_shrink(); switch(EditorImportExport::get_singleton()->image_export_group_get_image_action(E->get())) { + case EditorImportExport::IMAGE_ACTION_KEEP: case EditorImportExport::IMAGE_ACTION_NONE: { switch(EditorImportExport::get_singleton()->get_export_image_action()) { @@ -581,7 +587,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func } break; //use default case EditorImportExport::IMAGE_ACTION_COMPRESS_RAM: { group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM; - } break; //use default + } break; //use default } String image_list_md5; @@ -825,13 +831,32 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func StringName engine_cfg="res://engine.cfg"; + StringName boot_splash; + { + String splash=Globals::get_singleton()->get("application/boot_splash"); //avoid splash from being converted + splash=splash.strip_edges(); + if (splash!=String()) { + if (!splash.begins_with("res://")) + splash="res://"+splash; + splash=splash.simplify_path(); + boot_splash=splash; + } + } + + + for(int i=0;i<files.size();i++) { if (remap_files.has(files[i]) || files[i]==engine_cfg) //gonna be remapped (happened before!) continue; //from atlas? String src=files[i]; - Vector<uint8_t> buf = get_exported_file(src); + Vector<uint8_t> buf; + + if (src==boot_splash) + buf = get_exported_file_default(src); //bootsplash must be kept if used + else + buf = get_exported_file(src); ERR_CONTINUE( saved.has(src) ); @@ -1608,6 +1633,8 @@ void EditorImportExport::load_config() { g.action=IMAGE_ACTION_COMPRESS_RAM; else if (action=="compress_disk") g.action=IMAGE_ACTION_COMPRESS_DISK; + else if (action=="keep") + g.action=IMAGE_ACTION_KEEP; } if (d.has("atlas")) @@ -1735,6 +1762,7 @@ void EditorImportExport::save_config() { case IMAGE_ACTION_NONE: d["action"]="default"; break; case IMAGE_ACTION_COMPRESS_RAM: d["action"]="compress_ram"; break; case IMAGE_ACTION_COMPRESS_DISK: d["action"]="compress_disk"; break; + case IMAGE_ACTION_KEEP: d["action"]="keep"; break; } diff --git a/tools/editor/editor_import_export.h b/tools/editor/editor_import_export.h index f134a479a4..d8601929cf 100644 --- a/tools/editor/editor_import_export.h +++ b/tools/editor/editor_import_export.h @@ -83,6 +83,7 @@ public: typedef Error (*EditorExportSaveFunction)(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total); protected: + Vector<uint8_t> get_exported_file_default(String& p_fname) const; virtual Vector<uint8_t> get_exported_file(String& p_fname) const; virtual Vector<StringName> get_dependencies(bool p_bundles) const; @@ -227,6 +228,8 @@ public: IMAGE_ACTION_NONE, IMAGE_ACTION_COMPRESS_DISK, IMAGE_ACTION_COMPRESS_RAM, + IMAGE_ACTION_KEEP //for group + }; enum ScriptAction { diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index b0a2c568de..63684dcc93 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -93,7 +93,7 @@ #include "plugins/light_occluder_2d_editor_plugin.h" #include "plugins/color_ramp_editor_plugin.h" #include "plugins/collision_shape_2d_editor_plugin.h" - +#include "os/input.h" // end #include "tools/editor/io_plugins/editor_texture_import_plugin.h" #include "tools/editor/io_plugins/editor_scene_import_plugin.h" @@ -459,17 +459,74 @@ void EditorNode::open_resource(const String& p_type) { current_option=RESOURCE_LOAD; } -void EditorNode::save_resource(const Ref<Resource>& p_resource) { +void EditorNode::save_resource_in_path(const Ref<Resource>& p_resource,const String& p_path) { - ERR_FAIL_COND(p_resource.is_null() || p_resource->get_path()=="" || p_resource->get_path().find("::")!=-1); - resources_dock->save_resource(p_resource->get_path(),p_resource); + editor_data.apply_changes_in_editors(); + int flg=0; + if (EditorSettings::get_singleton()->get("on_save/compress_binary_resources")) + flg|=ResourceSaver::FLAG_COMPRESS; + if (EditorSettings::get_singleton()->get("on_save/save_paths_as_relative")) + flg|=ResourceSaver::FLAG_RELATIVE_PATHS; + + String path = Globals::get_singleton()->localize_path(p_path); + Error err = ResourceSaver::save(path,p_resource,flg|ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); + + if (err!=OK) { + accept->set_text("Error saving resource!"); + accept->popup_centered_minsize(); + return; + } +// EditorFileSystem::get_singleton()->update_file(path,p_resource->get_type()); + + ((Resource*)p_resource.ptr())->set_path(path); + emit_signal("resource_saved",p_resource); + +} + +void EditorNode::save_resource(const Ref<Resource>& p_resource) { + + if (p_resource->get_path().is_resource_file()) { + save_resource_in_path(p_resource,p_resource->get_path()); + } else { + save_resource_as(p_resource); + } } void EditorNode::save_resource_as(const Ref<Resource>& p_resource) { - resources_dock->save_resource_as(p_resource); + file->set_mode(EditorFileDialog::MODE_SAVE_FILE); + bool relpaths = (p_resource->has_meta("__editor_relpaths__") && p_resource->get_meta("__editor_relpaths__").operator bool()); + + List<String> extensions; + Ref<PackedScene> sd = memnew( PackedScene ); + ResourceSaver::get_recognized_extensions(p_resource,&extensions); + file->clear_filters(); + for(int i=0;i<extensions.size();i++) { + + file->add_filter("*."+extensions[i]+" ; "+extensions[i].to_upper()); + } + //file->set_current_path(current_path); + if (p_resource->get_path()!="") { + file->set_current_path(p_resource->get_path()); + if (extensions.size()) { + String ext=p_resource->get_path().extension().to_lower(); + if (extensions.find(ext)==NULL) { + file->set_current_path(p_resource->get_path().replacen("."+ext,"."+extensions.front()->get())); + } + } + } else { + + String existing; + if (extensions.size()) { + existing="new_"+p_resource->get_type().to_lower()+"."+extensions.front()->get().to_lower(); + } + file->set_current_path(existing); + + } + file->popup_centered_ratio(); + file->set_title("Save Resource As.."); } @@ -1049,7 +1106,7 @@ void EditorNode::_dialog_action(String p_file) { push_item(res.operator->() ); - } break; + } break; case FILE_OPEN_SCENE: { @@ -1320,7 +1377,20 @@ void EditorNode::_dialog_action(String p_file) { unzClose(pkg); } break; + case RESOURCE_SAVE: + case RESOURCE_SAVE_AS: { + + uint32_t current = editor_history.get_current(); + Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!current_obj->cast_to<Resource>()) + + RES current_res = RES(current_obj->cast_to<Resource>()); + + save_resource_in_path(current_res,p_file); + + } break; default: { //save scene? @@ -1358,6 +1428,67 @@ void EditorNode::push_item(Object *p_object,const String& p_property) { } +void EditorNode::_select_history(int p_idx) { + + //push it to the top, it is not correct, but it's more useful + ObjectID id=editor_history.get_history_obj(p_idx); + Object* obj=ObjectDB::get_instance(id); + if (!obj) + return; + push_item(obj); +} + +void EditorNode::_prepare_history() { + + int history_to = MAX(0,editor_history.get_history_len()-25); + + editor_history_menu->get_popup()->clear(); + + Ref<Texture> base_icon = gui_base->get_icon("Object","EditorIcons"); + Set<ObjectID> already; + for(int i=editor_history.get_history_len()-1;i>=history_to;i--) { + + + ObjectID id=editor_history.get_history_obj(i); + Object* obj=ObjectDB::get_instance(id); + if (!obj || already.has(id)) { + if (history_to>0) { + history_to--; + } + continue; + } + + already.insert(id); + + Ref<Texture> icon = gui_base->get_icon("Object","EditorIcons"); + if (gui_base->has_icon(obj->get_type(),"EditorIcons")) + icon=gui_base->get_icon(obj->get_type(),"EditorIcons"); + else + icon=base_icon; + + String text; + if (obj->cast_to<Resource>()) { + Resource *r=obj->cast_to<Resource>(); + if (r->get_path().is_resource_file()) + text=r->get_path().get_file(); + else if (r->get_name()!=String()) { + text=r->get_name(); + } else { + text=r->get_type(); + } + } else if (obj->cast_to<Node>()) { + text=obj->cast_to<Node>()->get_name(); + } else { + text=obj->get_type(); + } + + if (i==editor_history.get_history_pos()) { + text="["+text+"]"; + } + editor_history_menu->get_popup()->add_icon_item(icon,text,i); + } +} + void EditorNode::_property_editor_forward() { if (editor_history.next()) @@ -1402,6 +1533,9 @@ void EditorNode::_edit_current() { uint32_t current = editor_history.get_current(); Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + property_back->set_disabled( editor_history.is_at_begining() ); + property_forward->set_disabled( editor_history.is_at_end() ); + this->current=current_obj; editor_path->update_path(); @@ -1416,7 +1550,10 @@ void EditorNode::_edit_current() { object_menu->set_disabled(true); - if (current_obj->is_type("Resource")) { + bool is_resource = current_obj->is_type("Resource"); + resource_save_button->set_disabled(!is_resource); + + if (is_resource) { Resource *current_res = current_obj->cast_to<Resource>(); @@ -1425,12 +1562,11 @@ void EditorNode::_edit_current() { property_editor->edit( current_res ); object_menu->set_disabled(false); - resources_dock->add_resource(Ref<Resource>(current_res)); - //top_pallete->set_current_tab(1); - } + //resources_dock->add_resource(Ref<Resource>(current_res)); - if (current_obj->is_type("Node")) { + //top_pallete->set_current_tab(1); + } else if (current_obj->is_type("Node")) { Node * current_node = current_obj->cast_to<Node>(); ERR_FAIL_COND(!current_node); @@ -1445,6 +1581,12 @@ void EditorNode::_edit_current() { //top_pallete->set_current_tab(0); + } else { + + property_editor->edit( current_obj ); + //scene_tree_dock->set_selected(current_node); + //object_menu->get_popup()->clear(); + } /* Take care of PLUGIN EDITOR */ @@ -1517,7 +1659,13 @@ void EditorNode::_edit_current() { p->add_item("Copy Params",OBJECT_COPY_PARAMS); p->add_item("Set Params",OBJECT_PASTE_PARAMS); p->add_separator(); - p->add_item("Make Resources Unique",OBJECT_UNIQUE_RESOURCES); + p->add_item("Paste Resource",RESOURCE_PASTE); + if (is_resource) { + p->add_item("Copy Resource",RESOURCE_COPY); + p->add_item("Make Built-In",RESOURCE_UNREF); + } + p->add_separator(); + p->add_item("Make Sub-Resources Unique",OBJECT_UNIQUE_RESOURCES); p->add_separator(); p->add_icon_item(gui_base->get_icon("Help","EditorIcons"),"Class Reference",OBJECT_REQUEST_HELP); List<MethodInfo> methods; @@ -1550,6 +1698,20 @@ void EditorNode::_edit_current() { _update_keying(); } +void EditorNode::_resource_created() { + + Object *c = create_dialog->instance_selected(); + + ERR_FAIL_COND(!c); + Resource *r = c->cast_to<Resource>(); + ERR_FAIL_COND(!r); + + REF res( r ); + + push_item(c); + +} + void EditorNode::_resource_selected(const RES& p_res,const String& p_property) { @@ -1762,6 +1924,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) { int idx = editor_data.add_edited_scene(-1); _scene_tab_changed(idx); + editor_data.clear_editor_states(); //_cleanup_scene(); @@ -1804,6 +1967,13 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) { quick_open->set_title("Quick Open Script.."); } break; + case FILE_QUICK_OPEN_FILE: { + + + quick_open->popup("Resource",false,true); + quick_open->set_title("Quick Search File.."); + + } break; case FILE_RUN_SCRIPT: { file_script->popup_centered_ratio(); @@ -2266,7 +2436,70 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) { } break; #endif - + case RESOURCE_NEW: { + + create_dialog->popup_centered_ratio(); + } break; + case RESOURCE_LOAD: { + + open_resource(); + } break; + case RESOURCE_SAVE: { + + + uint32_t current = editor_history.get_current(); + Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!current_obj->cast_to<Resource>()) + + RES current_res = RES(current_obj->cast_to<Resource>()); + + save_resource(current_res); + + } break; + case RESOURCE_SAVE_AS: { + + uint32_t current = editor_history.get_current(); + Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!current_obj->cast_to<Resource>()) + + RES current_res = RES(current_obj->cast_to<Resource>()); + + save_resource_as(current_res); + + } break; + case RESOURCE_UNREF: { + + uint32_t current = editor_history.get_current(); + Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!current_obj->cast_to<Resource>()) + + RES current_res = RES(current_obj->cast_to<Resource>()); + current_res->set_path(""); + _edit_current(); + } break; + case RESOURCE_COPY: { + + uint32_t current = editor_history.get_current(); + Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!current_obj->cast_to<Resource>()) + + RES current_res = RES(current_obj->cast_to<Resource>()); + + EditorSettings::get_singleton()->set_resource_clipboard(current_res); + + } break; + case RESOURCE_PASTE: { + + RES r = EditorSettings::get_singleton()->get_resource_clipboard(); + if (r.is_valid()) { + push_item(EditorSettings::get_singleton()->get_resource_clipboard().ptr(),String()); + } + + } break; case OBJECT_REQUEST_HELP: { if (current) { @@ -3050,7 +3283,21 @@ void EditorNode::set_current_scene(int p_idx) { } -Error EditorNode::load_scene(const String& p_scene) { +bool EditorNode::is_scene_open(const String& p_path) { + + for(int i=0;i<editor_data.get_edited_scene_count();i++) { + if (editor_data.get_scene_path(i)==p_path) + return true; + } + + return false; +} + +void EditorNode::fix_dependencies(const String& p_for_file) { + dependency_fixer->edit(p_for_file); +} + +Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps) { if (!is_inside_tree()) { defer_load_scene = p_scene; @@ -3096,6 +3343,8 @@ Error EditorNode::load_scene(const String& p_scene) { //_cleanup_scene(); // i'm sorry but this MUST happen to avoid modified resources to not be reloaded. + dependency_errors.clear(); + Ref<PackedScene> sdata = ResourceLoader::load(lpath,"",true); if (!sdata.is_valid()) { @@ -3113,6 +3362,35 @@ Error EditorNode::load_scene(const String& p_scene) { return ERR_FILE_NOT_FOUND; } + if (!p_ignore_broken_deps && dependency_errors.has(lpath)) { + + current_option=-1; + Vector<String> errors; + for(Set<String>::Element *E=dependency_errors[lpath].front();E;E=E->next()) { + + errors.push_back(E->get()); + } + dependency_error->show(lpath,errors); + opening_prev=false; + + if (prev!=-1) { + set_current_scene(prev); + editor_data.remove_scene(idx); + } + return ERR_FILE_MISSING_DEPENDENCIES; + } + + dependency_errors.erase(lpath); //at least not self path + + for (Map<String,Set<String> >::Element *E=dependency_errors.front();E;E=E->next()) { + + String txt="Scene '"+E->key()+"' has broken dependencies:\n"; + for(Set<String>::Element *F=E->get().front();F;F=F->next()) { + txt+="\t"+F->get()+"\n"; + } + add_io_error(txt); + } + sdata->set_path(lpath,true); //take over path Node*new_scene=sdata->instance(true); @@ -3408,9 +3686,12 @@ void EditorNode::hide_animation_player_editors() { void EditorNode::_quick_opened(const String& p_resource) { - print_line("quick_opened"); - if (quick_open->get_base_type()=="PackedScene") { + if (current_option==FILE_QUICK_OPEN_FILE) { + scenes_dock->open(p_resource); + return; + } + if (quick_open->get_base_type()=="PackedScene") { open_request(p_resource); } else { load_resource(p_resource); @@ -3595,6 +3876,8 @@ void EditorNode::_bind_methods() { ObjectTypeDB::bind_method("_quick_opened",&EditorNode::_quick_opened); ObjectTypeDB::bind_method("_quick_run",&EditorNode::_quick_run); + ObjectTypeDB::bind_method("_resource_created",&EditorNode::_resource_created); + ObjectTypeDB::bind_method("_import_action",&EditorNode::_import_action); //ObjectTypeDB::bind_method("_import",&EditorNode::_import); // ObjectTypeDB::bind_method("_import_conflicts_solved",&EditorNode::_import_conflicts_solved); @@ -3624,6 +3907,8 @@ void EditorNode::_bind_methods() { ObjectTypeDB::bind_method("_set_main_scene_state",&EditorNode::_set_main_scene_state); ObjectTypeDB::bind_method("_update_scene_tabs",&EditorNode::_update_scene_tabs); + ObjectTypeDB::bind_method("_prepare_history",&EditorNode::_prepare_history); + ObjectTypeDB::bind_method("_select_history",&EditorNode::_select_history); ObjectTypeDB::bind_method(_MD("add_editor_import_plugin", "plugin"), &EditorNode::add_editor_import_plugin); @@ -4105,6 +4390,14 @@ EditorNode::EditorNode() { EditorHelp::generate_doc(); //before any editor classes are crated + if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) { + //only if no touchscreen ui hint, set emulation + InputDefault *id = Input::get_singleton()->cast_to<InputDefault>(); + if (id) + id->set_emulate_touch(false); //just disable just in case + } + + singleton=this; last_checked_version=0; changing_scene=false; @@ -4120,6 +4413,7 @@ EditorNode::EditorNode() { ResourceLoader::set_abort_on_missing_resources(false); FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("file_dialog/show_hidden_files")); ResourceLoader::set_error_notify_func(this,_load_error_notify); + ResourceLoader::set_dependency_error_notify_func(this,_dependency_error_report); ResourceLoader::set_timestamp_on_load(true); ResourceSaver::set_timestamp_on_save(true); @@ -4493,6 +4787,7 @@ EditorNode::EditorNode() { p->add_separator(); p->add_item("Quick Open Scene..",FILE_QUICK_OPEN_SCENE,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_O); p->add_item("Quick Open Script..",FILE_QUICK_OPEN_SCRIPT,KEY_MASK_ALT+KEY_MASK_CMD+KEY_O); + p->add_item("Quick Search File..",FILE_QUICK_OPEN_FILE,KEY_MASK_ALT+KEY_MASK_CMD+KEY_P); p->add_separator(); PopupMenu *pm_export = memnew(PopupMenu ); @@ -4735,13 +5030,14 @@ EditorNode::EditorNode() { scene_tree_dock->set_name("Scene"); //top_pallete->add_child(scene_tree_dock); dock_slot[DOCK_SLOT_LEFT_UR]->add_child(scene_tree_dock); - +#if 0 resources_dock = memnew( ResourcesDock(this) ); resources_dock->set_name("Resources"); //top_pallete->add_child(resources_dock); dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(resources_dock); //top_pallete->set_v_size_flags(Control::SIZE_EXPAND_FILL); - +#endif + dock_slot[DOCK_SLOT_RIGHT_BL]->hide(); /*Control *editor_spacer = memnew( Control ); editor_spacer->set_custom_minimum_size(Size2(260,200)); editor_spacer->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -4766,27 +5062,40 @@ EditorNode::EditorNode() { dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(prop_editor_base); HBoxContainer *prop_editor_hb = memnew( HBoxContainer ); - prop_editor_base->add_child(prop_editor_hb); - editor_path = memnew( EditorPath(&editor_history) ); - editor_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); - prop_editor_hb->add_child(editor_path); - - property_editor = memnew( PropertyEditor ); - property_editor->set_autoclear(true); - property_editor->set_show_categories(true); - property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); - - property_editor->hide_top_label(); - prop_editor_base->add_child( property_editor ); - property_editor->set_undo_redo(&editor_data.get_undo_redo()); + prop_editor_base->add_child(prop_editor_hb); + resource_new_button = memnew( ToolButton ); + resource_new_button->set_tooltip("Create a new resource in memory and edit it"); + resource_new_button->set_icon(gui_base->get_icon("New","EditorIcons")); + prop_editor_hb->add_child(resource_new_button); + resource_new_button->connect("pressed",this,"_menu_option",varray(RESOURCE_NEW)); + resource_new_button->set_focus_mode(Control::FOCUS_NONE); + + resource_load_button = memnew( ToolButton ); + resource_load_button->set_tooltip("Load an existing resource from disk and edit it"); + resource_load_button->set_icon(gui_base->get_icon("Load","EditorIcons")); + prop_editor_hb->add_child(resource_load_button); + resource_load_button->connect("pressed",this,"_menu_option",varray(RESOURCE_LOAD)); + resource_load_button->set_focus_mode(Control::FOCUS_NONE); + + resource_save_button = memnew( MenuButton ); + resource_save_button->set_tooltip("Save the currently edited resource"); + resource_save_button->set_icon(gui_base->get_icon("Save","EditorIcons")); + prop_editor_hb->add_child(resource_save_button); + resource_save_button->get_popup()->add_item("Save",RESOURCE_SAVE); + resource_save_button->get_popup()->add_item("Save As..",RESOURCE_SAVE_AS); + resource_save_button->get_popup()->connect("item_pressed",this,"_menu_option"); + resource_save_button->set_focus_mode(Control::FOCUS_NONE); + resource_save_button->set_disabled(true); + + prop_editor_hb->add_spacer(); - property_back = memnew( ToolButton ); property_back->set_icon( gui_base->get_icon("Back","EditorIcons") ); property_back->set_flat(true); property_back->set_tooltip("Go to the previous edited object in history."); + property_back->set_disabled(true); prop_editor_hb->add_child( property_back ); @@ -4794,14 +5103,48 @@ EditorNode::EditorNode() { property_forward->set_icon( gui_base->get_icon("Forward","EditorIcons") ); property_forward->set_flat(true); property_forward->set_tooltip("Go to the next edited object in history."); + property_forward->set_disabled(true); prop_editor_hb->add_child( property_forward ); + + editor_history_menu = memnew( MenuButton ); + editor_history_menu->set_icon( gui_base->get_icon("History","EditorIcons")); + prop_editor_hb->add_child(editor_history_menu); + editor_history_menu->connect("about_to_show",this,"_prepare_history"); + editor_history_menu->get_popup()->connect("item_pressed",this,"_select_history"); + + + prop_editor_hb = memnew( HBoxContainer ); //again... + + prop_editor_base->add_child(prop_editor_hb); + editor_path = memnew( EditorPath(&editor_history) ); + editor_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); + prop_editor_hb->add_child(editor_path); + + object_menu = memnew( MenuButton ); object_menu->set_icon(gui_base->get_icon("Tools","EditorIcons")); prop_editor_hb->add_child( object_menu ); object_menu->set_tooltip("Object properties."); + create_dialog = memnew( CreateDialog ); + gui_base->add_child(create_dialog); + create_dialog->set_base_type("Resource"); + create_dialog->connect("create",this,"_resource_created"); + + + property_editor = memnew( PropertyEditor ); + property_editor->set_autoclear(true); + property_editor->set_show_categories(true); + property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); + property_editor->set_use_doc_hints(true); + + property_editor->hide_top_label(); + + prop_editor_base->add_child( property_editor ); + property_editor->set_undo_redo(&editor_data.get_undo_redo()); + scenes_dock = memnew( ScenesDock(this) ); scenes_dock->set_name("FileSystem"); @@ -4929,7 +5272,11 @@ EditorNode::EditorNode() { + dependency_error = memnew( DependencyErrorDialog ); + gui_base->add_child(dependency_error); + dependency_fixer = memnew( DependencyEditor ); + gui_base->add_child( dependency_fixer ); settings_config_dialog = memnew( EditorSettingsDialog ); gui_base->add_child(settings_config_dialog); diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index d40658a056..dba2b7b86c 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -123,6 +123,7 @@ class EditorNode : public Node { FILE_OPEN_OLD_SCENE, FILE_QUICK_OPEN_SCENE, FILE_QUICK_OPEN_SCRIPT, + FILE_QUICK_OPEN_FILE, FILE_RUN_SCRIPT, FILE_OPEN_PREV, FILE_CLOSE, @@ -137,6 +138,7 @@ class EditorNode : public Node { RESOURCE_SAVE_AS, RESOURCE_UNREF, RESOURCE_COPY, + RESOURCE_PASTE, OBJECT_COPY_PARAMS, OBJECT_PASTE_PARAMS, OBJECT_UNIQUE_RESOURCES, @@ -256,11 +258,13 @@ class EditorNode : public Node { Button *property_back; Button *property_forward; SceneTreeDock *scene_tree_dock; - ResourcesDock *resources_dock; + //ResourcesDock *resources_dock; PropertyEditor *property_editor; ScenesDock *scenes_dock; EditorRunNative *run_native; + CreateDialog *create_dialog; + CallDialog *call_dialog; ConfirmationDialog *confirmation; ConfirmationDialog *import_confirmation; @@ -298,6 +302,10 @@ class EditorNode : public Node { HBoxContainer *animation_panel_hb; VBoxContainer *animation_vb; EditorPath *editor_path; + ToolButton *resource_new_button; + ToolButton *resource_load_button; + MenuButton *resource_save_button; + MenuButton *editor_history_menu; AnimationKeyEditor *animation_editor; EditorLog *log; CenterContainer *tabs_center; @@ -312,6 +320,9 @@ class EditorNode : public Node { ProgressDialog *progress_dialog; BackgroundProgress *progress_hb; + DependencyErrorDialog *dependency_error; + DependencyEditor *dependency_fixer; + TabContainer *dock_slot[DOCK_SLOT_MAX]; Rect2 dock_select_rect[DOCK_SLOT_MAX]; int dock_select_rect_over; @@ -367,6 +378,7 @@ class EditorNode : public Node { int current_option; //void _animation_visibility_toggle(); + void _resource_created(); void _resource_selected(const RES& p_res,const String& p_property=""); void _menu_option(int p_option); void _menu_confirm_current(); @@ -375,6 +387,9 @@ class EditorNode : public Node { void _property_editor_forward(); void _property_editor_back(); + void _select_history(int p_idx); + void _prepare_history(); + void _fs_changed(); void _sources_changed(bool p_exist); @@ -451,6 +466,16 @@ class EditorNode : public Node { void _save_scene_with_preview(String p_file); + Map<String,Set<String> > dependency_errors; + + static void _dependency_error_report(void *ud,const String& p_path,const String& p_dep,const String& p_type) { + EditorNode*en=(EditorNode*)ud; + if (!en->dependency_errors.has(p_path)) + en->dependency_errors[p_path]=Set<String>(); + en->dependency_errors[p_path].insert(p_dep+"::"+p_type); + + } + struct ExportDefer { String platform; String path; @@ -503,6 +528,8 @@ public: void edit_node(Node *p_node); void edit_resource(const Ref<Resource>& p_resource); void open_resource(const String& p_type=""); + + void save_resource_in_path(const Ref<Resource>& p_resource,const String& p_path); void save_resource(const Ref<Resource>& p_resource); void save_resource_as(const Ref<Resource>& p_resource); @@ -534,10 +561,13 @@ public: Viewport *get_scene_root() { return scene_root; } //root of the scene being edited Error save_optimized_copy(const String& p_scene,const String& p_preset); + void fix_dependencies(const String& p_for_file); void clear_scene() { _cleanup_scene(); } - Error load_scene(const String& p_scene); + Error load_scene(const String& p_scene,bool p_ignore_broken_deps=false); Error load_resource(const String& p_scene); + bool is_scene_open(const String& p_path); + void set_current_version(uint64_t p_version); void set_current_scene(int p_idx); diff --git a/tools/editor/editor_path.cpp b/tools/editor/editor_path.cpp index 86fd79d014..94e2efe346 100644 --- a/tools/editor/editor_path.cpp +++ b/tools/editor/editor_path.cpp @@ -73,7 +73,11 @@ void EditorPath::_notification(int p_what) { if (obj->cast_to<Resource>()) { Resource *r = obj->cast_to<Resource>(); - name=r->get_name(); + if (r->get_path().is_resource_file()) + name=r->get_path().get_file(); + else + name=r->get_name(); + if (name=="") name=r->get_type(); } else if (obj->cast_to<Node>()) { diff --git a/tools/editor/editor_run.cpp b/tools/editor/editor_run.cpp index 77c5f419b1..4d07463b21 100644 --- a/tools/editor/editor_run.cpp +++ b/tools/editor/editor_run.cpp @@ -28,7 +28,7 @@ /*************************************************************************/ #include "editor_run.h" #include "globals.h" - +#include "editor_settings.h" EditorRun::Status EditorRun::get_status() const { @@ -61,6 +61,70 @@ Error EditorRun::run(const String& p_scene,const String p_custom_args,const List } } + + int screen = EditorSettings::get_singleton()->get("game_window_placement/screen"); + + if (screen==0) { + screen=OS::get_singleton()->get_current_screen(); + } else { + screen--; + } + + Rect2 screen_rect; + screen_rect.pos=OS::get_singleton()->get_screen_position(screen); + screen_rect.size=OS::get_singleton()->get_screen_size(screen); + + + Size2 desired_size; + + desired_size.x=Globals::get_singleton()->get("display/width"); + desired_size.y=Globals::get_singleton()->get("display/height"); + + Size2 test_size; + test_size.x=Globals::get_singleton()->get("display/test_width"); + test_size.y=Globals::get_singleton()->get("display/test_height"); + if (test_size.x>0 && test_size.y>0) { + + desired_size=test_size; + } + + + int window_placement=EditorSettings::get_singleton()->get("game_window_placement/rect"); + + switch(window_placement) { + case 0: { // default + + args.push_back("-p"); + args.push_back(itos(screen_rect.pos.x)+"x"+itos(screen_rect.pos.y)); + } break; + case 1: { // centered + Vector2 pos=screen_rect.pos+((screen_rect.size-desired_size)/2).floor(); + args.push_back("-p"); + args.push_back(itos(pos.x)+"x"+itos(pos.y)); + } break; + case 2: { // custom pos + Vector2 pos = EditorSettings::get_singleton()->get("game_window_placement/rect_custom_position"); + pos+=screen_rect.pos; + args.push_back("-p"); + args.push_back(itos(pos.x)+"x"+itos(pos.y)); + } break; + case 3: { // force maximized + Vector2 pos=screen_rect.pos; + args.push_back("-p"); + args.push_back(itos(pos.x)+"x"+itos(pos.y)); + args.push_back("-mx"); + + } break; + case 4: { // force fullscreen + + Vector2 pos=screen_rect.pos; + args.push_back("-p"); + args.push_back(itos(pos.x)+"x"+itos(pos.y)); + args.push_back("-f"); + } break; + } + + if (p_breakpoints.size()) { args.push_back("-bp"); diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index 2f61d4f09d..a771893bdd 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -496,6 +496,15 @@ void EditorSettings::_load_defaults() { set("2d_editor/bone_selected_color",Color(0.9,0.45,0.45,0.9)); set("2d_editor/bone_ik_color",Color(0.9,0.9,0.45,0.9)); + set("game_window_placement/rect",0); + hints["game_window_placement/rect"]=PropertyInfo(Variant::INT,"game_window_placement/rect",PROPERTY_HINT_ENUM,"Default,Centered,Custom Position,Force Maximized,Force Full Screen"); + String screen_hints="Default (Same as Editor)"; + for(int i=0;i<OS::get_singleton()->get_screen_count();i++) { + screen_hints+=",Monitor "+itos(i+1); + } + set("game_window_placement/rect_custom_position",Vector2()); + set("game_window_placement/screen",0); + hints["game_window_placement/screen"]=PropertyInfo(Variant::INT,"game_window_placement/screen",PROPERTY_HINT_ENUM,screen_hints); set("on_save/compress_binary_resources",true); set("on_save/save_modified_external_resources",true); diff --git a/tools/editor/icons/icon_anchor.png b/tools/editor/icons/icon_anchor.png Binary files differnew file mode 100644 index 0000000000..1f9f9fa139 --- /dev/null +++ b/tools/editor/icons/icon_anchor.png diff --git a/tools/editor/icons/icon_control_align_bottom_center.png b/tools/editor/icons/icon_control_align_bottom_center.png Binary files differnew file mode 100644 index 0000000000..5ce9fe5c1c --- /dev/null +++ b/tools/editor/icons/icon_control_align_bottom_center.png diff --git a/tools/editor/icons/icon_control_align_bottom_left.png b/tools/editor/icons/icon_control_align_bottom_left.png Binary files differnew file mode 100644 index 0000000000..6c5129bf95 --- /dev/null +++ b/tools/editor/icons/icon_control_align_bottom_left.png diff --git a/tools/editor/icons/icon_control_align_bottom_right.png b/tools/editor/icons/icon_control_align_bottom_right.png Binary files differnew file mode 100644 index 0000000000..8857f4e940 --- /dev/null +++ b/tools/editor/icons/icon_control_align_bottom_right.png diff --git a/tools/editor/icons/icon_control_align_bottom_wide.png b/tools/editor/icons/icon_control_align_bottom_wide.png Binary files differnew file mode 100644 index 0000000000..56f009b8e4 --- /dev/null +++ b/tools/editor/icons/icon_control_align_bottom_wide.png diff --git a/tools/editor/icons/icon_control_align_center.png b/tools/editor/icons/icon_control_align_center.png Binary files differnew file mode 100644 index 0000000000..acd42525fa --- /dev/null +++ b/tools/editor/icons/icon_control_align_center.png diff --git a/tools/editor/icons/icon_control_align_center_left.png b/tools/editor/icons/icon_control_align_center_left.png Binary files differnew file mode 100644 index 0000000000..997074b097 --- /dev/null +++ b/tools/editor/icons/icon_control_align_center_left.png diff --git a/tools/editor/icons/icon_control_align_center_right.png b/tools/editor/icons/icon_control_align_center_right.png Binary files differnew file mode 100644 index 0000000000..b5cae63f7a --- /dev/null +++ b/tools/editor/icons/icon_control_align_center_right.png diff --git a/tools/editor/icons/icon_control_align_left_center.png b/tools/editor/icons/icon_control_align_left_center.png Binary files differnew file mode 100644 index 0000000000..7bb4dfb567 --- /dev/null +++ b/tools/editor/icons/icon_control_align_left_center.png diff --git a/tools/editor/icons/icon_control_align_left_wide.png b/tools/editor/icons/icon_control_align_left_wide.png Binary files differnew file mode 100644 index 0000000000..1b0a6cff95 --- /dev/null +++ b/tools/editor/icons/icon_control_align_left_wide.png diff --git a/tools/editor/icons/icon_control_align_right_center.png b/tools/editor/icons/icon_control_align_right_center.png Binary files differnew file mode 100644 index 0000000000..cf12d44c6a --- /dev/null +++ b/tools/editor/icons/icon_control_align_right_center.png diff --git a/tools/editor/icons/icon_control_align_right_wide.png b/tools/editor/icons/icon_control_align_right_wide.png Binary files differnew file mode 100644 index 0000000000..406ed25aed --- /dev/null +++ b/tools/editor/icons/icon_control_align_right_wide.png diff --git a/tools/editor/icons/icon_control_align_top_center.png b/tools/editor/icons/icon_control_align_top_center.png Binary files differnew file mode 100644 index 0000000000..da7ede984a --- /dev/null +++ b/tools/editor/icons/icon_control_align_top_center.png diff --git a/tools/editor/icons/icon_control_align_top_left.png b/tools/editor/icons/icon_control_align_top_left.png Binary files differnew file mode 100644 index 0000000000..84a224fbbe --- /dev/null +++ b/tools/editor/icons/icon_control_align_top_left.png diff --git a/tools/editor/icons/icon_control_align_top_right.png b/tools/editor/icons/icon_control_align_top_right.png Binary files differnew file mode 100644 index 0000000000..3b58eead9c --- /dev/null +++ b/tools/editor/icons/icon_control_align_top_right.png diff --git a/tools/editor/icons/icon_control_align_top_wide.png b/tools/editor/icons/icon_control_align_top_wide.png Binary files differnew file mode 100644 index 0000000000..869ae26134 --- /dev/null +++ b/tools/editor/icons/icon_control_align_top_wide.png diff --git a/tools/editor/icons/icon_control_align_wide.png b/tools/editor/icons/icon_control_align_wide.png Binary files differnew file mode 100644 index 0000000000..57a2933b25 --- /dev/null +++ b/tools/editor/icons/icon_control_align_wide.png diff --git a/tools/editor/icons/icon_control_hcenter_wide.png b/tools/editor/icons/icon_control_hcenter_wide.png Binary files differnew file mode 100644 index 0000000000..739ea5baeb --- /dev/null +++ b/tools/editor/icons/icon_control_hcenter_wide.png diff --git a/tools/editor/icons/icon_control_vcenter_wide.png b/tools/editor/icons/icon_control_vcenter_wide.png Binary files differnew file mode 100644 index 0000000000..44cbb8f344 --- /dev/null +++ b/tools/editor/icons/icon_control_vcenter_wide.png diff --git a/tools/editor/icons/icon_file_list.png b/tools/editor/icons/icon_file_list.png Binary files differindex e5e9213e61..ab790a85a5 100644 --- a/tools/editor/icons/icon_file_list.png +++ b/tools/editor/icons/icon_file_list.png diff --git a/tools/editor/icons/icon_filesystem.png b/tools/editor/icons/icon_filesystem.png Binary files differnew file mode 100644 index 0000000000..6841f9a792 --- /dev/null +++ b/tools/editor/icons/icon_filesystem.png diff --git a/tools/editor/icons/icon_history.png b/tools/editor/icons/icon_history.png Binary files differnew file mode 100644 index 0000000000..5c306c3ac9 --- /dev/null +++ b/tools/editor/icons/icon_history.png diff --git a/tools/editor/icons/icon_multi_node_edit.png b/tools/editor/icons/icon_multi_node_edit.png Binary files differnew file mode 100644 index 0000000000..357c062cbd --- /dev/null +++ b/tools/editor/icons/icon_multi_node_edit.png diff --git a/tools/editor/icons/icon_non_favorite.png b/tools/editor/icons/icon_non_favorite.png Binary files differnew file mode 100644 index 0000000000..edd806fbe8 --- /dev/null +++ b/tools/editor/icons/icon_non_favorite.png diff --git a/tools/editor/icons/icon_patch_9_frame.png b/tools/editor/icons/icon_patch_9_frame.png Binary files differnew file mode 100644 index 0000000000..c8f38fa61a --- /dev/null +++ b/tools/editor/icons/icon_patch_9_frame.png diff --git a/tools/editor/inspector_dock.cpp b/tools/editor/inspector_dock.cpp new file mode 100644 index 0000000000..57d19c3ec8 --- /dev/null +++ b/tools/editor/inspector_dock.cpp @@ -0,0 +1,22 @@ +#include "inspector_dock.h" + +#if 0 +void InspectorDock::_go_next() { + + +} + +void InspectorDock::_go_prev() { + + +} + +void InspectorDock::_bind_methods() { + +} + +InspectorDock::InspectorDock() { + + +} +#endif diff --git a/tools/editor/inspector_dock.h b/tools/editor/inspector_dock.h new file mode 100644 index 0000000000..90f043aba8 --- /dev/null +++ b/tools/editor/inspector_dock.h @@ -0,0 +1,35 @@ +#ifndef INSPECTOR_DOCK_H +#define INSPECTOR_DOCK_H + +#include "scene/gui/box_container.h" +#include "property_editor.h" + + +//this is for now bundled in EditorNode, will be moved away here eventually + +#if 0 +class InspectorDock : public VBoxContainer +{ + OBJ_TYPE(InspectorDock,VBoxContainer); + + PropertyEditor *property_editor; + + EditorHistory editor_history; + + void _go_next(); + void _go_prev(); + +protected: + + static void _bind_methods(); +public: + + EditorHistory &get_editor_history(); + + PropertyEditor *get_property_editor(); + + InspectorDock(); +}; + +#endif +#endif // INSPECTOR_DOCK_H diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp index d510333a32..d57cff850e 100644 --- a/tools/editor/io_plugins/editor_import_collada.cpp +++ b/tools/editor/io_plugins/editor_import_collada.cpp @@ -710,10 +710,126 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con //find largest source.. + /************************/ + /* ADD WEIGHTS IF EXIST */ + /************************/ + + Map<int,Vector<Collada::Vertex::Weight> > pre_weights; + + bool has_weights=false; + + if (skin_controller) { + + const Collada::SkinControllerData::Source *weight_src=NULL; + int weight_ofs=0; + + if (skin_controller->weights.sources.has("WEIGHT")) { + + String weight_id = skin_controller->weights.sources["WEIGHT"].source; + weight_ofs = skin_controller->weights.sources["WEIGHT"].offset; + if (skin_controller->sources.has(weight_id)) { + + weight_src = &skin_controller->sources[weight_id]; + + } + } + + int joint_ofs=0; + + if (skin_controller->weights.sources.has("JOINT")) { + + joint_ofs = skin_controller->weights.sources["JOINT"].offset; + } + + //should be OK, given this was pre-checked. + + int index_ofs=0; + int wstride = skin_controller->weights.sources.size(); + for(int w_i=0;w_i<skin_controller->weights.sets.size();w_i++) { + + int amount = skin_controller->weights.sets[w_i]; + + Vector<Collada::Vertex::Weight> weights; + + for (int a_i=0;a_i<amount;a_i++) { + + Collada::Vertex::Weight w; + + int read_from = index_ofs+a_i*wstride; + ERR_FAIL_INDEX_V(read_from+wstride-1,skin_controller->weights.indices.size(),ERR_INVALID_DATA); + int weight_index = skin_controller->weights.indices[read_from+weight_ofs]; + ERR_FAIL_INDEX_V(weight_index,weight_src->array.size(),ERR_INVALID_DATA); + + w.weight = weight_src->array[weight_index]; + + int bone_index = skin_controller->weights.indices[read_from+joint_ofs]; + if (bone_index==-1) + continue; //ignore this weight (refers to bind shape) + ERR_FAIL_INDEX_V(bone_index,bone_remap.size(),ERR_INVALID_DATA); + + w.bone_idx=bone_remap[bone_index]; + + + weights.push_back(w); + } + + /* FIX WEIGHTS */ + + + + weights.sort(); + + if (weights.size()>4) { + //cap to 4 and make weights add up 1 + weights.resize(4); + + } + + //make sure weights allways add up to 1 + float total=0; + for(int i=0;i<weights.size();i++) + total+=weights[i].weight; + if (total) + for(int i=0;i<weights.size();i++) + weights[i].weight/=total; + + if (weights.size()==0 || total==0) { //if nothing, add a weight to bone 0 + //no weights assigned + Collada::Vertex::Weight w; + w.bone_idx=0; + w.weight=1.0; + weights.clear(); + weights.push_back(w); + + } + + pre_weights[w_i]=weights; + + /* + for(Set<int>::Element *E=vertex_map[w_i].front();E;E=E->next()) { + + int dst = E->get(); + ERR_EXPLAIN("invalid vertex index in array"); + ERR_FAIL_INDEX_V(dst,vertex_array.size(),ERR_INVALID_DATA); + vertex_array[dst].weights=weights; + + }*/ + + + + + index_ofs+=wstride*amount; + + } + + //vertices need to be localized + has_weights=true; + + } Set<Collada::Vertex> vertex_set; //vertex set will be the vertices List<int> indices_list; //indices will be the indices - Map<int,Set<int> > vertex_map; //map vertices (for setting skinning/morph) + //Map<int,Set<int> > vertex_map; //map vertices (for setting skinning/morph) /**************************/ /* CREATE PRIMITIVE ARRAY */ @@ -753,11 +869,16 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con if (!p_optimize) vertex.uid=vertidx++; + + int vertex_index=p.indices[src+vertex_ofs]; //used for index field (later used by controllers) int vertex_pos = (vertex_src->stride?vertex_src->stride:3) * vertex_index; ERR_FAIL_INDEX_V(vertex_pos,vertex_src->array.size(),ERR_INVALID_DATA); vertex.vertex=Vector3(vertex_src->array[vertex_pos+0],vertex_src->array[vertex_pos+1],vertex_src->array[vertex_pos+2]); + if (pre_weights.has(vertex_index)) { + vertex.weights=pre_weights[vertex_index]; + } if (normal_src) { @@ -836,9 +957,9 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con vertex_set.insert(vertex); } - if (!vertex_map.has(vertex_index)) + /* if (!vertex_map.has(vertex_index)) vertex_map[vertex_index]=Set<int>(); - vertex_map[vertex_index].insert(index); //should be outside.. + vertex_map[vertex_index].insert(index); //should be outside..*/ //build triangles if needed if (j==0) prev2[0]=index; @@ -874,120 +995,10 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con vertex_array[F->get().idx]=F->get(); } - /************************/ - /* ADD WEIGHTS IF EXIST */ - /************************/ - - - bool has_weights=false; - - if (skin_controller) { - - const Collada::SkinControllerData::Source *weight_src=NULL; - int weight_ofs=0; - - if (skin_controller->weights.sources.has("WEIGHT")) { - - String weight_id = skin_controller->weights.sources["WEIGHT"].source; - weight_ofs = skin_controller->weights.sources["WEIGHT"].offset; - if (skin_controller->sources.has(weight_id)) { - - weight_src = &skin_controller->sources[weight_id]; - - } - } - - int joint_ofs=0; - - if (skin_controller->weights.sources.has("JOINT")) { - - joint_ofs = skin_controller->weights.sources["JOINT"].offset; - } - - //should be OK, given this was pre-checked. - - int index_ofs=0; - int wstride = skin_controller->weights.sources.size(); - for(int w_i=0;w_i<skin_controller->weights.sets.size();w_i++) { - - int amount = skin_controller->weights.sets[w_i]; - - if (vertex_map.has(w_i)) { //vertex may no longer be here, don't bother converting - Vector<Collada::Vertex::Weight> weights; - - for (int a_i=0;a_i<amount;a_i++) { - - Collada::Vertex::Weight w; - - int read_from = index_ofs+a_i*wstride; - ERR_FAIL_INDEX_V(read_from+wstride-1,skin_controller->weights.indices.size(),ERR_INVALID_DATA); - int weight_index = skin_controller->weights.indices[read_from+weight_ofs]; - ERR_FAIL_INDEX_V(weight_index,weight_src->array.size(),ERR_INVALID_DATA); - - w.weight = weight_src->array[weight_index]; - - int bone_index = skin_controller->weights.indices[read_from+joint_ofs]; - if (bone_index==-1) - continue; //ignore this weight (refers to bind shape) - ERR_FAIL_INDEX_V(bone_index,bone_remap.size(),ERR_INVALID_DATA); - - w.bone_idx=bone_remap[bone_index]; - - - weights.push_back(w); - } - - /* FIX WEIGHTS */ - - - - weights.sort(); - - if (weights.size()>4) { - //cap to 4 and make weights add up 1 - weights.resize(4); - - } - - //make sure weights allways add up to 1 - float total=0; - for(int i=0;i<weights.size();i++) - total+=weights[i].weight; - if (total) - for(int i=0;i<weights.size();i++) - weights[i].weight/=total; - - if (weights.size()==0 || total==0) { //if nothing, add a weight to bone 0 - //no weights assigned - Collada::Vertex::Weight w; - w.bone_idx=0; - w.weight=1.0; - weights.clear(); - weights.push_back(w); - - } - - - for(Set<int>::Element *E=vertex_map[w_i].front();E;E=E->next()) { - - int dst = E->get(); - ERR_EXPLAIN("invalid vertex index in array"); - ERR_FAIL_INDEX_V(dst,vertex_array.size(),ERR_INVALID_DATA); - vertex_array[dst].weights=weights; - - } - - } else { - //zzprint_line("no vertex found for index "+itos(w_i)); - } - - index_ofs+=wstride*amount; - - } - - //vertices need to be localized + if (has_weights) { + //if skeleton, localize Transform local_xform = p_local_xform; for(int i=0;i<vertex_array.size();i++) { @@ -1000,11 +1011,9 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con //vertex_array[i].tangent.normal*=-1.0; } } - - has_weights=true; - } + DVector<int> index_array; index_array.resize(indices_list.size()); DVector<int>::Write index_arrayw = index_array.write(); diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp index 4f7ec1839a..436725f6fb 100644 --- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp @@ -1068,12 +1068,14 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc //prepare atlas! Vector< Image > sources; + Vector< Image > tsources; bool alpha=false; bool crop = from->get_option("crop"); EditorProgress ep("make_atlas","Build Atlas For: "+p_path.get_file(),from->get_source_count()+3); print_line("sources: "+itos(from->get_source_count())); + for(int i=0;i<from->get_source_count();i++) { String path = EditorImportPlugin::expand_source_path(from->get_source_path(i)); @@ -1091,17 +1093,57 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc if (src.detect_alpha()) alpha=true; - sources.push_back(src); + tsources.push_back(src); } ep.step("Converting Images",sources.size()); - for(int i=0;i<sources.size();i++) { + int base_index=0; + + + Map<uint64_t,int> source_md5; + Map<int,List<int> > source_map; + + for(int i=0;i<tsources.size();i++) { + + Image src = tsources[i]; if (alpha) { - sources[i].convert(Image::FORMAT_RGBA); + src.convert(Image::FORMAT_RGBA); + } else { + src.convert(Image::FORMAT_RGB); + } + + DVector<uint8_t> data = src.get_data(); + MD5_CTX md5; + DVector<uint8_t>::Read r=data.read(); + MD5Init(&md5); + int len=data.size(); + for(int j=0;j<len;j++) { + uint8_t b = r[j]; + b>>=2; //to aid in comparing + MD5Update(&md5,(unsigned char*)&b,1); + } + MD5Final(&md5); + uint64_t *cmp = (uint64_t*)md5.digest; //less bits, but still useful for this + + tsources[i]=Image(); //clear + + if (source_md5.has(*cmp)) { + int sidx=source_md5[*cmp]; + source_map[sidx].push_back(i); + print_line("REUSING "+from->get_source_path(i)); + } else { - sources[i].convert(Image::FORMAT_RGB); + int sidx=sources.size(); + source_md5[*cmp]=sidx; + sources.push_back(src); + List<int> sm; + sm.push_back(i); + source_map[sidx]=sm; + } + + } //texturepacker is not really good for optimizing, so.. @@ -1141,28 +1183,44 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc Image atlas; atlas.create(nearest_power_of_2(dst_size.width),nearest_power_of_2(dst_size.height),0,alpha?Image::FORMAT_RGBA:Image::FORMAT_RGB); + + atlases.resize(from->get_source_count()); + for(int i=0;i<sources.size();i++) { int x=dst_positions[i].x; int y=dst_positions[i].y; - Ref<AtlasTexture> at = memnew( AtlasTexture ); Size2 sz = Size2(sources[i].get_width(),sources[i].get_height()); + + Rect2 region; + Rect2 margin; + if (crop && sz!=crops[i].size) { Rect2 rect = crops[i]; rect.size=sz-rect.size; - at->set_region(Rect2(x+border,y+border,crops[i].size.width,crops[i].size.height)); - at->set_margin(rect); + region=Rect2(x+border,y+border,crops[i].size.width,crops[i].size.height); + margin=rect; atlas.blit_rect(sources[i],crops[i],Point2(x+border,y+border)); } else { - at->set_region(Rect2(x+border,y+border,sz.x,sz.y)); + region=Rect2(x+border,y+border,sz.x,sz.y); atlas.blit_rect(sources[i],Rect2(0,0,sources[i].get_width(),sources[i].get_height()),Point2(x+border,y+border)); } - String apath = p_path.get_base_dir().plus_file(from->get_source_path(i).get_file().basename()+".atex"); - print_line("Atlas Tex: "+apath); - at->set_path(apath); - atlases.push_back(at); + ERR_CONTINUE( !source_map.has(i) ); + for (List<int>::Element *E=source_map[i].front();E;E=E->next()) { + + Ref<AtlasTexture> at = memnew( AtlasTexture ); + + + at->set_region(region); + at->set_margin(margin); + String apath = p_path.get_base_dir().plus_file(from->get_source_path(E->get()).get_file().basename()+".atex"); + at->set_path(apath); + atlases[E->get()]=at; + print_line("Atlas Tex: "+apath); + + } } if (ResourceCache::has(p_path)) { texture = Ref<ImageTexture> ( ResourceCache::get(p_path)->cast_to<ImageTexture>() ); @@ -1414,6 +1472,9 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c case EditorImportExport::IMAGE_ACTION_COMPRESS_RAM: { group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM; } break; //use default + case EditorImportExport::IMAGE_ACTION_KEEP: { + return Vector<uint8_t>(); + } break; //use default } diff --git a/tools/editor/multi_node_edit.cpp b/tools/editor/multi_node_edit.cpp new file mode 100644 index 0000000000..cfa998bee9 --- /dev/null +++ b/tools/editor/multi_node_edit.cpp @@ -0,0 +1,118 @@ +#include "multi_node_edit.h" +#include "editor_node.h" + +bool MultiNodeEdit::_set(const StringName& p_name, const Variant& p_value){ + + Node *es = EditorNode::get_singleton()->get_edited_scene(); + if (!es) + return false; + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action("MultiNode Set "+String(p_name)); + for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) { + + if (!es->has_node(E->get())) + continue; + + Node*n=es->get_node(E->get()); + if (!n) + continue; + + ur->add_do_property(n,p_name,p_value); + ur->add_undo_property(n,p_name,n->get(p_name)); + + } + + ur->commit_action(); + return true; +} + +bool MultiNodeEdit::_get(const StringName& p_name,Variant &r_ret) const { + + Node *es = EditorNode::get_singleton()->get_edited_scene(); + if (!es) + return false; + + for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) { + + if (!es->has_node(E->get())) + continue; + + const Node*n=es->get_node(E->get()); + if (!n) + continue; + + bool found; + r_ret=n->get(p_name,&found); + if (found) + return true; + + } + + return false; +} + +void MultiNodeEdit::_get_property_list( List<PropertyInfo> *p_list) const{ + + HashMap<String,PLData> usage; + + Node *es = EditorNode::get_singleton()->get_edited_scene(); + if (!es) + return; + + int nc=0; + + List<PLData*> datas; + + for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) { + + if (!es->has_node(E->get())) + continue; + + Node*n=es->get_node(E->get()); + if (!n) + continue; + + List<PropertyInfo> plist; + n->get_property_list(&plist,true); + + for(List<PropertyInfo>::Element *F=plist.front();F;F=F->next()) { + + if (!usage.has(F->get().name)) { + PLData pld; + pld.uses=0; + pld.info=F->get(); + usage[F->get().name]=pld; + datas.push_back(usage.getptr(F->get().name)); + } + + usage[F->get().name].uses++; + } + + nc++; + } + + for (List<PLData*>::Element *E=datas.front();E;E=E->next()) { + + if (nc==E->get()->uses) { + p_list->push_back(E->get()->info); + } + } + + +} + +void MultiNodeEdit::clear_nodes() { + + nodes.clear(); +} + +void MultiNodeEdit::add_node(const NodePath& p_node){ + + nodes.push_back(p_node); +} + +MultiNodeEdit::MultiNodeEdit() +{ +} diff --git a/tools/editor/multi_node_edit.h b/tools/editor/multi_node_edit.h new file mode 100644 index 0000000000..5a0cabf4be --- /dev/null +++ b/tools/editor/multi_node_edit.h @@ -0,0 +1,32 @@ +#ifndef MULTI_NODE_EDIT_H +#define MULTI_NODE_EDIT_H + +#include "scene/main/node.h" + +class MultiNodeEdit : public Reference { + + OBJ_TYPE(MultiNodeEdit,Reference); + + List<NodePath> nodes; + struct PLData { + int uses; + PropertyInfo info; + }; + +protected: + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + +public: + + + + void clear_nodes(); + void add_node(const NodePath& p_node); + + MultiNodeEdit(); +}; + +#endif // MULTI_NODE_EDIT_H diff --git a/tools/editor/plugins/animation_player_editor_plugin.cpp b/tools/editor/plugins/animation_player_editor_plugin.cpp index 05b12543d2..f8c484e886 100644 --- a/tools/editor/plugins/animation_player_editor_plugin.cpp +++ b/tools/editor/plugins/animation_player_editor_plugin.cpp @@ -549,6 +549,49 @@ void AnimationPlayerEditor::ensure_visibility() { _animation_edit(); } +Dictionary AnimationPlayerEditor::get_state() const { + + Dictionary d; + + d["visible"]=is_visible(); + if (is_visible() && player) { + d["player"]=EditorNode::get_singleton()->get_edited_scene()->get_path_to(player); + d["animation"]=player->get_current_animation(); + d["editing"]=edit_anim->is_pressed(); + } + + return d; + +} +void AnimationPlayerEditor::set_state(const Dictionary& p_state) { + + if (p_state.has("visible") && p_state["visible"]) { + + Node *n = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["player"]); + if (n && n->cast_to<AnimationPlayer>()) { + player=n->cast_to<AnimationPlayer>(); + _update_player(); + show(); + set_process(true); + ensure_visibility(); + EditorNode::get_singleton()->animation_panel_make_visible(true); + + if (p_state.has("animation")) { + String anim = p_state["animation"]; + _select_anim_by_name(anim); + if (p_state.has("editing") && p_state["editing"]) { + + edit_anim->set_pressed(true); + _animation_edit(); + } + } + + } + } + +} + + void AnimationPlayerEditor::_animation_resource_edit() { if (animation->get_item_count()) { @@ -1350,6 +1393,7 @@ AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin(EditorNode *p_node) { editor=p_node; anim_editor = memnew( AnimationPlayerEditor(editor) ); + anim_editor->set_undo_redo(editor->get_undo_redo()); editor->get_animation_panel()->add_child(anim_editor); /* editor->get_viewport()->add_child(anim_editor); diff --git a/tools/editor/plugins/animation_player_editor_plugin.h b/tools/editor/plugins/animation_player_editor_plugin.h index 9f0413088d..5705742565 100644 --- a/tools/editor/plugins/animation_player_editor_plugin.h +++ b/tools/editor/plugins/animation_player_editor_plugin.h @@ -151,6 +151,10 @@ protected: static void _bind_methods(); public: + Dictionary get_state() const; + void set_state(const Dictionary& p_state); + + void ensure_visibility(); void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo=p_undo_redo; } @@ -167,6 +171,9 @@ class AnimationPlayerEditorPlugin : public EditorPlugin { public: + virtual Dictionary get_state() const { return anim_editor->get_state(); } + virtual void set_state(const Dictionary& p_state) { anim_editor->set_state(p_state); } + virtual String get_name() const { return "Anim"; } bool has_main_screen() const { return false; } virtual void edit(Object *p_node); diff --git a/tools/editor/plugins/canvas_item_editor_plugin.cpp b/tools/editor/plugins/canvas_item_editor_plugin.cpp index f2738f0a62..8fc2945450 100644 --- a/tools/editor/plugins/canvas_item_editor_plugin.cpp +++ b/tools/editor/plugins/canvas_item_editor_plugin.cpp @@ -1910,12 +1910,20 @@ void CanvasItemEditor::_notification(int p_what) { List<Node*> &selection = editor_selection->get_selected_node_list(); + bool all_control=true; + bool has_control=false; + for(List<Node*>::Element *E=selection.front();E;E=E->next()) { CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>(); if (!canvas_item || !canvas_item->is_visible()) continue; + if (canvas_item->cast_to<Control>()) + has_control=true; + else + all_control=false; + CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item); if (!se) continue; @@ -1932,6 +1940,13 @@ void CanvasItemEditor::_notification(int p_what) { } + bool show_anchor = all_control && has_control; + if (show_anchor != !anchor_menu->is_hidden()) { + if (show_anchor) + anchor_menu->show(); + else + anchor_menu->hide(); + } for(Map<ObjectID,BoneList>::Element *E=bone_list.front();E;E=E->next()) { @@ -1974,6 +1989,32 @@ void CanvasItemEditor::_notification(int p_what) { ungroup_button->set_icon(get_icon("Ungroup","EditorIcons")); key_insert_button->set_icon(get_icon("Key","EditorIcons")); + + //anchor_menu->add_icon_override("Align Top Left"); + anchor_menu->set_icon(get_icon("Anchor","EditorIcons")); + PopupMenu *p=anchor_menu->get_popup(); + + p->add_icon_item(get_icon("ControlAlignTopLeft","EditorIcons"),"Top Left",ANCHOR_ALIGN_TOP_LEFT); + p->add_icon_item(get_icon("ControlAlignTopRight","EditorIcons"),"Top Right",ANCHOR_ALIGN_TOP_RIGHT); + p->add_icon_item(get_icon("ControlAlignBottomRight","EditorIcons"),"Bottom Right",ANCHOR_ALIGN_BOTTOM_RIGHT); + p->add_icon_item(get_icon("ControlAlignBottomLeft","EditorIcons"),"Bottom Left",ANCHOR_ALIGN_BOTTOM_LEFT); + p->add_separator(); + p->add_icon_item(get_icon("ControlAlignLeftCenter","EditorIcons"),"Center Left",ANCHOR_ALIGN_CENTER_LEFT); + p->add_icon_item(get_icon("ControlAlignTopCenter","EditorIcons"),"Center Top",ANCHOR_ALIGN_CENTER_TOP); + p->add_icon_item(get_icon("ControlAlignRightCenter","EditorIcons"),"Center Right",ANCHOR_ALIGN_CENTER_RIGHT); + p->add_icon_item(get_icon("ControlAlignBottomCenter","EditorIcons"),"Center Bottom",ANCHOR_ALIGN_CENTER_BOTTOM); + p->add_icon_item(get_icon("ControlAlignCenter","EditorIcons"),"Center",ANCHOR_ALIGN_CENTER); + p->add_separator(); + p->add_icon_item(get_icon("ControlAlignLeftWide","EditorIcons"),"Left Wide",ANCHOR_ALIGN_LEFT_WIDE); + p->add_icon_item(get_icon("ControlAlignTopWide","EditorIcons"),"Top Wide",ANCHOR_ALIGN_TOP_WIDE); + p->add_icon_item(get_icon("ControlAlignRightWide","EditorIcons"),"Right Wide",ANCHOR_ALIGN_RIGHT_WIDE); + p->add_icon_item(get_icon("ControlAlignBottomWide","EditorIcons"),"Bottom Wide",ANCHOR_ALIGN_BOTTOM_WIDE); + p->add_icon_item(get_icon("ControlVcenterWide","EditorIcons"),"VCenter Wide ",ANCHOR_ALIGN_VCENTER_WIDE); + p->add_icon_item(get_icon("ControlHcenterWide","EditorIcons"),"HCenter Wide ",ANCHOR_ALIGN_HCENTER_WIDE); + p->add_separator(); + p->add_icon_item(get_icon("ControlAlignWide","EditorIcons"),"Full Rect",ANCHOR_ALIGN_WIDE); + + } if (p_what==NOTIFICATION_READY) { @@ -2179,6 +2220,27 @@ void CanvasItemEditor::_update_scroll(float) { } +void CanvasItemEditor::_set_anchor(Control::AnchorType p_left,Control::AnchorType p_top,Control::AnchorType p_right,Control::AnchorType p_bottom) { + List<Node*> &selection = editor_selection->get_selected_node_list(); + + undo_redo->create_action("Change Anchors"); + for(List<Node*>::Element *E=selection.front();E;E=E->next()) { + + Control *c = E->get()->cast_to<Control>(); + + undo_redo->add_do_method(c,"set_anchor",MARGIN_LEFT,p_left); + undo_redo->add_do_method(c,"set_anchor",MARGIN_TOP,p_top); + undo_redo->add_do_method(c,"set_anchor",MARGIN_RIGHT,p_right); + undo_redo->add_do_method(c,"set_anchor",MARGIN_BOTTOM,p_bottom); + undo_redo->add_undo_method(c,"set_anchor",MARGIN_LEFT,c->get_anchor(MARGIN_LEFT)); + undo_redo->add_undo_method(c,"set_anchor",MARGIN_TOP,c->get_anchor(MARGIN_TOP)); + undo_redo->add_undo_method(c,"set_anchor",MARGIN_RIGHT,c->get_anchor(MARGIN_RIGHT)); + undo_redo->add_undo_method(c,"set_anchor",MARGIN_BOTTOM,c->get_anchor(MARGIN_BOTTOM)); + } + + undo_redo->commit_action(); + +} void CanvasItemEditor::_popup_callback(int p_op) { @@ -2381,6 +2443,56 @@ void CanvasItemEditor::_popup_callback(int p_op) { case SPACE_VERTICAL: { //space_selected_items< proj_vector2_y, compare_items_y >(); } break; + case ANCHOR_ALIGN_TOP_LEFT: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_BEGIN); + } break; + case ANCHOR_ALIGN_TOP_RIGHT: { + _set_anchor(ANCHOR_END,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_BEGIN); + } break; + case ANCHOR_ALIGN_BOTTOM_LEFT: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_END,ANCHOR_BEGIN,ANCHOR_END); + } break; + case ANCHOR_ALIGN_BOTTOM_RIGHT: { + _set_anchor(ANCHOR_END,ANCHOR_END,ANCHOR_END,ANCHOR_END); + } break; + case ANCHOR_ALIGN_CENTER_LEFT: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_BEGIN,ANCHOR_CENTER); + } break; + case ANCHOR_ALIGN_CENTER_RIGHT: { + + _set_anchor(ANCHOR_END,ANCHOR_CENTER,ANCHOR_END,ANCHOR_CENTER); + } break; + case ANCHOR_ALIGN_CENTER_TOP: { + _set_anchor(ANCHOR_CENTER,ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_BEGIN); + } break; + case ANCHOR_ALIGN_CENTER_BOTTOM: { + _set_anchor(ANCHOR_CENTER,ANCHOR_END,ANCHOR_CENTER,ANCHOR_END); + } break; + case ANCHOR_ALIGN_CENTER: { + _set_anchor(ANCHOR_CENTER,ANCHOR_CENTER,ANCHOR_CENTER,ANCHOR_CENTER); + } break; + case ANCHOR_ALIGN_TOP_WIDE: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_BEGIN); + } break; + case ANCHOR_ALIGN_LEFT_WIDE: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_END); + } break; + case ANCHOR_ALIGN_RIGHT_WIDE: { + _set_anchor(ANCHOR_END,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_END); + } break; + case ANCHOR_ALIGN_BOTTOM_WIDE: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_END,ANCHOR_END,ANCHOR_END); + } break; + case ANCHOR_ALIGN_VCENTER_WIDE: { + _set_anchor(ANCHOR_CENTER,ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_END); + } break; + case ANCHOR_ALIGN_HCENTER_WIDE: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_END,ANCHOR_CENTER); + } break; + case ANCHOR_ALIGN_WIDE: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_END); + } break; + case ANIM_INSERT_KEY: case ANIM_INSERT_KEY_EXISTING: { @@ -2999,6 +3111,14 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_item("Center Selection", VIEW_CENTER_TO_SELECTION, KEY_F); p->add_item("Frame Selection", VIEW_FRAME_TO_SELECTION, KEY_MASK_CMD|KEY_F); + anchor_menu = memnew( MenuButton ); + anchor_menu->set_text("Anchor"); + hb->add_child(anchor_menu); + anchor_menu->get_popup()->connect("item_pressed", this,"_popup_callback"); + anchor_menu->hide(); + + //p = anchor_menu->get_popup(); + animation_hb = memnew( HBoxContainer ); diff --git a/tools/editor/plugins/canvas_item_editor_plugin.h b/tools/editor/plugins/canvas_item_editor_plugin.h index 48a34e2d07..485422028e 100644 --- a/tools/editor/plugins/canvas_item_editor_plugin.h +++ b/tools/editor/plugins/canvas_item_editor_plugin.h @@ -90,6 +90,23 @@ class CanvasItemEditor : public VBoxContainer { UNGROUP_SELECTED, ALIGN_HORIZONTAL, ALIGN_VERTICAL, + ANCHOR_ALIGN_TOP_LEFT, + ANCHOR_ALIGN_TOP_RIGHT, + ANCHOR_ALIGN_BOTTOM_LEFT, + ANCHOR_ALIGN_BOTTOM_RIGHT, + ANCHOR_ALIGN_CENTER_LEFT, + ANCHOR_ALIGN_CENTER_RIGHT, + ANCHOR_ALIGN_CENTER_TOP, + ANCHOR_ALIGN_CENTER_BOTTOM, + ANCHOR_ALIGN_CENTER, + ANCHOR_ALIGN_TOP_WIDE, + ANCHOR_ALIGN_LEFT_WIDE, + ANCHOR_ALIGN_RIGHT_WIDE, + ANCHOR_ALIGN_BOTTOM_WIDE, + ANCHOR_ALIGN_VCENTER_WIDE, + ANCHOR_ALIGN_HCENTER_WIDE, + ANCHOR_ALIGN_WIDE, + SPACE_HORIZONTAL, SPACE_VERTICAL, EXPAND_TO_PARENT, @@ -225,6 +242,7 @@ class CanvasItemEditor : public VBoxContainer { MenuButton *view_menu; HBoxContainer *animation_hb; MenuButton *animation_menu; + MenuButton *anchor_menu; Button *key_loc_button; Button *key_rot_button; @@ -305,6 +323,8 @@ class CanvasItemEditor : public VBoxContainer { void _viewport_input_event(const InputEvent& p_event); void _viewport_draw(); + void _set_anchor(Control::AnchorType p_left,Control::AnchorType p_top,Control::AnchorType p_right,Control::AnchorType p_bottom); + HSplitContainer *palette_split; VSplitContainer *bottom_split; diff --git a/tools/editor/plugins/mesh_editor_plugin.cpp b/tools/editor/plugins/mesh_editor_plugin.cpp index 2c64b2eb6b..13d4c8db5a 100644 --- a/tools/editor/plugins/mesh_editor_plugin.cpp +++ b/tools/editor/plugins/mesh_editor_plugin.cpp @@ -216,6 +216,8 @@ MeshInstanceEditor::MeshInstanceEditor() { SpatialEditor::get_singleton()->add_control_to_menu_panel(options); options->set_text("Mesh"); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshInstance","EditorIcons")); + options->get_popup()->add_item("Create Trimesh Static Body",MENU_OPTION_CREATE_STATIC_TRIMESH_BODY); options->get_popup()->add_item("Create Convex Static Body",MENU_OPTION_CREATE_STATIC_CONVEX_BODY); options->get_popup()->add_separator(); diff --git a/tools/editor/plugins/multimesh_editor_plugin.cpp b/tools/editor/plugins/multimesh_editor_plugin.cpp index 0df906117e..3c88b1d3a8 100644 --- a/tools/editor/plugins/multimesh_editor_plugin.cpp +++ b/tools/editor/plugins/multimesh_editor_plugin.cpp @@ -330,6 +330,8 @@ MultiMeshEditor::MultiMeshEditor() { options->set_area_as_parent_rect(); options->set_text("MultiMesh"); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MultiMeshInstance","EditorIcons")); + options->get_popup()->add_item("Populate Surface"); options->get_popup()->connect("item_pressed", this,"_menu_option"); diff --git a/tools/editor/plugins/particles_2d_editor_plugin.cpp b/tools/editor/plugins/particles_2d_editor_plugin.cpp index fdf534a3a8..dadfa8bfdc 100644 --- a/tools/editor/plugins/particles_2d_editor_plugin.cpp +++ b/tools/editor/plugins/particles_2d_editor_plugin.cpp @@ -146,6 +146,7 @@ void Particles2DEditorPlugin::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { menu->get_popup()->connect("item_pressed",this,"_menu_callback"); + menu->set_icon(menu->get_popup()->get_icon("Particles2D","EditorIcons")); file->connect("file_selected",this,"_file_selected"); } } diff --git a/tools/editor/plugins/particles_editor_plugin.cpp b/tools/editor/plugins/particles_editor_plugin.cpp index f6f01d82ca..5c84d9a86a 100644 --- a/tools/editor/plugins/particles_editor_plugin.cpp +++ b/tools/editor/plugins/particles_editor_plugin.cpp @@ -111,6 +111,7 @@ void ParticlesEditor::_populate() { void ParticlesEditor::_notification(int p_notification) { if (p_notification==NOTIFICATION_ENTER_TREE) { + options->set_icon(options->get_popup()->get_icon("Particles","EditorIcons")); } } diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 77663f39c0..8fc6a6931e 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -2168,7 +2168,18 @@ void SpatialEditorViewport::set_state(const Dictionary& p_state) { view_menu->get_popup()->set_item_checked( idx, listener ); } - + if (p_state.has("previewing")) { + Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]); + if (pv && pv->cast_to<Camera>()) { + previewing=pv->cast_to<Camera>(); + previewing->connect("exit_tree",this,"_preview_exited_scene"); + VS::get_singleton()->viewport_attach_camera( viewport->get_viewport(), previewing->get_camera() ); //replace + view_menu->hide(); + surface->update(); + preview_camera->set_pressed(true); + preview_camera->show(); + } + } } Dictionary SpatialEditorViewport::get_state() const { @@ -2181,6 +2192,10 @@ Dictionary SpatialEditorViewport::get_state() const { d["use_environment"]=camera->get_environment().is_valid(); d["use_orthogonal"]=camera->get_projection()==Camera::PROJECTION_ORTHOGONAL; d["listener"]=viewport->is_audio_listener(); + if (previewing) { + d["previewing"]=EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing); + } + return d; } diff --git a/tools/editor/project_export.cpp b/tools/editor/project_export.cpp index a087f23c25..9f871fd3ab 100644 --- a/tools/editor/project_export.cpp +++ b/tools/editor/project_export.cpp @@ -80,7 +80,7 @@ bool ProjectExportDialog::_create_tree(TreeItem *p_parent,EditorFileSystemDirect String path = p_dir->get_file_path(i); fitem->set_tooltip(0,path); fitem->set_metadata(0,path); - Ref<Texture> icon = get_icon( (has_icon(p_dir->get_file_type(i),"EditorIcons")?p_dir->get_file_type(i):String("Object")),"EditorIcons"); + Ref<Texture> icon = get_icon( (has_icon(p_dir->get_file_type(i),ei)?p_dir->get_file_type(i):ot),ei); fitem->set_icon(0,icon); fitem->set_cell_mode(1,TreeItem::CELL_MODE_RANGE); @@ -1216,6 +1216,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { group_image_action->add_item("Default"); group_image_action->add_item("Compress Disk"); group_image_action->add_item("Compress RAM"); + group_image_action->add_item("Keep Original"); group_options->add_margin_child("Compress Mode:",group_image_action); group_image_action->connect("item_selected",this,"_group_changed"); @@ -1372,6 +1373,8 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { button_export = add_button("Export..",!OS::get_singleton()->get_swap_ok_cancel(),"export_pck"); updating_script=false; + ei="EditorIcons"; + ot="Object"; } diff --git a/tools/editor/project_export.h b/tools/editor/project_export.h index c88233ae01..d85e688e58 100644 --- a/tools/editor/project_export.h +++ b/tools/editor/project_export.h @@ -78,6 +78,9 @@ private: HBoxContainer *plat_errors; Label *platform_error_string; + StringName ei; + StringName ot; + Tree * tree; EditorFileDialog *pck_export; diff --git a/tools/editor/project_settings.cpp b/tools/editor/project_settings.cpp index fea9c705ef..25a2750166 100644 --- a/tools/editor/project_settings.cpp +++ b/tools/editor/project_settings.cpp @@ -771,18 +771,47 @@ void ProjectSettings::_autoload_add() { void ProjectSettings::_autoload_delete(Object *p_item,int p_column, int p_button) { + TreeItem *ti=p_item->cast_to<TreeItem>(); String name = "autoload/"+ti->get_text(0); - undo_redo->create_action("Remove Autoload"); - undo_redo->add_do_property(Globals::get_singleton(),name,Variant()); - undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name)); - undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",name,true); - undo_redo->add_do_method(this,"_update_autoload"); - undo_redo->add_undo_method(this,"_update_autoload"); - undo_redo->add_do_method(this,"_settings_changed"); - undo_redo->add_undo_method(this,"_settings_changed"); - undo_redo->commit_action(); + if (p_button==0) { + //delete + undo_redo->create_action("Remove Autoload"); + undo_redo->add_do_property(Globals::get_singleton(),name,Variant()); + undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name)); + undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",name,true); + undo_redo->add_do_method(this,"_update_autoload"); + undo_redo->add_undo_method(this,"_update_autoload"); + undo_redo->add_do_method(this,"_settings_changed"); + undo_redo->add_undo_method(this,"_settings_changed"); + undo_redo->commit_action(); + } else { + + TreeItem *swap; + + if (p_button==1) { + swap=ti->get_prev(); + } else if (p_button==2) { + swap=ti->get_next(); + } + if (!swap) + return; + + String swap_name= "autoload/"+swap->get_text(0); + + undo_redo->create_action("Move Autoload"); + undo_redo->add_do_method(Globals::get_singleton(),"set_order",swap_name,Globals::get_singleton()->get_order(name)); + undo_redo->add_do_method(Globals::get_singleton(),"set_order",name,Globals::get_singleton()->get_order(swap_name)); + undo_redo->add_undo_method(Globals::get_singleton(),"set_order",swap_name,Globals::get_singleton()->get_order(swap_name)); + undo_redo->add_undo_method(Globals::get_singleton(),"set_order",name,Globals::get_singleton()->get_order(name)); + undo_redo->add_do_method(this,"_update_autoload"); + undo_redo->add_undo_method(this,"_update_autoload"); + undo_redo->add_do_method(this,"_settings_changed"); + undo_redo->add_undo_method(this,"_settings_changed"); + undo_redo->commit_action(); + + } } @@ -1134,6 +1163,8 @@ void ProjectSettings::_update_autoload() { TreeItem *t = autoload_list->create_item(root); t->set_text(0,name); t->set_text(1,Globals::get_singleton()->get(pi.name)); + t->add_button(1,get_icon("MoveUp","EditorIcons"),1); + t->add_button(1,get_icon("MoveDown","EditorIcons"),2); t->add_button(1,get_icon("Del","EditorIcons"),0); } diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index 955c426d2b..b513e32c13 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -39,6 +39,9 @@ #include "editor_settings.h" #include "editor_import_export.h" #include "editor_node.h" +#include "multi_node_edit.h" +#include "array_property_edit.h" +#include "editor_help.h" void CustomPropertyEditor::_notification(int p_what) { @@ -2212,6 +2215,23 @@ void PropertyEditor::update_tree() { sep->set_selectable(1,false); sep->set_custom_bg_color(0,get_color("prop_category","Editor")); sep->set_custom_bg_color(1,get_color("prop_category","Editor")); + + if (use_doc_hints) { + StringName type=p.name; + if (!class_descr_cache.has(type)) { + + String descr; + DocData *dd=EditorHelp::get_doc_data(); + Map<String,DocData::ClassDoc>::Element *E=dd->class_list.find(type); + if (E) { + descr=E->get().brief_description; + } + class_descr_cache[type]=descr.world_wrap(80); + + } + + sep->set_tooltip(0,"Class: "+p.name+":\n\n"+class_descr_cache[type]); + } //sep->set_custom_color(0,Color(1,1,1)); @@ -2265,6 +2285,42 @@ void PropertyEditor::update_tree() { item->set_tooltip(0, p.name); + if (use_doc_hints) { + StringName setter; + StringName type; + if (ObjectTypeDB::get_setter_and_type_for_property(obj->get_type_name(),p.name,type,setter)) { + + String descr; + bool found=false; + Map<StringName,Map<StringName,String> >::Element *E=descr_cache.find(type); + if (E) { + + Map<StringName,String>::Element *F=E->get().find(setter); + if (F) { + found=true; + descr=F->get(); + } + } + if (!found) { + + DocData *dd=EditorHelp::get_doc_data(); + Map<String,DocData::ClassDoc>::Element *E=dd->class_list.find(type); + if (E) { + for(int i=0;i<E->get().methods.size();i++) { + if (E->get().methods[i].name==setter.operator String()) { + descr=E->get().methods[i].description.strip_edges().world_wrap(80); + } + } + } + + descr_cache[type][setter]=descr; + } + + item->set_tooltip(0, "Property: "+p.name+"\n\n"+descr); + } + } + //EditorHelp::get_doc_data(); + Dictionary d; d["name"]=p.name; d["type"]=(int)p.type; @@ -2347,8 +2403,10 @@ void PropertyEditor::update_tree() { item->set_cell_mode( 1, TreeItem::CELL_MODE_RANGE ); + if (p.hint==PROPERTY_HINT_SPRITE_FRAME) { + item->set_range_config(1,0,99999,1); - if (p.hint==PROPERTY_HINT_RANGE || p.hint==PROPERTY_HINT_EXP_RANGE) { + } else if (p.hint==PROPERTY_HINT_RANGE || p.hint==PROPERTY_HINT_EXP_RANGE) { int c = p.hint_string.get_slice_count(","); float min=0,max=100,step=1; @@ -2449,11 +2507,32 @@ void PropertyEditor::update_tree() { } } break; + case Variant::ARRAY: { + + item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"Array["+itos(v.call("size"))+"]"); + else + item->set_text(1,"Array[]"); + item->set_icon( 0, get_icon("ArrayData","EditorIcons") ); + + + } break; + case Variant::INT_ARRAY: { item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); - item->set_editable( 1, !read_only ); - item->set_text(1,"[IntArray]"); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"IntArray["+itos(v.call("size"))+"]"); + else + item->set_text(1,"IntArray[]"); item->set_icon( 0, get_icon("ArrayInt","EditorIcons") ); @@ -2461,26 +2540,86 @@ void PropertyEditor::update_tree() { case Variant::REAL_ARRAY: { item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); - item->set_editable( 1, !read_only ); - item->set_text(1,"[RealArray]"); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"FloatArray["+itos(v.call("size"))+"]"); + else + item->set_text(1,"FloatArray[]"); item->set_icon( 0, get_icon("ArrayReal","EditorIcons") ); + } break; case Variant::STRING_ARRAY: { item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); - item->set_editable( 1, !read_only ); - item->set_text(1,"[StringArray]"); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"String["+itos(v.call("size"))+"]"); + else + item->set_text(1,"String[]"); item->set_icon( 0, get_icon("ArrayString","EditorIcons") ); + } break; case Variant::RAW_ARRAY: { item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); - item->set_editable( 1, !read_only ); - item->set_text(1,"[Raw Data]"); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"Byte["+itos(v.call("size"))+"]"); + else + item->set_text(1,"Byte[]"); item->set_icon( 0, get_icon("ArrayData","EditorIcons") ); + + } break; + case Variant::VECTOR2_ARRAY: { + + item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"Vector2["+itos(v.call("size"))+"]"); + else + item->set_text(1,"Vector2[]"); + item->set_icon( 0, get_icon("Vector2","EditorIcons") ); + + + } break; + case Variant::VECTOR3_ARRAY: { + + item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"Vector3["+itos(v.call("size"))+"]"); + else + item->set_text(1,"Vector3[]"); + item->set_icon( 0, get_icon("Vector","EditorIcons") ); + + + } break; + case Variant::COLOR_ARRAY: { + + item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"Color["+itos(v.call("size"))+"]"); + else + item->set_text(1,"Color[]"); + item->set_icon( 0, get_icon("Color","EditorIcons") ); + + } break; case Variant::VECTOR2: { @@ -2676,7 +2815,7 @@ void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value) { } } - if (!undo_redo) { + if (!undo_redo || obj->cast_to<MultiNodeEdit>() || obj->cast_to<ArrayPropertyEdit>()) { //kind of hacky obj->set(p_name,p_value); _changed_callbacks(obj,p_name); @@ -2996,6 +3135,19 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) { emit_signal("resource_selected",r,n); } + } else if (t==Variant::ARRAY || t==Variant::INT_ARRAY || t==Variant::REAL_ARRAY || t==Variant::STRING_ARRAY || t==Variant::VECTOR2_ARRAY || t==Variant::VECTOR3_ARRAY || t==Variant::COLOR_ARRAY || t==Variant::RAW_ARRAY) { + + Variant v = obj->get(n); + + if (v.get_type()!=t) { + Variant::CallError ce; + v=Variant::construct(Variant::Type(t),NULL,0,ce); + } + + Ref<ArrayPropertyEdit> ape = memnew( ArrayPropertyEdit ); + ape->edit(obj,n,Variant::Type(t)); + + EditorNode::get_singleton()->push_item(ape.ptr()); } } } @@ -3181,6 +3333,7 @@ PropertyEditor::PropertyEditor() { read_only=false; show_categories=false; refresh_countdown=0; + use_doc_hints=false; } diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h index de5cac8711..36ecc794ed 100644 --- a/tools/editor/property_editor.h +++ b/tools/editor/property_editor.h @@ -95,6 +95,7 @@ class CustomPropertyEditor : public Popup { Button *checks20[20]; + Control *easing_draw; Object* owner; @@ -157,9 +158,13 @@ class PropertyEditor : public Control { bool read_only; bool show_categories; float refresh_countdown; + bool use_doc_hints; HashMap<String,String> pending; String selected_property; + + Map<StringName,Map<StringName,String> > descr_cache; + Map<StringName,String > class_descr_cache; CustomPropertyEditor *custom_editor; @@ -217,6 +222,7 @@ public: void set_autoclear(bool p_enable); void set_show_categories(bool p_show); + void set_use_doc_hints(bool p_enable) { use_doc_hints=p_enable; } PropertyEditor(); ~PropertyEditor(); diff --git a/tools/editor/quick_open.cpp b/tools/editor/quick_open.cpp index 749318386c..6135a4ab64 100644 --- a/tools/editor/quick_open.cpp +++ b/tools/editor/quick_open.cpp @@ -30,8 +30,9 @@ #include "os/keyboard.h" -void EditorQuickOpen::popup(const String& p_base, bool p_dontclear) { +void EditorQuickOpen::popup(const StringName &p_base, bool p_dontclear, bool p_add_dirs) { + add_directories=p_add_dirs; popup_centered_ratio(0.6); if (p_dontclear) search_box->select_all(); @@ -66,27 +67,53 @@ void EditorQuickOpen::_sbox_input(const InputEvent& p_ie) { void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd) { - for(int i=0;i<efsd->get_subdir_count();i++) { + if (!add_directories) { + for(int i=0;i<efsd->get_subdir_count();i++) { - _parse_fs(efsd->get_subdir(i)); + _parse_fs(efsd->get_subdir(i)); + } } + TreeItem *root = search_options->get_root(); + + if (add_directories) { + String path = efsd->get_path(); + if (!path.ends_with("/")) + path+="/"; + if (path!="res://") { + path=path.substr(6,path.length()); + if (path.findn(search_box->get_text())!=-1) { + TreeItem *ti = search_options->create_item(root); + ti->set_text(0,path); + Ref<Texture> icon = get_icon("folder","FileDialog"); + ti->set_icon(0,icon); + } + } + } for(int i=0;i<efsd->get_file_count();i++) { String file = efsd->get_file_path(i); file=file.substr(6,file.length()); if (ObjectTypeDB::is_type(efsd->get_file_type(i),base_type) && (search_box->get_text()=="" || file.findn(search_box->get_text())!=-1)) { - TreeItem *root = search_options->get_root(); TreeItem *ti = search_options->create_item(root); ti->set_text(0,file); - Ref<Texture> icon = get_icon( (has_icon(efsd->get_file_type(i),"EditorIcons")?efsd->get_file_type(i):String("Object")),"EditorIcons"); + Ref<Texture> icon = get_icon( (has_icon(efsd->get_file_type(i),ei)?efsd->get_file_type(i):ot),ei); ti->set_icon(0,icon); if (root->get_children()==ti) ti->select(0); } } + + + if (add_directories) { + for(int i=0;i<efsd->get_subdir_count();i++) { + + _parse_fs(efsd->get_subdir(i)); + } + } + } void EditorQuickOpen::_update_search() { @@ -118,7 +145,7 @@ void EditorQuickOpen::_notification(int p_what) { } -String EditorQuickOpen::get_base_type() const { +StringName EditorQuickOpen::get_base_type() const { return base_type; } @@ -152,4 +179,7 @@ EditorQuickOpen::EditorQuickOpen() { set_hide_on_ok(false); search_options->connect("item_activated",this,"_confirmed"); search_options->set_hide_root(true); + ei="EditorIcons"; + ot="Object"; + add_directories=false; } diff --git a/tools/editor/quick_open.h b/tools/editor/quick_open.h index 63652a442a..8b38256d39 100644 --- a/tools/editor/quick_open.h +++ b/tools/editor/quick_open.h @@ -38,7 +38,11 @@ class EditorQuickOpen : public ConfirmationDialog { LineEdit *search_box; Tree *search_options; - String base_type; + StringName base_type; + StringName ei; + StringName ot; + bool add_directories; + void _update_search(); @@ -55,9 +59,9 @@ protected: static void _bind_methods(); public: - String get_base_type() const; + StringName get_base_type() const; - void popup(const String& p_base,bool p_dontclear=false); + void popup(const StringName& p_base,bool p_dontclear=false,bool p_add_dirs=false); EditorQuickOpen(); }; diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp index ae0b58a665..276f2dea33 100644 --- a/tools/editor/scene_tree_dock.cpp +++ b/tools/editor/scene_tree_dock.cpp @@ -35,7 +35,7 @@ #include "tools/editor/plugins/canvas_item_editor_plugin.h" #include "script_editor_debugger.h" #include "tools/editor/plugins/script_editor_plugin.h" - +#include "multi_node_edit.h" void SceneTreeDock::_unhandled_key_input(InputEvent p_event) { @@ -450,6 +450,19 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { reparent_dialog->set_current( nodeset ); } break; + case TOOL_MULTI_EDIT: { + + Node*root=EditorNode::get_singleton()->get_edited_scene(); + if (!root) + break; + Ref<MultiNodeEdit> mne = memnew( MultiNodeEdit ); + for (const Map<Node*,Object*>::Element *E=EditorNode::get_singleton()->get_editor_selection()->get_selection().front();E;E=E->next()) { + mne->add_node(root->get_path_to(E->key())); + } + + EditorNode::get_singleton()->push_item(mne.ptr()); + + } break; case TOOL_ERASE: { List<Node*> remove_list = editor_selection->get_selected_node_list(); @@ -507,6 +520,7 @@ void SceneTreeDock::_notification(int p_what) { "MoveDown", "Duplicate", "Reparent", + "MultiNodeEdit", "Remove", }; @@ -515,6 +529,8 @@ void SceneTreeDock::_notification(int p_what) { for(int i=0;i<TOOL_BUTTON_MAX;i++) tool_buttons[i]->set_icon(get_icon(button_names[i],"EditorIcons")); + EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed",this,"_selection_changed"); + } break; } } @@ -1075,9 +1091,19 @@ void SceneTreeDock::_update_tool_buttons() { tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root); tool_buttons[TOOL_REPARENT]->set_disabled(disable_root); tool_buttons[TOOL_ERASE]->set_disabled(disable); + tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2); + } + +void SceneTreeDock::_selection_changed() { + + tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2); + +} + + void SceneTreeDock::_create() { @@ -1262,6 +1288,7 @@ void SceneTreeDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_delete_confirm"),&SceneTreeDock::_delete_confirm); ObjectTypeDB::bind_method(_MD("_node_prerenamed"),&SceneTreeDock::_node_prerenamed); ObjectTypeDB::bind_method(_MD("_import_subscene"),&SceneTreeDock::_import_subscene); + ObjectTypeDB::bind_method(_MD("_selection_changed"),&SceneTreeDock::_selection_changed); ObjectTypeDB::bind_method(_MD("instance"),&SceneTreeDock::instance); } @@ -1365,6 +1392,12 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec hbc_bottom->add_spacer(); tb = memnew( ToolButton ); + tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_MULTI_EDIT, false)); + tb->set_tooltip("Multi-Edit Selected Nodes"); + hbc_bottom->add_child(tb); + tool_buttons[TOOL_MULTI_EDIT]=tb; + + tb = memnew( ToolButton ); tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_ERASE, false)); tb->set_tooltip("Erase Selected Node(s)"); hbc_bottom->add_child(tb); diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h index f0bbbad6be..b1c53d2ff9 100644 --- a/tools/editor/scene_tree_dock.h +++ b/tools/editor/scene_tree_dock.h @@ -62,6 +62,7 @@ class SceneTreeDock : public VBoxContainer { TOOL_MOVE_DOWN, TOOL_DUPLICATE, TOOL_REPARENT, + TOOL_MULTI_EDIT, TOOL_ERASE, TOOL_BUTTON_MAX }; @@ -119,6 +120,7 @@ class SceneTreeDock : public VBoxContainer { void _import_subscene(); bool _validate_no_foreign(); + void _selection_changed(); void _fill_path_renames(Vector<StringName> base_path,Vector<StringName> new_base_path,Node * p_node, List<Pair<NodePath,NodePath> > *p_renames); diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp index 9153616775..7d9c5b24b2 100644 --- a/tools/editor/scenes_dock.cpp +++ b/tools/editor/scenes_dock.cpp @@ -35,15 +35,30 @@ #include "os/os.h" #include "editor_node.h" +#include "editor_settings.h" + bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir) { - String search_term = tree_filter->get_search_term(); - ScenesDockFilter::FilterOption file_filter = tree_filter->get_file_filter(); TreeItem *item = tree->create_item(p_parent); - item->set_text(0,p_dir->get_name()+"/"); + String dname=p_dir->get_name(); + if (dname=="") + dname="res://"; + + item->set_text(0,dname); item->set_icon(0,get_icon("Folder","EditorIcons")); - item->set_custom_bg_color(0,get_color("prop_subsection","Editor")); + item->set_selectable(0,true); + String lpath = p_dir->get_path(); + if (lpath!="res://" && lpath.ends_with("/")) { + lpath=lpath.substr(0,lpath.length()-1); + } + item->set_metadata(0,lpath); + if (lpath==path) { + item->select(0); + } + + + //item->set_custom_bg_color(0,get_color("prop_subsection","Editor")); bool has_items=false; @@ -52,7 +67,7 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di if (_create_tree(item,p_dir->get_subdir(i))) has_items=true; } - +#if 0 for (int i=0;i<p_dir->get_file_count();i++) { String file_name = p_dir->get_file(i); @@ -89,13 +104,13 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di has_items=true; } - - if (!has_items) { +#endif + /*if (!has_items) { memdelete(item); return false; - } + }*/ return true; } @@ -105,7 +120,28 @@ void ScenesDock::_update_tree() { tree->clear(); updating_tree=true; - _create_tree(NULL,EditorFileSystem::get_singleton()->get_filesystem()); + TreeItem *root = tree->create_item(); + TreeItem *favorites = tree->create_item(root); + favorites->set_icon(0, get_icon("Favorites","EditorIcons") ); + favorites->set_text(0,"Favorites:"); + favorites->set_selectable(0,false); + Vector<String> faves = EditorSettings::get_singleton()->get_favorite_dirs(); + for(int i=0;i<faves.size();i++) { + if (!faves[i].begins_with("res://")) + continue; + + TreeItem *ti = tree->create_item(favorites); + String fv = faves[i]; + if (fv=="res://") + ti->set_text(0,"/"); + else + ti->set_text(0,faves[i].get_file()); + ti->set_icon(0,get_icon("Folder","EditorIcons")); + ti->set_selectable(0,true); + ti->set_metadata(0,faves[i]); + } + + _create_tree(root,EditorFileSystem::get_singleton()->get_filesystem()); updating_tree=false; } @@ -117,68 +153,192 @@ void ScenesDock::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { + if (initialized) + return; + initialized=false; - EditorFileSystem::get_singleton()->connect("filesystem_changed",this,"_update_tree"); + EditorFileSystem::get_singleton()->connect("filesystem_changed",this,"_fs_changed"); button_reload->set_icon( get_icon("Reload","EditorIcons")); button_favorite->set_icon( get_icon("Favorites","EditorIcons")); + button_fav_up->set_icon( get_icon("MoveUp","EditorIcons")); + button_fav_down->set_icon( get_icon("MoveDown","EditorIcons")); button_instance->set_icon( get_icon("Add","EditorIcons")); button_open->set_icon( get_icon("Folder","EditorIcons")); + button_back->set_icon( get_icon("Filesystem","EditorIcons")); + display_mode->set_icon( get_icon("FileList","EditorIcons")); + display_mode->connect("pressed",this,"_change_file_display"); + file_options->set_icon( get_icon("Tools","EditorIcons")); + files->connect("item_activated",this,"_select_file"); + button_hist_next->connect("pressed",this,"_fw_history"); + button_hist_prev->connect("pressed",this,"_bw_history"); - String path = Globals::get_singleton()->get_resource_path()+"/favorites.cfg"; - FileAccess *f=FileAccess::open(path,FileAccess::READ); - if (f) { + button_hist_next->set_icon( get_icon("Forward","EditorIcons")); + button_hist_prev->set_icon( get_icon("Back","EditorIcons")); + file_options->get_popup()->connect("item_pressed",this,"_file_option"); - String l = f->get_line(); - while(l!="") { - favorites.insert(l); - l = f->get_line(); - - } + button_back->connect("pressed",this,"_go_to_tree",varray(),CONNECT_DEFERRED); + current_path->connect("text_entered",this,"_go_to_dir"); + _update_tree(); //maybe it finished already - f->close(); - memdelete(f); + if (EditorFileSystem::get_singleton()->is_scanning()) { + _set_scannig_mode(); } - - - _update_tree(); //maybe it finished already + } break; + case NOTIFICATION_PROCESS: { + if (EditorFileSystem::get_singleton()->is_scanning()) { + scanning_progress->set_val(EditorFileSystem::get_singleton()->get_scanning_progress()*100); + } } break; case NOTIFICATION_EXIT_TREE: { } break; - case NOTIFICATION_PROCESS: { - } break; } } -void ScenesDock::_favorite_toggled() { - if (updating_tree) + + +void ScenesDock::_dir_selected() { + + TreeItem *ti = tree->get_selected(); + if (!ti) return; + String dir = ti->get_metadata(0); + bool found=false; + Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs(); + for(int i=0;i<favorites.size();i++) { + + if (favorites[i]==dir) { + found=true; + break; + } + } + + + button_favorite->set_pressed(found); + if (ti->get_parent() && ti->get_parent()->get_parent()==tree->get_root() && !ti->get_parent()->get_prev()) { + + //a favorite!!! + button_fav_up->set_disabled(!ti->get_prev()); + button_fav_down->set_disabled(!ti->get_next()); + } else { + button_fav_up->set_disabled(true); + button_fav_down->set_disabled(true); + + } +} + +void ScenesDock::_fav_up_pressed() { TreeItem *sel = tree->get_selected(); if (!sel) - return; //? + return ; - bool faved = sel->is_checked(0); - String path = sel->get_metadata(0); - if (faved) - favorites.insert(path); - else - favorites.erase(path); + if (!sel->get_prev()) + return; + + String sw = sel->get_prev()->get_metadata(0); + String txt = sel->get_metadata(0); + + Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs(); + + int a_idx=favorited.find(sw); + int b_idx=favorited.find(txt); + + if (a_idx==-1 || b_idx==-1) + return; + SWAP(favorited[a_idx],favorited[b_idx]); + + EditorSettings::get_singleton()->set_favorite_dirs(favorited); + + _update_tree(); - timer->start(); + if (!tree->get_root() || !tree->get_root()->get_children() || !tree->get_root()->get_children()->get_children()) + return; + sel = tree->get_root()->get_children()->get_children(); + while(sel) { + String t = sel->get_metadata(0); + if (t==txt) { + sel->select(0); + return; + } + sel=sel->get_next(); + } } -void ScenesDock::_favorites_toggled(bool p_toggled) { +void ScenesDock::_fav_down_pressed() { + + TreeItem *sel = tree->get_selected(); + if (!sel) + return ; + + if (!sel->get_next()) + return; + + String sw = sel->get_next()->get_metadata(0); + String txt = sel->get_metadata(0); + + Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs(); + + int a_idx=favorited.find(sw); + int b_idx=favorited.find(txt); + + if (a_idx==-1 || b_idx==-1) + return; + SWAP(favorited[a_idx],favorited[b_idx]); + + EditorSettings::get_singleton()->set_favorite_dirs(favorited); _update_tree(); + + if (!tree->get_root() || !tree->get_root()->get_children() || !tree->get_root()->get_children()->get_children()) + return; + sel = tree->get_root()->get_children()->get_children(); + while(sel) { + + String t = sel->get_metadata(0); + if (t==txt) { + sel->select(0); + return; + } + sel=sel->get_next(); + } +} + +void ScenesDock::_favorites_pressed() { + + TreeItem *sel = tree->get_selected(); + if (!sel) + return ; + String dir = sel->get_metadata(0); + + int idx = -1; + Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs(); + for(int i=0;i<favorites.size();i++) { + + if (favorites[i]==dir) { + idx=i; + break; + } + } + + if (button_favorite->is_pressed() && idx==-1) { + favorites.push_back(dir); + EditorSettings::get_singleton()->set_favorite_dirs(favorites); + _update_tree(); + } else if (!button_favorite->is_pressed() && idx!=-1) { + favorites.remove(idx); + EditorSettings::get_singleton()->set_favorite_dirs(favorites); + _update_tree(); + } + } String ScenesDock::get_selected_path() const { @@ -199,65 +359,712 @@ void ScenesDock::_instance_pressed() { emit_signal("instance",path); } -void ScenesDock::_open_pressed(){ +void ScenesDock::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) { - TreeItem *sel = tree->get_selected(); - if (!sel) { + if (p_preview.is_valid() && path==p_path.get_base_dir()) { + + int idx=p_udata; + if (idx>=files->get_item_count()) + return; + String fpath = files->get_item_metadata(idx); + if (fpath!=p_path) + return; + files->set_item_icon(idx,p_preview); + + } + +} + +void ScenesDock::_change_file_display() { + + if (display_mode->is_pressed()) { + display_mode->set_icon( get_icon("FileThumbnail","EditorIcons")); + + } else { + display_mode->set_icon( get_icon("FileList","EditorIcons")); + } + + _update_files(true); +} + +void ScenesDock::_update_files(bool p_keep_selection) { + + Set<String> cselection; + + if (p_keep_selection) { + + for(int i=0;i<files->get_item_count();i++) { + + if (files->is_selected(i)) + cselection.insert(files->get_item_text(i)); + } + } + + files->clear(); + + EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_path(path); + if (!efd) return; + + int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size"); + Ref<Texture> folder_thumbnail; + Ref<Texture> file_thumbnail; + + bool use_thumbnails=!display_mode->is_pressed(); + + if (use_thumbnails) { //thumbnails + + files->set_max_columns(0); + files->set_icon_mode(ItemList::ICON_MODE_TOP); + files->set_fixed_column_width(thumbnail_size*3/2); + files->set_max_text_lines(2); + files->set_min_icon_size(Size2(thumbnail_size,thumbnail_size)); + + if (!has_icon("ResizedFolder","EditorIcons")) { + Ref<ImageTexture> folder = get_icon("FolderBig","EditorIcons"); + Image img = folder->get_data(); + img.resize(thumbnail_size,thumbnail_size); + Ref<ImageTexture> resized_folder = Ref<ImageTexture>( memnew( ImageTexture)); + resized_folder->create_from_image(img,0); + Theme::get_default()->set_icon("ResizedFolder","EditorIcons",resized_folder); + } + + folder_thumbnail = get_icon("ResizedFolder","EditorIcons"); + + if (!has_icon("ResizedFile","EditorIcons")) { + Ref<ImageTexture> file = get_icon("FileBig","EditorIcons"); + Image img = file->get_data(); + img.resize(thumbnail_size,thumbnail_size); + Ref<ImageTexture> resized_file = Ref<ImageTexture>( memnew( ImageTexture)); + resized_file->create_from_image(img,0); + Theme::get_default()->set_icon("ResizedFile","EditorIcons",resized_file); + } + + file_thumbnail = get_icon("ResizedFile","EditorIcons"); + + } else { + + files->set_icon_mode(ItemList::ICON_MODE_LEFT); + files->set_max_columns(1); + files->set_max_text_lines(1); + files->set_fixed_column_width(0); + files->set_min_icon_size(Size2()); + } - String path = sel->get_metadata(0); - if (ResourceLoader::get_resource_type(path)=="PackedScene") { - editor->open_request(path); + if (path!="res://") { + + if (use_thumbnails) { + files->add_item("..",folder_thumbnail,true); + } else { + files->add_item("..",get_icon("folder","FileDialog"),true); + } + + String bd = path.get_base_dir(); + if (bd!="res://" && !bd.ends_with("/")) + bd+="/"; + + files->set_item_metadata(files->get_item_count()-1,bd); + } + + for(int i=0;i<efd->get_subdir_count();i++) { + + String dname=efd->get_subdir(i)->get_name(); + + + if (use_thumbnails) { + files->add_item(dname,folder_thumbnail,true); + } else { + files->add_item(dname,get_icon("folder","FileDialog"),true); + } + + files->set_item_metadata(files->get_item_count()-1,path.plus_file(dname)+"/"); + + if (cselection.has(dname)) + files->select(files->get_item_count()-1,false); + } + + for(int i=0;i<efd->get_file_count();i++) { + + String fname=efd->get_file(i); + String fp = path.plus_file(fname); + + + String type = efd->get_file_type(i); + Ref<Texture> type_icon; + + if (has_icon(type,"EditorIcons")) { + type_icon=get_icon(type,"EditorIcons"); + } else { + type_icon=get_icon("Object","EditorIcons"); + } + + if (use_thumbnails) { + files->add_item(fname,file_thumbnail,true); + files->set_item_metadata(files->get_item_count()-1,fp); + files->set_item_tag_icon(files->get_item_count()-1,type_icon); + EditorResourcePreview::get_singleton()->queue_resource_preview(fp,this,"_thumbnail_done",files->get_item_count()-1); + } else { + files->add_item(fname,type_icon,true); + files->set_item_metadata(files->get_item_count()-1,fp); + + } + + if (cselection.has(fname)) + files->select(files->get_item_count()-1,false); + + } + + +} + +void ScenesDock::_select_file(int p_idx) { + + files->select(p_idx,true); + _open_pressed(); +} + +void ScenesDock::_go_to_tree() { + + tree->show(); + files->hide(); + path_hb->hide(); + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); + button_favorite->show(); + button_fav_up->show(); + button_fav_down->show(); + button_open->hide(); + button_instance->hide(); + button_open->hide(); + file_options->hide(); + tree_mode=true; +} + +void ScenesDock::_go_to_dir(const String& p_dir){ + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (da->change_dir(p_dir)==OK) { + path=da->get_current_dir(); + _update_files(false); + } + current_path->set_text(path); + memdelete(da); + + +} +void ScenesDock::_fs_changed() { + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + scanning_vb->hide(); + + if (tree_mode) { + + tree->show(); + button_favorite->show(); + button_fav_up->show(); + button_fav_down->show(); + _update_tree(); + } else { + files->show(); + path_hb->show(); + button_instance->show(); + button_open->show(); + file_options->show(); + _update_files(true); + } + + set_process(false); +} + +void ScenesDock::_set_scannig_mode() { + + tree->hide(); + button_favorite->hide(); + button_fav_up->hide(); + button_fav_down->hide(); + button_instance->hide(); + button_open->hide(); + file_options->hide(); + button_hist_prev->set_disabled(true); + button_hist_next->set_disabled(true); + scanning_vb->show(); + path_hb->hide(); + files->hide(); + set_process(true); + if (EditorFileSystem::get_singleton()->is_scanning()) { + scanning_progress->set_val(EditorFileSystem::get_singleton()->get_scanning_progress()*100); + } else { + scanning_progress->set_val(0); + } + +} + +void ScenesDock::_fw_history() { + + if (history_pos<history.size()-1) + history_pos++; + + path=history[history_pos]; + + if (tree_mode) { + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); + } else { + _update_files(false); + current_path->set_text(path); + } + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + +} + +void ScenesDock::_bw_history() { + + if (history_pos>0) + history_pos--; + + path=history[history_pos]; + + if (tree_mode) { + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); } else { + _update_files(false); + current_path->set_text(path); + } + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + +} + +void ScenesDock::_push_to_history() { - /* + history.resize(history_pos+1); + if (history[history_pos]!=path) { + history.push_back(path); + history_pos++; + } + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + +} + + +void ScenesDock::_find_inside_move_files(EditorFileSystemDirectory *efsd,Vector<String>& files) { - RES res = ResourceLoader::load(path); - if (res.is_null()) { + for(int i=0;i<efsd->get_subdir_count();i++) { + _find_inside_move_files(efsd->get_subdir(i),files); + } + for(int i=0;i<efsd->get_file_count();i++) { + files.push_back(efsd->get_file_path(i)); + } + +} +void ScenesDock::_find_remaps(EditorFileSystemDirectory *efsd,Map<String,String> &renames,List<String>& to_remaps) { + for(int i=0;i<efsd->get_subdir_count();i++) { + _find_remaps(efsd->get_subdir(i),renames,to_remaps); + } + for(int i=0;i<efsd->get_file_count();i++) { + Vector<String> deps=efsd->get_file_deps(i); + for(int j=0;j<deps.size();j++) { + if (renames.has(deps[j])) { + to_remaps.push_back(efsd->get_file_path(i)); + break; + } + } + } +} + + +void ScenesDock::_rename_operation(const String& p_to_path) { + + if (move_files[0]==p_to_path) { + EditorNode::get_singleton()->show_warning("Same source and destination files, doing nothing."); + return; + } + if (FileAccess::exists(p_to_path)) { + EditorNode::get_singleton()->show_warning("Target file exists, can't overwrite. Delete first."); + return; + } + + Map<String,String> renames; + renames[move_files[0]]=p_to_path; + + List<String> remap; + + _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(),renames,remap); + print_line("found files to remap: "+itos(remap.size())); + + //perform remaps + for(List<String>::Element *E=remap.front();E;E=E->next()) { + + Error err = ResourceLoader::rename_dependencies(E->get(),renames); + print_line("remapping: "+E->get()); + + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Can't rename deps for:\n"+E->get()+"\n"); + } + } + + //finally, perform moves + + DirAccess *da=DirAccess::create(DirAccess::ACCESS_RESOURCES); + + Error err = da->rename(move_files[0],p_to_path); + print_line("moving file "+move_files[0]+" to "+p_to_path); + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Error moving file:\n"+move_files[0]+"\n"); + } + + //rescan everything + memdelete(da); + print_line("call rescan!"); + _rescan(); +} + + +void ScenesDock::_move_operation(const String& p_to_path) { + + if (p_to_path==path) { + EditorNode::get_singleton()->show_warning("Same source and destination paths, doing nothing."); + return; + } + + //find files inside dirs to be moved + + Vector<String> inside_files; + + for(int i=0;i<move_dirs.size();i++) { + if (p_to_path.begins_with(move_dirs[i])) { + EditorNode::get_singleton()->show_warning("Can't move directories to within themselves"); return; - }*/ + } - editor->load_resource(path); + EditorFileSystemDirectory *efsd=EditorFileSystem::get_singleton()->get_path(move_dirs[i]); + if (!efsd) + continue; + _find_inside_move_files(efsd,inside_files); } -// emit_signal("open",path); + //make list of remaps + Map<String,String> renames; + String repfrom=path=="res://"?path:String(path+"/"); + String repto=p_to_path=="res://"?p_to_path:String(p_to_path+"/"); + + for(int i=0;i<move_files.size();i++) { + renames[move_files[i]]=move_files[i].replace_first(repfrom,repto); + print_line("move file "+move_files[i]+" -> "+renames[move_files[i]]); + } + for(int i=0;i<inside_files.size();i++) { + renames[inside_files[i]]=inside_files[i].replace_first(repfrom,repto); + print_line("inside file "+inside_files[i]+" -> "+renames[inside_files[i]]); + } + + //make list of files that will be run the remapping + List<String> remap; + _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(),renames,remap); + print_line("found files to remap: "+itos(remap.size())); + + //perform remaps + for(List<String>::Element *E=remap.front();E;E=E->next()) { + + Error err = ResourceLoader::rename_dependencies(E->get(),renames); + print_line("remapping: "+E->get()); + + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Can't rename deps for:\n"+E->get()+"\n"); + } + } + + //finally, perform moves + + DirAccess *da=DirAccess::create(DirAccess::ACCESS_RESOURCES); + + for(int i=0;i<move_files.size();i++) { + + String to = move_files[i].replace_first(repfrom,repto); + Error err = da->rename(move_files[i],to); + print_line("moving file "+move_files[i]+" to "+to); + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Error moving file:\n"+move_files[i]+"\n"); + } + } + + for(int i=0;i<move_dirs.size();i++) { + + String to = p_to_path.plus_file(move_dirs[i].get_file()); + Error err = da->rename(move_dirs[i],to); + print_line("moving dir "+move_dirs[i]+" to "+to); + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Error moving dir:\n"+move_dirs[i]+"\n"); + } + } + + memdelete(da); + //rescan everything + print_line("call rescan!"); + _rescan(); + +} + +void ScenesDock::_file_option(int p_option) { + + switch(p_option) { + + case FILE_DEPENDENCIES: { + + int idx = files->get_current(); + if (idx<0 || idx>=files->get_item_count()) + break; + String path = files->get_item_metadata(idx); + deps_editor->edit(path); + } break; + case FILE_OWNERS: { + + int idx = files->get_current(); + if (idx<0 || idx>=files->get_item_count()) + break; + String path = files->get_item_metadata(idx); + owners_editor->show(path); + } break; + case FILE_MOVE: { + + move_dirs.clear();; + move_files.clear(); + + for(int i=0;i<files->get_item_count();i++) { + + String path = files->get_item_metadata(i); + if (!files->is_selected(i)) + continue; + + if (files->get_item_text(i)=="..") { + EditorNode::get_singleton()->show_warning("Can't operate on '..'"); + return; + } + + if (path.ends_with("/")) { + move_dirs.push_back(path.substr(0,path.length()-1)); + } else { + move_files.push_back(path); + } + } + + + if (move_dirs.empty() && move_files.size()==1) { + + rename_dialog->clear_filters(); + rename_dialog->add_filter("*."+move_files[0].extension()); + rename_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + rename_dialog->set_current_path(move_files[0]); + rename_dialog->popup_centered_ratio(); + rename_dialog->set_title("Pick New Name and Location For: "+move_files[0].get_file()); + + + } else { + //just move + move_dialog->popup_centered_ratio(); + } + + + } break; + case FILE_REMOVE: { + + Vector<String> torem; + + for(int i=0;i<files->get_item_count();i++) { + + String path = files->get_item_metadata(i); + if (path.ends_with("/") || !files->is_selected(i)) + continue; + torem.push_back(path); + } + + if (torem.empty()) { + EditorNode::get_singleton()->show_warning("No files selected!"); + break; + } + + remove_dialog->show(torem); + //1) find if used + //2) warn + + } break; + case FILE_INFO: { + + } break; + + } } -void ScenesDock::_save_favorites() { +void ScenesDock::_open_pressed(){ + + + if (tree_mode) { + + TreeItem *sel = tree->get_selected(); + if (!sel) { + return; + } + path = sel->get_metadata(0); + /*if (path!="res://" && path.ends_with("/")) { + path=path.substr(0,path.length()-1); + }*/ + + tree_mode=false; + + tree->hide(); + files->show(); + path_hb->show(); + button_favorite->hide(); + button_fav_up->hide(); + button_fav_down->hide(); + button_instance->show(); + button_open->show(); + file_options->show(); + + _update_files(false); - String path = Globals::get_singleton()->get_resource_path()+"/favorites.cfg"; - FileAccess *f=FileAccess::open(path,FileAccess::WRITE); - ERR_FAIL_COND(!f); - for(Set<String>::Element *E=favorites.front();E;E=E->next() ) { + current_path->set_text(path); - CharString utf8f = E->get().utf8(); - f->store_buffer((const uint8_t*)utf8f.get_data(),utf8f.length()); - f->store_8('\n'); + _push_to_history(); + + + } else { + + int idx=-1; + for(int i=0;i<files->get_item_count();i++) { + if (files->is_selected(i)) { + idx=i; + break; + } + } + + if (idx<0) + return; + + + + String path = files->get_item_metadata(idx); + + if (path.ends_with("/")) { + if (path!="res://") { + path=path.substr(0,path.length()-1); + } + this->path=path; + _update_files(false); + current_path->set_text(path); + _push_to_history(); + } else { + + if (ResourceLoader::get_resource_type(path)=="PackedScene") { + + editor->open_request(path); + } else { + + editor->load_resource(path); + } + } } - f->close(); - memdelete(f); +// emit_signal("open",path); + } + void ScenesDock::_rescan() { + _set_scannig_mode(); EditorFileSystem::get_singleton()->scan(); + +} + +void ScenesDock::fix_dependencies(const String& p_for_file) { + deps_editor->edit(p_for_file); +} + +void ScenesDock::open(const String& p_path) { + + + String npath; + String nfile; + + if (p_path.ends_with("/")) { + + if (p_path!="res://") + npath=p_path.substr(0,p_path.length()-1); + else + npath="res://"; + } else { + nfile=p_path.get_file(); + npath=p_path.get_base_dir(); + } + + path=npath; + + if (tree_mode && nfile=="") { + _update_tree(); + tree->grab_focus(); + tree->call_deferred("ensure_cursor_is_visible"); + _push_to_history(); + return; + } else if (tree_mode){ + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); + _open_pressed(); + current_path->set_text(path); + } else { + _update_files(false); + _push_to_history(); + } + + for(int i=0;i<files->get_item_count();i++) { + + String md = files->get_item_metadata(i); + if (md==p_path) { + files->select(i,true); + files->ensure_current_is_visible(); + break; + } + } + } void ScenesDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_update_tree"),&ScenesDock::_update_tree); ObjectTypeDB::bind_method(_MD("_rescan"),&ScenesDock::_rescan); - ObjectTypeDB::bind_method(_MD("_favorites_toggled"),&ScenesDock::_favorites_toggled); - ObjectTypeDB::bind_method(_MD("_favorite_toggled"),&ScenesDock::_favorite_toggled); + ObjectTypeDB::bind_method(_MD("_favorites_pressed"),&ScenesDock::_favorites_pressed); ObjectTypeDB::bind_method(_MD("_instance_pressed"),&ScenesDock::_instance_pressed); ObjectTypeDB::bind_method(_MD("_open_pressed"),&ScenesDock::_open_pressed); - ObjectTypeDB::bind_method(_MD("_save_favorites"),&ScenesDock::_save_favorites); + + ObjectTypeDB::bind_method(_MD("_thumbnail_done"),&ScenesDock::_thumbnail_done); + ObjectTypeDB::bind_method(_MD("_select_file"), &ScenesDock::_select_file); + ObjectTypeDB::bind_method(_MD("_go_to_tree"), &ScenesDock::_go_to_tree); + ObjectTypeDB::bind_method(_MD("_go_to_dir"), &ScenesDock::_go_to_dir); + ObjectTypeDB::bind_method(_MD("_change_file_display"), &ScenesDock::_change_file_display); + ObjectTypeDB::bind_method(_MD("_fw_history"), &ScenesDock::_fw_history); + ObjectTypeDB::bind_method(_MD("_bw_history"), &ScenesDock::_bw_history); + ObjectTypeDB::bind_method(_MD("_fs_changed"), &ScenesDock::_fs_changed); + ObjectTypeDB::bind_method(_MD("_dir_selected"), &ScenesDock::_dir_selected); + ObjectTypeDB::bind_method(_MD("_fav_up_pressed"), &ScenesDock::_fav_up_pressed); + ObjectTypeDB::bind_method(_MD("_fav_down_pressed"), &ScenesDock::_fav_down_pressed); + ObjectTypeDB::bind_method(_MD("_file_option"), &ScenesDock::_file_option); + ObjectTypeDB::bind_method(_MD("_move_operation"), &ScenesDock::_move_operation); + ObjectTypeDB::bind_method(_MD("_rename_operation"), &ScenesDock::_rename_operation); ADD_SIGNAL(MethodInfo("instance")); ADD_SIGNAL(MethodInfo("open")); @@ -271,153 +1078,156 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { HBoxContainer *toolbar_hbc = memnew( HBoxContainer ); add_child(toolbar_hbc); + button_hist_prev = memnew( ToolButton ); + toolbar_hbc->add_child(button_hist_prev); + button_hist_prev->set_disabled(true); + button_hist_prev->set_tooltip("Previous Directory"); + + button_hist_next = memnew( ToolButton ); + toolbar_hbc->add_child(button_hist_next); + button_hist_next->set_disabled(true); + button_hist_prev->set_focus_mode(FOCUS_NONE); + button_hist_next->set_focus_mode(FOCUS_NONE); + button_hist_next->set_tooltip("Next Directory"); + button_reload = memnew( Button ); button_reload->set_flat(true); button_reload->connect("pressed",this,"_rescan"); toolbar_hbc->add_child(button_reload); + button_reload->set_focus_mode(FOCUS_NONE); + button_reload->set_tooltip("Re-Scan Filesystem"); + + toolbar_hbc->add_spacer(); + + button_fav_up = memnew( ToolButton ); + button_fav_up->set_flat(true); + toolbar_hbc->add_child(button_fav_up); + button_fav_up->set_disabled(true); + button_fav_up->connect("pressed",this,"_fav_up_pressed"); + button_fav_up->set_tooltip("Move Favorite Up"); + + button_fav_down = memnew( ToolButton ); + button_fav_down->set_flat(true); + toolbar_hbc->add_child(button_fav_down); + button_fav_down->set_disabled(true); + button_fav_down->connect("pressed",this,"_fav_down_pressed"); + button_fav_down->set_tooltip("Move Favorite Down"); button_favorite = memnew( Button ); button_favorite->set_flat(true); button_favorite->set_toggle_mode(true); - button_favorite->connect("toggled",this,"_favorites_toggled"); + button_favorite->connect("pressed",this,"_favorites_pressed"); toolbar_hbc->add_child(button_favorite); + button_favorite->set_tooltip("Toggle folder status as Favorite"); + + button_favorite->set_focus_mode(FOCUS_NONE); + button_fav_up->set_focus_mode(FOCUS_NONE); + button_fav_down->set_focus_mode(FOCUS_NONE); - toolbar_hbc->add_spacer(); button_open = memnew( Button ); button_open->set_flat(true); button_open->connect("pressed",this,"_open_pressed"); toolbar_hbc->add_child(button_open); + button_open->hide(); + button_open->set_focus_mode(FOCUS_NONE); + button_open->set_tooltip("Open the selected file.\nOpen as scene if a scene, or as resource otherwise."); + button_instance = memnew( Button ); button_instance->set_flat(true); button_instance->connect("pressed",this,"_instance_pressed"); toolbar_hbc->add_child(button_instance); + button_instance->hide(); + button_instance->set_focus_mode(FOCUS_NONE); + button_instance->set_tooltip("Instance the selected scene(s) as child of the selected node."); + + + file_options = memnew( MenuButton ); + toolbar_hbc->add_child(file_options); + file_options->get_popup()->add_item("Rename or Move",FILE_MOVE); + file_options->get_popup()->add_item("Delete",FILE_REMOVE); + file_options->get_popup()->add_separator(); + file_options->get_popup()->add_item("Edit Dependencies",FILE_DEPENDENCIES); + file_options->get_popup()->add_item("View Owners",FILE_OWNERS); + //file_options->get_popup()->add_item("Info",FILE_INFO); + file_options->hide(); + file_options->set_focus_mode(FOCUS_NONE); + file_options->set_tooltip("Miscenaneous options related to resources on disk."); tree = memnew( Tree ); - tree_filter=memnew( ScenesDockFilter() ); - tree_filter->connect("filter_changed", this, "_update_tree"); - add_child(tree_filter); + + tree->set_hide_root(true); add_child(tree); + tree->set_v_size_flags(SIZE_EXPAND_FILL); tree->connect("item_edited",this,"_favorite_toggled"); tree->connect("item_activated",this,"_open_pressed"); - - timer = memnew( Timer ); - timer->set_one_shot(true); - timer->set_wait_time(2); - timer->connect("timeout",this,"_save_favorites"); - add_child(timer); - + tree->connect("cell_selected",this,"_dir_selected"); + + files = memnew( ItemList ); + files->set_v_size_flags(SIZE_EXPAND_FILL); + files->set_select_mode(ItemList::SELECT_MULTI); + + path_hb = memnew( HBoxContainer ); + button_back = memnew( ToolButton ); + path_hb->add_child(button_back); + current_path=memnew( LineEdit ); + current_path->set_h_size_flags(SIZE_EXPAND_FILL); + path_hb->add_child(current_path); + display_mode = memnew( ToolButton ); + path_hb->add_child(display_mode); + display_mode->set_toggle_mode(true); + add_child(path_hb); + path_hb->hide(); + + + add_child(files); + files->hide(); + + scanning_vb = memnew( VBoxContainer ); + Label *slabel = memnew( Label ); + slabel->set_text("Scanning Files,\nPlease Wait.."); + slabel->set_align(Label::ALIGN_CENTER); + scanning_vb->add_child(slabel); + scanning_progress = memnew( ProgressBar ); + scanning_vb->add_child(scanning_progress); + add_child(scanning_vb); + scanning_vb->hide(); + + + + deps_editor = memnew( DependencyEditor ); + add_child(deps_editor); + + owners_editor = memnew( DependencyEditorOwners); + add_child(owners_editor); + + remove_dialog = memnew( DependencyRemoveDialog); + add_child(remove_dialog); + + move_dialog = memnew( EditorDirDialog ); + add_child(move_dialog); + move_dialog->connect("dir_selected",this,"_move_operation"); + move_dialog->get_ok()->set_text("Move"); + + rename_dialog = memnew( EditorFileDialog ); + rename_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + rename_dialog->connect("file_selected",this,"_rename_operation"); + add_child(rename_dialog); updating_tree=false; + initialized=false; -} - -ScenesDock::~ScenesDock() { - -} - -void ScenesDockFilter::_setup_filters() { - - filter_option->clear(); - filter_option->add_item("Path"); - filter_option->add_item("Name"); - filter_option->add_item("Folder"); -#if 0 - List<String> extensions; - ResourceLoader::get_recognized_extensions_for_type("",&extensions); - - file_filter->add_item("All Files (*)"); - filters.push_back("*"); - - List<String> filter_texts; - for(int i=0;i<extensions.size();i++) { - filter_texts.push_back("*."+extensions[i]+" ; "+extensions[i].to_upper()); - filters.push_back(extensions[i]); - } - for(int i=0;i<filter_texts.size();i++) { - - String flt=filter_texts[i].get_slice(";",0).strip_edges(); - String desc=filter_texts[i].get_slice(";",1).strip_edges(); - if (desc.length()) - file_filter->add_item(desc+" ( "+flt+" )"); - else - file_filter->add_item("( "+flt+" )"); - } -#endif -} - -void ScenesDockFilter::_command(int p_command) { - switch (p_command) { - - case CMD_CLEAR_FILTER: { - if (search_box->get_text()!="") { - search_box->clear(); - emit_signal("filter_changed"); - } - }break; - } -} - -void ScenesDockFilter::_search_text_changed(const String &p_newtext) { - emit_signal("filter_changed"); -} - -String ScenesDockFilter::get_search_term() { - return search_box->get_text().strip_edges(); -} - -ScenesDockFilter::FilterOption ScenesDockFilter::get_file_filter() { - return _current_filter; -} - -void ScenesDockFilter::_file_filter_selected(int p_idx) { - FilterOption selected = (FilterOption)(filter_option->get_selected()); - if (_current_filter != selected ) { - _current_filter = selected; - emit_signal("filter_changed"); - } -} - -void ScenesDockFilter::_notification(int p_what) { - switch(p_what) { - case NOTIFICATION_ENTER_TREE: { - clear_search_button->set_icon(get_icon("CloseHover","EditorIcons")); - } break; - } -} - -void ScenesDockFilter::_bind_methods() { + history.push_back("res://"); + history_pos=0; + tree_mode=true; - ObjectTypeDB::bind_method(_MD("_command"),&ScenesDockFilter::_command); - ObjectTypeDB::bind_method(_MD("_search_text_changed"), &ScenesDockFilter::_search_text_changed); - ObjectTypeDB::bind_method(_MD("_file_filter_selected"), &ScenesDockFilter::_file_filter_selected); - ADD_SIGNAL( MethodInfo("filter_changed") ); } -ScenesDockFilter::ScenesDockFilter() { - - _current_filter = FILTER_PATH; - - filter_option = memnew( OptionButton ); - filter_option->set_custom_minimum_size(Size2(60,10)); - filter_option->set_clip_text(true); - filter_option->connect("item_selected", this, "_file_filter_selected"); - add_child(filter_option); - - _setup_filters(); - - search_box = memnew( LineEdit ); - search_box->connect("text_changed",this,"_search_text_changed"); - search_box->set_h_size_flags(SIZE_EXPAND_FILL); - add_child(search_box); - - clear_search_button = memnew( ToolButton ); - clear_search_button->connect("pressed",this,"_command",make_binds(CMD_CLEAR_FILTER)); - add_child(clear_search_button); +ScenesDock::~ScenesDock() { } diff --git a/tools/editor/scenes_dock.h b/tools/editor/scenes_dock.h index de7ab51edc..d045124bf7 100644 --- a/tools/editor/scenes_dock.h +++ b/tools/editor/scenes_dock.h @@ -36,40 +36,112 @@ #include "scene/gui/tool_button.h" #include "scene/gui/option_button.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/item_list.h" +#include "scene/gui/progress_bar.h" + #include "os/dir_access.h" #include "os/thread.h" #include "editor_file_system.h" - +#include "editor_dir_dialog.h" +#include "dependency_editor.h" class EditorNode; -class ScenesDockFilter; + class ScenesDock : public VBoxContainer { OBJ_TYPE( ScenesDock, VBoxContainer ); + enum FileMenu { + FILE_DEPENDENCIES, + FILE_OWNERS, + FILE_MOVE, + FILE_REMOVE, + FILE_REIMPORT, + FILE_INFO + }; + + + VBoxContainer *scanning_vb; + ProgressBar *scanning_progress; + EditorNode *editor; Set<String> favorites; Button *button_reload; Button *button_instance; Button *button_favorite; + Button *button_fav_up; + Button *button_fav_down; Button *button_open; - Timer *timer; + Button *button_back; + Button *display_mode; + Button *button_hist_next; + Button *button_hist_prev; + LineEdit *current_path; + HBoxContainer *path_hb; + + MenuButton *file_options; + + + DependencyEditor *deps_editor; + DependencyEditorOwners *owners_editor; + DependencyRemoveDialog *remove_dialog; + + EditorDirDialog *move_dialog; + EditorFileDialog *rename_dialog; - ScenesDockFilter *tree_filter; + Vector<String> move_dirs; + Vector<String> move_files; + + + Vector<String> history; + int history_pos; + + String path; + + bool initialized; bool updating_tree; - Tree * tree; + Tree * tree; //directories + ItemList *files; + + bool tree_mode; + + void _go_to_tree(); + void _go_to_dir(const String& p_dir); + void _select_file(int p_idx); + bool _create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir); + void _thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata); + void _find_inside_move_files(EditorFileSystemDirectory *efsd,Vector<String>& files); + void _find_remaps(EditorFileSystemDirectory *efsd,Map<String,String> &renames,List<String>& to_remaps); + + void _rename_operation(const String& p_to_path); + void _move_operation(const String& p_to_path); + + + void _file_option(int p_option); + void _update_files(bool p_keep_selection); + void _change_file_display(); + void _fs_changed(); + void _fw_history(); + void _bw_history(); + void _push_to_history(); + + void _fav_up_pressed(); + void _fav_down_pressed(); + void _dir_selected(); void _update_tree(); void _rescan(); - void _favorites_toggled(bool); - void _favorite_toggled(); + void _set_scannig_mode(); + + void _favorites_pressed(); void _instance_pressed(); void _open_pressed(); - void _save_favorites(); + protected: void _notification(int p_what); @@ -77,48 +149,14 @@ protected: public: String get_selected_path() const; + void open(const String& p_path); + + void fix_dependencies(const String& p_for_file); + ScenesDock(EditorNode *p_editor); ~ScenesDock(); }; -class ScenesDockFilter : public HBoxContainer { - - OBJ_TYPE( ScenesDockFilter, HBoxContainer ); - -private: - friend class ScenesDock; - - enum Command { - CMD_CLEAR_FILTER, - }; - - Tree *tree; - OptionButton *filter_option; - LineEdit *search_box; - ToolButton *clear_search_button; - - enum FilterOption { - FILTER_PATH, // NAME or Folder - FILTER_NAME, - FILTER_FOLDER, - }; - FilterOption _current_filter; - //Vector<String> filters; - - void _command(int p_command); - void _search_text_changed(const String& p_newtext); - void _setup_filters(); - void _file_filter_selected(int p_idx); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - String get_search_term(); - FilterOption get_file_filter(); - ScenesDockFilter(); -}; #endif // SCENES_DOCK_H diff --git a/tools/editor/spatial_editor_gizmos.h b/tools/editor/spatial_editor_gizmos.h index 8d6730e2f1..02f60db7f8 100644 --- a/tools/editor/spatial_editor_gizmos.h +++ b/tools/editor/spatial_editor_gizmos.h @@ -201,6 +201,8 @@ public: };
+
+
class SpatialPlayerSpatialGizmo : public SpatialGizmoTool {
OBJ_TYPE(SpatialPlayerSpatialGizmo,SpatialGizmoTool);
@@ -214,6 +216,8 @@ public: };
+
+
class TestCubeSpatialGizmo : public SpatialGizmoTool {
OBJ_TYPE(TestCubeSpatialGizmo,SpatialGizmoTool);
diff --git a/tools/html_fs/godot.html b/tools/html_fs/godot.html new file mode 100644 index 0000000000..36761deb90 --- /dev/null +++ b/tools/html_fs/godot.html @@ -0,0 +1,1317 @@ +<!doctype html> +<html lang="en-us"> + <head> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>Emscripten-Generated Code</title> + <style> + body { + font-family: arial; + margin: 0; + padding: none; + } + + .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; } + div.emscripten { text-align: center; } + div.emscripten_border { border: 1px solid black; } + /* the canvas *must not* have any border or padding, or mouse coords will be wrong */ + canvas.emscripten { border: 0px none; } + + #emscripten_logo { + display: inline-block; + margin: 0; + } + + .spinner { + height: 30px; + width: 30px; + margin: 0; + margin-top: 20px; + margin-left: 20px; + display: inline-block; + vertical-align: top; + + -webkit-animation: rotation .8s linear infinite; + -moz-animation: rotation .8s linear infinite; + -o-animation: rotation .8s linear infinite; + animation: rotation 0.8s linear infinite; + + border-left: 5px solid rgb(235, 235, 235); + border-right: 5px solid rgb(235, 235, 235); + border-bottom: 5px solid rgb(235, 235, 235); + border-top: 5px solid rgb(120, 120, 120); + + border-radius: 100%; + background-color: rgb(189, 215, 46); + } + + @-webkit-keyframes rotation { + from {-webkit-transform: rotate(0deg);} + to {-webkit-transform: rotate(360deg);} + } + @-moz-keyframes rotation { + from {-moz-transform: rotate(0deg);} + to {-moz-transform: rotate(360deg);} + } + @-o-keyframes rotation { + from {-o-transform: rotate(0deg);} + to {-o-transform: rotate(360deg);} + } + @keyframes rotation { + from {transform: rotate(0deg);} + to {transform: rotate(360deg);} + } + + #status { + display: inline-block; + vertical-align: top; + margin-top: 30px; + margin-left: 20px; + font-weight: bold; + color: rgb(120, 120, 120); + } + + #progress { + height: 20px; + width: 30px; + } + + #controls { + display: inline-block; + float: right; + vertical-align: top; + margin-top: 30px; + margin-right: 20px; + } + + #output { + width: 100%; + height: 200px; + margin: 0 auto; + margin-top: 10px; + display: block; + background-color: black; + color: white; + font-family: 'Lucida Console', Monaco, monospace; + outline: none; + } + </style> + </head> + <body> + <a href="http://emscripten.org"> + <?xml version="1.0" encoding="UTF-8" standalone="no"?><svg + version="1.1" + id="Layer_1" + x="0px" + y="0px" + width="296px" + height="78px" + viewBox="420 120 100 170" + enable-background="new 0 0 900 400" + xml:space="preserve" + inkscape:version="0.48.4 r9939" + sodipodi:docname="emscripten_powered_by_logo.svg"><metadata + id="metadata345"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs + id="defs343"><linearGradient + y2="247.6265" + x2="225.1929" + y1="152.499" + x1="225.1929" + gradientUnits="userSpaceOnUse" + id="linearGradient5104"><stop + id="stop5106" + style="stop-color:#C1D72F" + offset="0.3227531" /><stop + id="stop5108" + style="stop-color:#BCD631" + offset="0.45119295" /><stop + id="stop5110" + style="stop-color:#AFD136" + offset="0.64491969" /><stop + id="stop5112" + style="stop-color:#ABD037" + offset="1" /><a:midPointStop + style="stop-color:#C1D72F" + offset="0.0123" /><a:midPointStop + style="stop-color:#C1D72F" + offset="0.3086" /><a:midPointStop + style="stop-color:#ABD037" + offset="1" /></linearGradient><linearGradient + inkscape:collect="always" + xlink:href="#SVGID_2_" + id="linearGradient5120" + x1="397.56918" + y1="128.12726" + x2="397.56918" + y2="166.25996" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.103059,0,0,1.103059,-38.997823,3.1312145)" /><filter + inkscape:collect="always" + id="filter5126"><feGaussianBlur + inkscape:collect="always" + stdDeviation="0.56377237" + id="feGaussianBlur5128" /></filter><linearGradient + inkscape:collect="always" + xlink:href="#SVGID_2_" + id="linearGradient5134" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.103059,0,0,1.103059,-38.997823,3.1312145)" + x1="397.56918" + y1="128.12726" + x2="397.56918" + y2="166.25996" /></defs><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1440" + inkscape:window-height="838" + id="namedview341" + showgrid="false" + inkscape:zoom="0.63555556" + inkscape:cx="224.82424" + inkscape:cy="-52.085109" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="Layer_1" /><g + id="g5130" + transform="matrix(0.91591318,0,0,0.91591318,28.176953,14.143571)"><path + transform="matrix(1.103059,0,0,1.103059,-35.073492,-16.03923)" + id="path5122" + style="fill:#383838;fill-opacity:0.34705882;stroke:none;filter:url(#filter5126)" + d="m 494.39333,173.6323 c 0.57407,0.28703 1.87073,1.00226 2.89426,1.02855 0.55732,0.0143 1.14006,-0.1672 1.60262,-0.4784 1.20466,-0.81046 2.23561,-2.03031 2.72683,-3.39661 0.19424,-0.54027 0.0238,-1.72222 0.0238,-1.72222 l -3.82713,-14.06478 -1.98533,0 0.50231,-2.67891 6.36261,0 2.55939,12.22285 4.78392,-9.68746 -2.00924,0 0,-2.65498 7.19979,0 -11.00301,22.38875 -1.69829,1.91358 -2.29628,1.3395 -2.46371,0.26312 -2.29628,-0.21528 -2.79859,-1.36342 z m -12.0637,-14.56445 c -0.93698,1.88565 -1.70261,4.35262 -0.81842,6.26333 0.36549,0.78976 1.35098,1.19428 2.192,1.41737 0.60934,0.16133 1.29167,0.0999 1.88775,-0.10468 0.48126,-0.1655 0.8829,-0.5224 1.255,-0.8697 0.40341,-0.3768 0.77723,-0.80461 1.03505,-1.29262 0.21864,-0.41395 0.40236,-0.84786 0.49325,-1.30698 0.20667,-1.0485 0.35879,-2.1079 0.33583,-3.17631 -0.0184,-0.87403 -0.0789,-1.87107 -0.47711,-2.64959 -0.26344,-0.51379 -0.77017,-0.71849 -1.33113,-0.85633 -0.42395,-0.10479 -0.81432,-0.0626 -1.21773,0.10517 -0.65479,0.27273 -1.2544,0.5311 -1.82112,0.95764 -0.57331,0.4317 -1.21403,0.86959 -1.53337,1.5127 z m 0.65588,-4.31208 c 0,0 2.19341,-1.80738 3.45549,-2.27082 0.71718,-0.26365 3.45363,-0.65258 4.15,-0.3378 1.47292,0.66633 2.26103,1.57529 2.7222,2.60001 0.46118,1.02472 0.69944,2.59956 0.79701,3.73627 0.13278,1.55027 -0.13682,3.77629 -0.53404,5.74843 -0.30079,1.49256 -1.01883,2.74423 -1.83478,3.92156 -1.06526,1.5373 -1.82382,2.15116 -3.66756,2.46594 -0.98864,0.16889 -1.93845,0.46787 -3.25466,0.0928 -1.4384,-0.40963 -2.35273,-0.81244 -3.39599,-1.63337 -0.72524,-0.57054 -1.16043,-1.54043 -1.16043,-1.54043 l 0,2.82636 -4.8903,0 3.39872,-23.01602 -1.92242,-0.85888 0.0403,-2.38127 7.25847,0.0534 z m -23.77803,2.20447 c 0.29175,1.49273 0.0813,4.83252 -0.86111,6.69751 -0.3062,0.60617 -0.94813,1.32967 -1.55479,1.6983 -1.01515,0.61713 -2.21688,1.21322 -3.3966,1.07639 -0.47944,-0.0541 -0.97036,-0.34348 -1.24383,-0.74151 -0.47686,-0.69328 -0.43621,-1.55032 -0.45448,-2.39198 -0.024,-1.06873 0.13137,-2.23775 0.38272,-3.277 0.18705,-0.7744 0.4229,-1.58254 0.86111,-2.24844 0.39037,-0.59323 0.92628,-1.12617 1.55478,-1.45909 0.54854,-0.29014 1.19695,-0.38467 1.81791,-0.40664 0.63637,-0.0231 1.3031,0.0385 1.88966,0.28704 0.3875,0.16453 0.92361,0.3524 1.00463,0.76542 z m 1.29312,-9.69052 -0.64254,6.12262 c 0,0 -1.68393,-0.96858 -2.605,-1.25148 -0.73032,-0.22434 -1.50312,-0.36654 -2.26624,-0.33838 -0.97069,0.0345 -1.91182,0.22099 -2.81751,0.57088 -0.9185,0.35497 -1.78344,0.94565 -2.49338,1.62792 -0.88025,0.84538 -1.51404,1.90455 -2.02977,3.0106 -0.39653,0.84993 -0.69517,1.75284 -0.87975,2.67232 -0.22875,1.14241 -0.44415,2.38719 -0.43937,3.55197 0.01,1.44865 0.0623,2.89489 0.54092,4.26214 0.25525,0.72907 0.71643,1.40578 1.28572,1.9283 0.56835,0.52207 1.29566,0.87604 2.02935,1.11621 0.41072,0.13491 0.85346,0.17274 1.28579,0.16935 1.00285,-0.01 2.03715,-0.0883 2.97671,-0.43999 0.66497,-0.2489 1.21759,-0.73399 1.79298,-1.1502 0.75304,-0.54475 2.16476,-1.86006 2.16476,-1.86006 l 0,1.62374 -0.5751,0 0,1.48807 6.86709,0 0,-2.84135 -1.92841,0 3.21374,-23.57782 -7.37422,0 0,2.33412 z m -93.60062,7.55781 2.33363,15.57933 6.23084,0 4.04243,-11.34169 1.62654,11.34169 5.88425,0 7.05633,-16.38872 0,-2.0141 -6.1713,0 0,2.82349 1.88966,0 -4.04243,10.16973 -0.74151,0 -1.29167,-12.55773 -5.38194,0 -4.7361,12.50989 -1.55478,-12.94538 -6.86496,0 0,2.82349 z m -12.15,0.72146 c -0.56264,0.0892 -1.03524,0.17358 -1.53086,0.45447 -0.737,0.41808 -1.46132,0.95771 -1.91357,1.67437 -0.44123,0.70048 -0.53204,1.57581 -0.66975,2.39196 -0.1751,1.04003 -0.20064,2.10306 -0.19136,3.15741 0.01,0.81614 -0.0138,1.66577 0.35879,2.39197 0.1904,0.37315 0.52874,0.80945 0.88503,1.02855 0.56015,0.34453 1.06632,0.55494 1.72222,0.598 0.72597,0.0483 1.48801,-0.18852 2.10493,-0.57408 0.59422,-0.37072 1.03334,-0.97401 1.38735,-1.5787 0.46117,-0.78744 0.70905,-1.69257 0.90895,-2.58334 0.20377,-0.90704 0.33579,-1.84565 0.28703,-2.77468 -0.0491,-0.92714 -0.18211,-1.88434 -0.57407,-2.72684 -0.2728,-0.58681 -0.70954,-1.00753 -1.29166,-1.29165 -0.44403,-0.21628 -0.99455,-0.24402 -1.48303,-0.16744 z m -6.62442,-0.73581 c 0.65404,-0.6664 1.4072,-1.25479 2.23273,-1.69161 1.0305,-0.54505 2.16429,-0.92749 3.31518,-1.11604 1.51307,-0.24806 3.09342,-0.2847 4.60036,0 0.88055,0.16632 1.78322,0.44742 2.50307,0.98113 0.77409,0.57312 1.35279,1.40936 1.79291,2.26639 0.42901,0.83457 0.6828,1.77223 0.77798,2.70605 0.16564,1.61985 0.024,3.29135 -0.37201,4.87103 -0.33328,1.33759 -0.88436,2.64754 -1.65745,3.78889 -0.67549,0.99679 -1.52894,1.91262 -2.53721,2.5709 -0.89957,0.58746 -1.9718,0.87641 -3.01035,1.15006 -0.87153,0.22963 -1.77166,0.4095 -2.67235,0.40576 -1.21068,-0.01 -2.47998,-0.0817 -3.58589,-0.57511 -1.09854,-0.48896 -1.89728,-1.32739 -2.60455,-2.30013 -0.61123,-0.83995 -1.02561,-1.59975 -1.31932,-2.87516 -0.2125,-0.9233 -0.40006,-2.19912 -0.37215,-3.14592 0.0335,-1.16537 0.3568,-2.74121 0.83416,-3.80434 0.52547,-1.17098 1.17609,-2.3161 2.07489,-3.2319 z m 94.95184,13.82318 c -2.20516,1.01761 -4.61429,1.69636 -7.02343,1.69636 -5.32726,0 -7.22678,-3.12145 -7.22678,-7.22678 0,-7.1251 4.54685,-11.19645 10.0772,-11.19645 3.7324,0 5.56453,1.69625 5.56453,4.47856 0,4.85189 -5.12329,6.27735 -10.41633,6.82001 0.10168,1.73076 0.81446,3.32485 3.3592,3.32485 1.2218,0 2.88401,-0.37315 4.91982,-1.22099 z m -3.22292,-11.77374 c 0,-0.81423 -0.57695,-1.28891 -1.62876,-1.28891 -1.89988,0 -3.46041,1.66212 -3.96978,4.34287 1.45897,-0.20368 5.59854,-0.91613 5.59854,-3.05396 z m -30.33408,11.77374 c -2.2054,1.01761 -4.61457,1.69636 -7.02371,1.69636 -5.32653,0 -7.22671,-3.12145 -7.22671,-7.22678 0,-7.1251 4.54679,-11.19645 10.07785,-11.19645 3.73175,0 5.56382,1.69625 5.56382,4.47856 0,4.85189 -5.12273,6.27735 -10.41568,6.82001 0.10142,1.73076 0.81422,3.32485 3.35884,3.32485 1.22158,0 2.8842,-0.37315 4.91994,-1.22099 z m -3.22305,-11.77374 c 0,-0.81423 -0.57638,-1.28891 -1.62883,-1.28891 -1.89959,0 -3.46023,1.66212 -3.96971,4.34287 1.4591,-0.20368 5.59854,-0.91613 5.59854,-3.05396 z m -82.36051,20.5268 -0.0679,-0.13571 0.98406,-5.66614 2.10303,-15.16698 c 0.0687,-0.40664 -0.0332,-0.61046 -0.30522,-0.71214 l -1.66259,-0.61111 0.37379,-2.57855 6.78556,0 -0.40663,2.71427 0.10142,0.0335 c 2.0016,-1.86631 4.10566,-3.08743 6.24306,-3.08743 2.91821,0 4.95366,1.86577 4.95366,6.78561 0,4.68241 -1.83206,11.6379 -8.14271,11.6379 -2.20534,0 -3.42694,-0.84825 -4.68256,-1.73039 l -0.74621,5.08917 c -0.0341,0.37361 0.0326,0.50898 0.47457,0.54273 l 3.42697,0.33969 -0.37385,2.5447 -9.0589,0 z m 6.78613,-12.04485 c 0.84787,0.71258 1.96788,1.32305 3.22348,1.32305 2.74798,0 3.76601,-3.86811 3.76601,-6.85368 0,-2.002 -0.47476,-3.32542 -1.76432,-3.32542 -1.35696,0 -3.08763,1.4591 -4.30913,2.54506 z m 81.08934,4.85147 0.33969,-2.54464 1.56064,-0.2038 c 0.47498,-0.0683 0.5429,-0.1695 0.61084,-0.67837 l 1.42466,-10.34864 c 0.0335,-0.37315 -0.0335,-0.61046 -0.33914,-0.71214 l -1.69691,-0.61111 0.37365,-2.57855 6.71797,0 -0.44097,3.05395 0.10191,0.0679 c 1.32326,-1.89982 3.22359,-3.46042 5.39485,-3.46042 0.7463,0 2.0359,0.13582 2.61295,0.30538 l -0.84863,6.17508 -3.96972,-0.13582 -0.10157,-1.76443 c -0.0335,-0.30537 -0.10223,-0.40701 -0.37391,-0.40701 -0.64452,0 -1.69636,0.78027 -2.64651,1.76455 l -1.18674,8.61817 c -0.0687,0.54303 -0.0334,0.64474 0.47477,0.67874 l 3.22351,0.27142 -0.37384,2.51081 -10.8575,0 z" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cssscccccccccccccccccssssssssccssscssssscsssccccccccsssssssssccsccsssssssssscsscccccccccccccccccccccccccccccccsssscsssssscscsssssssscsssssssssscsssscsccsscscsssscsccsscsccccccccccsssccccccccssscccccccccccccsccccsccccccc" /><path + sodipodi:nodetypes="cssscccccccccccccccccssssssssccssscssssscsssccccccccsssssssssccsccsssssssssscsscccccccccccccccccccccccccccccccsssscsssssscscsssssssscsssssssssscsssscsccsscscsssscsccsscsccccccccccsssccccccccssscccccccccccccsccccsccccccc" + inkscape:connector-curvature="0" + d="m 509.55935,174.26011 c 0.63327,0.31663 2.06355,1.10555 3.19256,1.13455 0.61476,0.0158 1.25757,-0.18443 1.76781,-0.5277 1.3288,-0.89397 2.46618,-2.23946 3.00784,-3.74661 0.21419,-0.59598 0.0258,-1.89972 0.0258,-1.89972 l -4.22153,-15.51428 -2.18993,0 0.55406,-2.95501 7.01835,0 2.82313,13.48255 5.27696,-10.68586 -2.21631,0 0,-2.92858 7.94179,0 -12.13698,24.69605 -1.87332,2.11078 -2.5329,1.4776 -2.71762,0.29022 -2.53295,-0.23748 -3.08699,-1.50392 z m -13.30698,-16.06545 c -1.0335,2.08005 -1.87803,4.80122 -0.90274,6.90883 0.4032,0.87116 1.49018,1.31738 2.4179,1.56347 0.67214,0.17793 1.42477,0.1102 2.08233,-0.11548 0.53084,-0.1826 0.97383,-0.5762 1.38432,-0.9593 0.44502,-0.4157 0.85733,-0.8875 1.14176,-1.42582 0.24113,-0.45665 0.44375,-0.93526 0.54404,-1.44168 0.22797,-1.1566 0.3958,-2.3252 0.37043,-3.50371 -0.0204,-0.96413 -0.0869,-2.06387 -0.52631,-2.92259 -0.29054,-0.56679 -0.84946,-0.79259 -1.46826,-0.94463 -0.46761,-0.11559 -0.89829,-0.0686 -1.34322,0.11597 -0.72226,0.30083 -1.38368,0.5859 -2.00879,1.05634 -0.63242,0.4762 -1.33915,0.9593 -1.69146,1.6686 z m 0.72346,-4.75648 c 0,0 2.41951,-1.99358 3.81169,-2.50482 0.79109,-0.29085 3.80953,-0.71977 4.57766,-0.3726 1.6247,0.73503 2.49408,1.73759 3.00274,2.86791 0.50868,1.13043 0.77154,2.86756 0.87911,4.12137 0.14648,1.71007 -0.15092,4.16549 -0.58904,6.34083 -0.33179,1.64636 -1.12383,3.02703 -2.02388,4.32576 -1.17506,1.6957 -2.01178,2.37286 -4.04556,2.72004 -1.09051,0.18629 -2.13814,0.51607 -3.59006,0.10268 -1.5866,-0.45183 -2.59522,-0.89615 -3.74599,-1.8017 -0.79994,-0.62933 -1.28003,-1.6992 -1.28003,-1.6992 l 0,3.11766 -5.39426,0 3.74898,-25.38802 -2.12052,-0.94738 0.0443,-2.62669 8.00657,0.0587 z m -26.22853,2.43167 c 0.32185,1.64663 0.0893,5.33062 -0.9498,7.38781 -0.33781,0.66857 -1.04588,1.46667 -1.7151,1.8733 -1.11975,0.68073 -2.44527,1.33822 -3.7466,1.18729 -0.52883,-0.0601 -1.07036,-0.37888 -1.37203,-0.81791 -0.52601,-0.76478 -0.48121,-1.71012 -0.50128,-2.63848 -0.0263,-1.17893 0.14487,-2.46835 0.42212,-3.6147 0.20635,-0.8543 0.4665,-1.74564 0.94981,-2.48024 0.43067,-0.65433 1.02178,-1.24217 1.71508,-1.60939 0.60504,-0.32004 1.32025,-0.42437 2.00521,-0.44854 0.70197,-0.0251 1.4374,0.0425 2.08446,0.31654 0.4274,0.18153 1.01882,0.3888 1.10813,0.84432 z m 1.42642,-10.68922 -0.70874,6.75362 c 0,0 -1.85753,-1.06838 -2.8735,-1.38048 -0.80562,-0.24744 -1.65802,-0.40424 -2.49984,-0.37318 -1.07069,0.0382 -2.10882,0.24369 -3.1078,0.62968 -1.01321,0.39157 -1.96724,1.04315 -2.75039,1.79572 -0.97095,0.93248 -1.67003,2.10085 -2.23897,3.3208 -0.43738,0.93753 -0.76677,1.93354 -0.9704,2.94777 -0.2523,1.26016 -0.4899,2.63324 -0.48461,3.91802 0.011,1.59795 0.0683,3.19329 0.59661,4.70144 0.28155,0.80417 0.79028,1.55058 1.41822,2.127 0.62695,0.57587 1.4292,0.96634 2.23856,1.23121 0.45301,0.14881 0.94135,0.19054 1.41828,0.18685 1.10615,-0.011 2.24705,-0.0973 3.28346,-0.48539 0.73352,-0.2745 1.34304,-0.80959 1.97773,-1.2687 0.83064,-0.60085 2.38786,-2.05176 2.38786,-2.05176 l 0,1.79104 -0.63429,0 0,1.64147 7.57478,0 0,-3.13415 -2.12721,0 3.54494,-26.00772 -8.13411,0 0,2.57462 z m -103.24702,8.33671 2.57413,17.18493 6.87304,0 4.45903,-12.51049 1.79414,12.51049 6.49065,0 7.78353,-18.07772 0,-2.2217 -6.8073,0 0,3.11449 2.08446,0 -4.45903,11.21783 -0.8179,0 -1.42488,-13.85193 -5.93654,0 -5.2242,13.79919 -1.71497,-14.27958 -7.57246,0 0,3.11449 z m -13.4021,0.79586 c -0.62064,0.0982 -1.14194,0.19148 -1.68866,0.50127 -0.813,0.46118 -1.61192,1.05641 -2.11077,1.84697 -0.48673,0.77268 -0.58683,1.73821 -0.73875,2.63846 -0.1932,1.14723 -0.22134,2.31976 -0.21116,3.48281 0.011,0.90024 -0.0148,1.83747 0.39579,2.63847 0.21,0.41165 0.58324,0.89285 0.97623,1.13455 0.61796,0.38003 1.17622,0.61214 1.89972,0.6596 0.80077,0.0533 1.64141,-0.20792 2.32189,-0.63318 0.65546,-0.40892 1.13978,-1.07441 1.53029,-1.7414 0.50878,-0.86864 0.78215,-1.86707 1.00265,-2.84964 0.22477,-1.00044 0.37039,-2.03585 0.31663,-3.06058 -0.0541,-1.02274 -0.20091,-2.07854 -0.63327,-3.00784 -0.3009,-0.64731 -0.78264,-1.11143 -1.42476,-1.42485 -0.48983,-0.23858 -1.09705,-0.26912 -1.63583,-0.18464 z m -7.30711,-0.81171 c 0.72143,-0.735 1.55219,-1.38409 2.46282,-1.86591 1.1367,-0.60125 2.38729,-1.02309 3.65678,-1.23104 1.66908,-0.27366 3.41222,-0.314 5.07446,0 0.97135,0.18342 1.96702,0.49352 2.76107,1.08223 0.85389,0.63222 1.49219,1.55466 1.97771,2.49999 0.47321,0.92057 0.7531,1.95483 0.85808,2.98495 0.18274,1.78675 0.0263,3.63055 -0.41031,5.37303 -0.36757,1.47539 -0.97545,2.92034 -1.82825,4.17929 -0.74509,1.09959 -1.68654,2.10982 -2.79871,2.8359 -0.99227,0.64796 -2.175,0.96671 -3.32055,1.26856 -0.96139,0.25333 -1.95426,0.4517 -2.94774,0.44756 -1.33549,-0.011 -2.73559,-0.0897 -3.9555,-0.63431 -1.21174,-0.53936 -2.09278,-1.46419 -2.87295,-2.53723 -0.67423,-0.92645 -1.13131,-1.76457 -1.45532,-3.17146 -0.2344,-1.0184 -0.44126,-2.42572 -0.41044,-3.47012 0.0365,-1.28547 0.39349,-3.02371 0.92005,-4.19644 0.57967,-1.29168 1.29729,-2.5548 2.2888,-3.565 z m 104.73744,15.24778 c -2.43247,1.12251 -5.0899,1.87126 -7.74734,1.87126 -5.87626,0 -7.97147,-3.44315 -7.97147,-7.97158 0,-7.8594 5.0154,-12.35035 11.11569,-12.35035 4.11711,0 6.13803,1.87105 6.13803,4.94016 0,5.35189 -5.65129,6.92425 -11.48983,7.52281 0.11219,1.90916 0.89836,3.66755 3.7054,3.66755 1.3477,0 3.18121,-0.41165 5.42682,-1.34689 z m -3.55513,-12.98704 c 0,-0.89823 -0.63635,-1.42181 -1.79655,-1.42181 -2.09568,0 -3.81712,1.83342 -4.37899,4.79047 1.60937,-0.22468 6.17554,-1.01053 6.17554,-3.36866 z m -33.46028,12.98704 c -2.4327,1.12251 -5.09006,1.87126 -7.74751,1.87126 -5.87553,0 -7.97151,-3.44315 -7.97151,-7.97158 0,-7.8594 5.01539,-12.35035 11.11645,-12.35035 4.11635,0 6.13722,1.87105 6.13722,4.94016 0,5.35189 -5.65062,6.92425 -11.48908,7.52281 0.11182,1.90916 0.89812,3.66755 3.70494,3.66755 1.34748,0 3.1815,-0.41165 5.42704,-1.34689 z m -3.55514,-12.98704 c 0,-0.89823 -0.63578,-1.42181 -1.79674,-1.42181 -2.09539,0 -3.81683,1.83342 -4.37881,4.79047 1.60951,-0.22468 6.17555,-1.01053 6.17555,-3.36866 z m -90.84852,22.6422 -0.0749,-0.14971 1.08546,-6.25004 2.31984,-16.73008 c 0.0757,-0.44854 -0.0367,-0.67336 -0.33673,-0.78554 l -1.83388,-0.67411 0.41228,-2.84425 7.48486,0 -0.44853,2.99397 0.11182,0.0371 c 2.2079,-2.05871 4.52887,-3.40563 6.88646,-3.40563 3.21901,0 5.46427,2.05807 5.46427,7.48491 0,5.16501 -2.02094,12.8373 -8.98192,12.8373 -2.43264,0 -3.78014,-0.93565 -5.16516,-1.90869 l -0.82311,5.61357 c -0.0376,0.41212 0.0356,0.56148 0.52347,0.59873 l 3.78017,0.37469 -0.41234,2.8069 -9.9925,0 z m 7.48553,-13.28615 c 0.93528,0.78598 2.17068,1.45946 3.55568,1.45946 3.03118,0 4.15411,-4.26682 4.15411,-7.56009 0,-2.2083 -0.52366,-3.66812 -1.94612,-3.66812 -1.49686,0 -3.40583,1.6095 -4.75323,2.80736 z m 89.44624,5.35147 0.37469,-2.80694 1.72154,-0.2248 c 0.52388,-0.0753 0.5988,-0.1869 0.67374,-0.74827 l 1.57152,-11.41514 c 0.0365,-0.41155 -0.0368,-0.67336 -0.3741,-0.78554 l -1.87181,-0.67411 0.41215,-2.84425 7.41037,0 -0.48647,3.36865 0.11241,0.0749 c 1.45966,-2.09562 3.55581,-3.81702 5.95085,-3.81702 0.8232,0 2.2457,0.14982 2.88225,0.33688 l -0.93613,6.81148 -4.37882,-0.14982 -0.11196,-1.94633 c -0.0371,-0.33677 -0.11284,-0.44891 -0.41252,-0.44891 -0.71092,0 -1.87116,0.86067 -2.91921,1.94635 l -1.30904,9.50637 c -0.0757,0.59903 -0.0368,0.71124 0.52367,0.74874 l 3.55571,0.29932 -0.41234,2.76961 -11.9765,0 z" + style="fill:url(#linearGradient5134);fill-opacity:1;stroke:none" + id="path5080" /></g><path + fill="#E2E2E2" + d="M256.023,135.437H196.36c-16.432,0-29.8,13.368-29.8,29.8v73.527c0,16.432,13.368,29.8,29.8,29.8h59.663 c16.433,0,29.801-13.368,29.801-29.8v-73.527C285.824,148.805,272.456,135.437,256.023,135.437z M191.561,165.236 c0-2.646,2.153-4.8,4.8-4.8h59.663c2.647,0,4.801,2.153,4.801,4.8v73.527c0,2.646-2.153,4.8-4.801,4.8H196.36 c-2.646,0-4.8-2.153-4.8-4.8V165.236z" + id="path3" /><path + d="m 531.664,250.155 h 18.498 l -2.809,18.064 h 5.59 37.586 l 2.6,-17.718 c 4.98,-1.091 9.133,-3.455 12.512,-6.693 3.084,4.075 8.566,7.37 18.252,7.37 6.338,0 12.775,-1.807 17.174,-3.687 4.254,2.399 9.463,3.687 15.459,3.687 3.088,0 6.236,-0.355 9.426,-1.023 h 67.135 l 3.354,-24.827 -5.445,-0.764 1.879,-13.356 c 0.371,-2.386 0.449,-4.66 0.449,-6.156 l -0.008,-0.375 c -0.457,-12.191 -8.139,-19.765 -20.045,-19.765 -2.404,0 -4.623,0.314 -6.676,0.852 h -34.189 l -0.035,0.244 c -2.527,-0.701 -5.41,-1.096 -8.686,-1.096 -3.801,0 -7.406,0.555 -10.76,1.598 l 0.105,-0.746 h -12.467 l 1.826,-12.951 H 615.08 l -1.846,7.658 c -1.373,5.704 -2.213,5.793 -4.453,6.03 l -4.508,0.477 c -3.049,-1.424 -6.357,-2.065 -9.602,-2.065 -2.135,0 -4.275,0.284 -6.416,0.852 h -19.291 c 0.502,-1.772 0.775,-3.674 0.775,-5.678 0,-9.601 -6.846,-16.305 -16.646,-16.305 -11.055,0 -18.775,7.721 -18.775,18.776 0,0.951 0.082,1.869 0.219,2.764 -2.135,-0.288 -4.277,-0.409 -5.553,-0.409 -2.053,0 -4.072,0.288 -6.045,0.852 h -31.342 c -2.74,-0.553 -5.641,-0.852 -8.537,-0.852 -7.138,0 -13.492,1.674 -18.808,4.723 l -3.451,-1.461 c -3.711,-1.571 -11.232,-3.262 -18.979,-3.262 -8.933,0 -16.383,2.56 -21.576,7.016 -3.265,-4.473 -8.523,-7.016 -15.228,-7.016 -4.822,0 -9.021,1.477 -12.572,3.44 -2.996,-2.204 -6.796,-3.44 -11.115,-3.44 -2.327,0 -4.48,0.315 -6.476,0.852 h -33.963 l -0.035,0.245 c -2.526,-0.702 -5.41,-1.097 -8.687,-1.097 -20.458,0 -35.307,16.031 -35.307,38.117 0,17.363 10.785,28.149 28.148,28.149 3.087,0 6.236,-0.356 9.426,-1.023 h 88.816 c 3.706,0.676 7.669,1.023 11.154,1.023 8.907,0 16.278,-2.375 21.51,-6.593 4.872,4.252 11.585,6.593 19.728,6.593 3.053,0 6.206,-0.368 9.286,-1.023 h 44.664 2.069 z" + id="path5" + inkscape:connector-curvature="0" + style="fill:#e2e2e2" /><path + fill="#F5F5F5" + d="M255.023,133.437H195.36c-16.432,0-29.8,13.368-29.8,29.8v73.527c0,16.432,13.368,29.8,29.8,29.8h59.663 c16.433,0,29.801-13.368,29.801-29.8v-73.527C284.824,146.805,271.456,133.437,255.023,133.437z M190.561,163.236 c0-2.646,2.153-4.8,4.8-4.8h59.663c2.647,0,4.801,2.153,4.801,4.8v73.527c0,2.646-2.153,4.8-4.801,4.8H195.36 c-2.646,0-4.8-2.153-4.8-4.8V163.236z" + id="path7" /><g + id="g9"><g + id="g11"><path + fill="#FBFDF8" + d="M195.361,251.626c-8.161,0-14.8-6.64-14.8-14.8v-73.527c0-8.161,6.639-14.8,14.8-14.8h59.663 c8.161,0,14.8,6.639,14.8,14.8v73.527c0,8.16-6.639,14.8-14.8,14.8H195.361z" + id="path13" /><path + fill="#F0F4E1" + d="M255.024,152.499c5.964,0,10.8,4.835,10.8,10.8v73.527c0,5.965-4.835,10.8-10.8,10.8h-59.663 c-5.964,0-10.8-4.835-10.8-10.8v-73.527c0-5.964,4.835-10.8,10.8-10.8H255.024 M255.024,144.499h-59.663 c-10.366,0-18.8,8.434-18.8,18.8v73.527c0,10.366,8.434,18.8,18.8,18.8h59.663c10.366,0,18.8-8.434,18.8-18.8v-73.527 C273.824,152.933,265.391,144.499,255.024,144.499L255.024,144.499z" + id="path15" /></g><defs + id="defs17"><filter + id="Adobe_OpacityMaskFilter" + filterUnits="userSpaceOnUse" + x="176.562" + y="144.499" + width="97.263" + height="111.127"><feColorMatrix + type="matrix" + values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" + color-interpolation-filters="sRGB" + result="source" + id="feColorMatrix20" /></filter></defs><mask + maskUnits="userSpaceOnUse" + x="176.562" + y="144.499" + width="97.263" + height="111.127" + id="SVGID_1_"><g + filter="url(#Adobe_OpacityMaskFilter)" + id="g23"><image + overflow="visible" + width="422" + height="480" + xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEBLAEsAAD/7AARRHVja3kAAQAEAAAAHgAA/+4AIUFkb2JlAGTAAAAAAQMA EAMCAwYAAAg2AAAQ4QAAF1b/2wCEABALCwsMCxAMDBAXDw0PFxsUEBAUGx8XFxcXFx8eFxoaGhoX Hh4jJSclIx4vLzMzLy9AQEBAQEBAQEBAQEBAQEABEQ8PERMRFRISFRQRFBEUGhQWFhQaJhoaHBoa JjAjHh4eHiMwKy4nJycuKzU1MDA1NUBAP0BAQEBAQEBAQEBAQP/CABEIAeMBqQMBIgACEQEDEQH/ xACjAAEAAgMBAQAAAAAAAAAAAAAABQYBAwQHAgEBAQAAAAAAAAAAAAAAAAAAAAEQAAEDAQQKAwAC AwEAAAAAAAABAwQCMRMUBRBQEjMVJQYWNgcgESEwI5AiMkARAAEBAwsEAQIFAwUBAAAAAAABMQID EFAycqOz0wQ0RaURIXGRIEFRMGEiExRAgRKh0SMzQxUSAQAAAAAAAAAAAAAAAAAAAJD/2gAMAwEA AhEDEQAAANUJsrZYFfFgV8WBXxYEL0ki5fo6GjJuaRuaRuaRuaRuaRuaRuaRuaRuaRuaRuaRuaRu aRuaMHQ5dR3ojnJ9XxYFfFgV8WD0jxf2AodbslbAD6mDhlpLvI/qkuiovZL7CGzNfRCJwQacEGnB Bp0QSdEEnRBJ0QSdEEnRBJ3BBpwQacEHidwQXzPfBA6bBqK5w2nlKVH3iJitt+gAeweP+wFDrdkr Y+vmaN02k6+e3d2Gjo6N0c2zoyaM7xozuGluGluGluGluGluGluGluGluGluGluGluGnG8c/z1YO PVIfJF80xoIGPsfBVVrl6hIrD7+B7B4/7AUOt2StnXaYyxHTJ6ZKvrqb4x9MgAAAAAAAAAAAAAAA DGR8692Dh4pbkIKJscTVNiLdVY1+weP+wFDgJ+JLJORs3XbIc3dGz6ZAAAAAAAAAAAAAAAAAAAPn R0ayMi5uLqv1S51eIT2Dx/2AofB38Ra5uIm6kOzm6o+gAAAAAAAAAAAAAAAAAAAPj7+TkjJWNIOt 2et1WfYPH/YIofH2cZcJyEnKkenn6IyAAAAAAAAAAAAAAAAAAABjODmjZONIWt2WtVWPYPH/AGCK Hx9nIXGcg5ypLfo3xkAAAAAAAAAAAAAAAAAAADGcHPGyUaQ1astaqseweP8AsEUPk6+QuM7BTtSW 7TujIAAAAAAAAAAAAAAAAAAAGM4OeOkY4hqzZqzVY9g8f9gih8nXyFxnYKdqS3ad0ZAAAAAAAAAA AAAAAAAAAAxnBzx0jHENWbNWarHsHj/sEUPk6+QuM7BTtSW7TujIAAAAAAAAAAAAAAAAAAAGM4Oe OkY4hqzZqzVY9g8f9gih8nXyFxnYKdqS3ad0ZAAAAAAAAAAAAAAAAAAAAxnBzx0jHENWbNWarHsH j/sEUPk6+QuM7BTtSW7TujIAAAAAAAAAAAAAAAAAAAGM4OeOkY4hqzZqzVY9g8f9gih8nXyFxnYK dqS3ad0ZAAAAAAAAAAAAAAAAAAAAxnBzx0jHENWbNWarHsHj/sEUPk6+QuM7BTtSW7TujIAAAAAA AAAAAAAAAAAAAGM4OeOkY4hqzZqzVY9g8f8AYIofJ18hcZ2Cnakt2ndGQAAAAAAAAAAAAAAAAAAA MZwc8dIxxDVmzVmqx7B4/wCwRQ+Tr5C4zsFO1JbtO6MgAAAAAAAAAAAAAAAAAAAYzg546RjiGrNm rNVj2Dx/2CKHydfIXGdgp2pLdp3RkAAAAAAAAAAAAAAAAAAADGcHPHSMcQ1Zs1ZqseweP+wRQ+Tr 5C4zsFO1JbtO6MgAAAAAAAAAAAAAAAAAAAYzg546RjiGrNmrNVj2Dx/2CKHydfIXGdgp2pLdp3Rk AAAAAAAAAAAAAAAAAAADGcHPHSMcQ1Zs1ZqseweP+wRQ+Tr5C4zsFO1JbtO6MgAAAAAAAAAAAAAA AAAAAYzg546RjiGrNmrNVj2Dx/2CKHydfIXGdgp2pLdp3RkAAAAAAAAAAAAAAAAAAADGcHPHSMcQ 1Zs1ZqseweP+wRQ+Tr4y5TkHOVJb9G+MgAAAAAAAAAAAAAAAAAAAYzg542SjSGrVlrVVj2Dx/wBg ih8fZxlxnIKcqT6ObpjIAAAAAAAAAAAAAAAAAAAGM4OeNkY0h61Za1VY9g8f9gih8Xbwlxm4GbqW 6uLrj7AAAAAAAAAAAAAAAAAAAA+fr5OaNkI0ia1Y61Vb9g8f9gihxknCl1m65N1OdsZ3x0ZxkAAA AAAAAAAAAAAAAAAAx8fek5ozui6jazYKsRPsHj/sEUOu2Ktlqn6XZ6scjBSRLbOPpjYxkAAAAAAA AAAAAAAAAAYfJjm+uM0xXVE1xVOZr0Y9g8f9gKHW7JWz7s1W6i9SdYlasXXB9pLbI7fHY5/s3NeT 7fGT6fI+nyPp8j6fI+nyPp8j6fI+nyPp8j6fI+nyPp8D7x8fJtxp1m7Tp5jbw/MfWIjbXTk5SHsH j/sBQ63ZK2AdthqO8vXbUZWrJ0V/oJ7ZB7Sa+ofJMIkS6IySyJRLIkSyJEsiRLIkSyJEsiRLIkSy JVLYiRLYicEr8xfwSemN0kjy8PIdkfxQp0xWEAPYPH/YCh1uyVsAAz08ome2si37qZkumaULspIu 2aRkuyki7KSLspIuyki7KSLspIuyki7KSLtilC6qSLtilC6fNNFu5qz8k7wcI+vkAAHsHj/sBWoQ AAAAAAAAAAAAAAAAAAAAAAAAAHpAf//aAAgBAgABBQD/ACi//9oACAEDAAEFAP8AKL//2gAIAQEA AQUA6w6rz/LM+776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvv qs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qz vvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++ qzvvqs776rMfLPYHlHyRFUbivuDeUv1FOSVKJkRwE4CcAOAHADgBwA4AcAOAHADgBwA4AcAOAHAD gBwA4AcAOAHADgBwA4AcAOAnARciFyRUK8ndQcgyGxaaqf4fYHlHwRFUjZe68RsqbpGoKIUQkKYY kISEYJDAmBMCYEwJgTAmBMCYEwJgTAmBMCYEwJgTAmBMCYEwJgTAmCQWELCKoSFcNByEhIyxusk5 VVQV0VUL8vYHlGltupyqDlaIMREQaijcUoilMUSKgkZDDIYZDDIYZDDIYZDDIYZDDIYZDDIYZDDI YZDDIYZDDIYZDDIYZDDIYZDDIYZDDIYZDDILGQWKVRSuKORR2KPRCZltDiSYrjFXx9geUaG26nKs vy9KEjxhmONRxuOUMFLAjIjJdF0XRdIXSF0hdF0XRdF0XRdF0XRdF0XRdF0XRdIXSF0hdIXRdCsi sisFTBXHHY49GH4xMhU10y4tTFfw9geUCJ9rlcL6SNHGGBlgbZKGilsShDZQ+kPr/wBX0fSGygtC CtoVNDjI6wPsElgzCGjlLrdTden2B5QZfGvnYbCIkdkYZGmihsSn61ItJXQOtD7JIZJTBm0X6+Hs DyhP1cpjbLcVojtDLY3QIn1qZU+yugebJDRKaJ7CVUvtq27o9geURaLx6C19JFbI7Y1QU0/WqFQd oH6CS2TG/wAzZrZd0ewPKMqo2n4VH5FoGKBunVTifj9JJpJdBnVH+mj2B5RkqfdcOki0jFJQn5qm pPx5CTSS6TOKf6tHsDyjI0/2hIRU/GUKbNU1DyfklCWhm6f06PYHlGRf9QkIqfjKCWapWx4kkszj daPYHlGQ2wrItjImqlseJJMM43Wj2B5RkNsEjWNarUeJJMM43Oj2B5RkNsEjWNarUeJJMM43Oj2B 5RkNsGyLY1qtR6ySTDONzo9geUZDbBsi2NarUesk2TDON1o9geUZDbBsjWNarUesk2TDON1o9geU ZDbBsjWNarUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDb BsjWNarUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsj WNarUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNa rUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUe skkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUeskk wzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUeskkwzj daPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUeskkwzjdaP YHlGQ2wbI1jWq1HrJNkwzjdaPYHlGQ2wbItjWq1HrJNkwzjdaPYHlGQ2wbItjWq1HrJJMM43Oj2B 5RkNsGyNY1qtR4kkwzjc6PYHlGQ2wSNY1qtR4kkwzjc6PYHlGQ2wrItjImqlseJJMM43Wj2B5RkV sJSKv4yolmqVseJJLM43Wj2B5Rkf/UJSKv4ypTZqmoeX8kqS1M43Oj2B5Rki/wC0Koi1DKlC/mqa h5SSpLUzdf6tHsDyjJ6/p2HURaxiobX81TWv4/USaiXUZy59N6PYHlGXubEiE5+RaxisaqEXVCjl Q/WSayXX+Zy59ro9geUUVbNeXPpVRFdI7gzWUVfeqK6h2skOElwmu/ST3bx/R7A8oMpk/SxHiM8M OjThTX9iLqWqr6HHB50kOkp4zSVsUVKqro9geUDLit15fLSumM+MPjTw26UuCVH2moPsWoqcK3R1 4feJD5MkIiTpKvO6fYHlGiFLViuHLSpGJAzIGnyh8peKXRHEEcQ20NtDbQ2kNpDaQ2kNpDaQ2kNp DaQ2kNpDaQ2kNpDaQ2kNpDaQ2kNpDaQ20NtDbQVxBXEFdKnit8cfHpA/IJMn6TMp+0vw9geUaYU+ pmqJNprRmUNSRuSUSSmQgkgSQI+X5fl+X5fl+X5fl+X5fl+X5fl+X5fl+X5fl+X5fl+X4r4sgWQV SCuSOSR2SPSiRLREzDMlUVVVfh7A8o+EeW4wsTNKKxmYijcsollMspliSxJZjDGIYxDGIYxDGIYx DGIYxDGIYxDGIYxDGIYxDGIYxDGIYxDGIYxDGIYxDGIYxBZYssqllUsrljksdmISsxooSVmLjyqq r8vYHlHxRVRWZ77QznNI3mzSlGZUKU5hSJmKHEUOIocRQ4jScRQ4ihxFDiKHEUOIocRQ4ihxFDiK HEUOIocRQ4ihxFDiKHEUOIocRpOIocRQ4ihxFBcxQXMEKsxpHM1aQezmhB/M3nCquqtfn7A8o/hS utC9dL50vnS/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/ eL50vnS9dLytT7X+PrDhvHuTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOT HJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY/pP/aAAgBAgIGPwBR f//aAAgBAwIGPwBRf//aAAgBAQEGPwCPk8jmv2su47DV1z9uE90V5xHl7vuKrTXWMHDNdYwcM11j BwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHD NdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11 jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMH DNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDP+z/AEd/2MzUhXbvz7H6XVO/ Y7vFJSkpSUpKUlKSlJSkpSUpKUlKSlJSkpSUpKUlKSlJSkpSUpKUlKSlJSkpSUpKUlKSlJSkp+le p3d6ndOn4OZqQrt349EOqp0QT9PVfzGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGC9X RVh9/wAjo8nRfnmakK7d+H+LqdVEefTqonYYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBg wYMGDBeqd/uKip2+/wAszUhXbsqOutURVT9SidhgwYMlZ/XsGDBgvYVFQVOnb6fHM1IV27J0QR95 O6idhOwyaWC9hU6d/oK6v0+GZqQrt2RFVOyCdhBJrUU/cRO6N+GZqQrt06CL07qIJNiijydGjzsu ZqQrt0dd/MRBBJsUUU/y+8uZqQrt06/YQQSbFFFOv2WXM1IV26KIJNyij0uZqQrt0e8iCTcoo/Lm akK7dHvIggk2KKKPy5mpCu3R7yIJNyij8uZqQrt0e8iCTcoo/LmakK7dHvIgk3KKPy5mpCu3R7yI JNyij8uZqQrt0e8iCTaooo/LmakK7dHvIgk3KKPy5mpCu3R7yIJNyij8uZqQrt0e8iCCTaoo/Lma kK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu3R7y IIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCCTaoo /LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu 3R7yIIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCC Taoo/LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCTcoo/LmakK7dHvIgk2qKKPy5m pCu3R7yIJNyij8uZqQrt0e8iCTcoo/LmakK7dHvIgk3KKPy5mpCu3R7yIJNyij8uZqQrt0e8iCCT aoo/LmakK7dHvIgk3KKPy5mpCu3R4QSblFHpczUhXboqfcQQSbVFFT7y5mpCu3RPzEEEmxRRRHZc zUhXbojyfRR1RBJsUUUX7JLmakK7dk/bVfAgk2KKL37qwVV+suZqQrt2RHk+giook2L3F7i9GJ8M zUhXbsqItFRFRRO40aNmVo0aL3FhuL5+OZqQrt34I69REVFGjRo0aNGjf6po0aNGjRo0XuK5DXv9 zqrV+OZqQrt349UXt9hEVeijRo0aNGjRo0aNGjRo0aNGjRo0aNGjRo0aNGjRo0aNGjRo0Xq9/YVH V6OnVflmakK7d+XVOw3qh0e7FM7PJ7KQ0aNGjRo0aNGjRo0aNGjRo0aNGjRo0aNGjRpSKaH6V6nR 3sh1eXr+BmakK7d/C7KqFJfZTX2U19lNfZTX2U19lN72U3vZTe9lN72U3vZTe9lN72U3vZTe9lN7 2U3vZTe9lN72U3vZTe9lN72U3vZTe9lN72U19lNfZTX2U19lNfZSX2d3l/Ej/wAj/wCf+7/jD6/y f5/7tBOnX+L/AMfr+5tPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPK m08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptP Km08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKn/jan//Z" + transform="matrix(0.24 0 0 0.24 174.5615 142.499)" + id="image25"></image></g></mask><g + opacity="0.09" + mask="url(#SVGID_1_)" + a:adobe-blending-mode="multiply" + a:adobe-opacity-share="1" + id="g27"><path + fill="#1D2915" + a:adobe-blending-mode="normal" + a:adobe-opacity-share="0" + d="M195.361,251.626 c-8.161,0-14.8-6.64-14.8-14.8v-73.527c0-8.161,6.639-14.8,14.8-14.8h59.663c8.161,0,14.8,6.639,14.8,14.8v73.527 c0,8.16-6.639,14.8-14.8,14.8H195.361z" + id="path29" /><path + fill="#1D2915" + a:adobe-blending-mode="normal" + a:adobe-opacity-share="0" + d="M255.024,152.499 c5.964,0,10.8,4.835,10.8,10.8v73.527c0,5.965-4.835,10.8-10.8,10.8h-59.663c-5.964,0-10.8-4.835-10.8-10.8v-73.527 c0-5.964,4.835-10.8,10.8-10.8H255.024 M255.024,144.499h-59.663c-10.366,0-18.8,8.434-18.8,18.8v73.527 c0,10.366,8.434,18.8,18.8,18.8h59.663c10.366,0,18.8-8.434,18.8-18.8v-73.527C273.824,152.933,265.391,144.499,255.024,144.499 L255.024,144.499z" + id="path31" /></g></g><g + id="g33"><g + id="g35"><linearGradient + id="SVGID_2_" + gradientUnits="userSpaceOnUse" + x1="225.1929" + y1="152.499" + x2="225.1929" + y2="247.6265"><stop + offset="0.0123" + style="stop-color:#C1D72F" + id="stop38" /><stop + offset="0.1394" + style="stop-color:#BCD631" + id="stop40" /><stop + offset="0.5859" + style="stop-color:#AFD136" + id="stop42" /><stop + offset="1" + style="stop-color:#ABD037" + id="stop44" /><a:midPointStop + offset="0.0123" + style="stop-color:#C1D72F" /><a:midPointStop + offset="0.3086" + style="stop-color:#C1D72F" /><a:midPointStop + offset="1" + style="stop-color:#ABD037" /></linearGradient><path + d="M184.562,236.826c0,5.965,4.835,10.8,10.8,10.8h59.663c5.964,0,10.8-4.835,10.8-10.8v-73.527 c0-5.964-4.835-10.8-10.8-10.8h-59.663c-5.964,0-10.8,4.835-10.8,10.8V236.826z" + id="path46" + fill="url(#SVGID_2_)" /></g><defs + id="defs48"><filter + id="Adobe_OpacityMaskFilter_1_" + filterUnits="userSpaceOnUse" + x="184.562" + y="152.499" + width="81.263" + height="95.127"><feColorMatrix + type="matrix" + values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" + color-interpolation-filters="sRGB" + result="source" + id="feColorMatrix51" /></filter></defs><mask + maskUnits="userSpaceOnUse" + x="184.562" + y="152.499" + width="81.263" + height="95.127" + id="SVGID_3_"><g + filter="url(#Adobe_OpacityMaskFilter_1_)" + id="g54"><image + overflow="visible" + width="356" + height="414" + xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEBLAEsAAD/7AARRHVja3kAAQAEAAAAHgAA/+4AIUFkb2JlAGTAAAAAAQMA EAMCAwYAAAXBAAALIQAAEOP/2wCEABALCwsMCxAMDBAXDw0PFxsUEBAUGx8XFxcXFx8eFxoaGhoX Hh4jJSclIx4vLzMzLy9AQEBAQEBAQEBAQEBAQEABEQ8PERMRFRISFRQRFBEUGhQWFhQaJhoaHBoa JjAjHh4eHiMwKy4nJycuKzU1MDA1NUBAP0BAQEBAQEBAQEBAQP/CABEIAaEBawMBIgACEQEDEQH/ xACYAAEAAgMBAQAAAAAAAAAAAAAABAcBBQYDAgEBAAAAAAAAAAAAAAAAAAAAABAAAAMIAwEAAgMB AAAAAAAAAAIGATIDBBQFFjZQMwcRECKQMRMSEQABAgQEBgEBBwQDAQAAAAAAAQIxcgMEEFCRsyGC M6PTNBFBIGFxEiIyE1GB0UKhscFiEgEAAAAAAAAAAAAAAAAAAACQ/9oADAMBAAIRAxEAAADy0npz Z0Dnx0DS7Q9kr0IKcIKeICeICeICeICeICeICeICeICeICeICeICeICfggp2CElQD1aXxOgc+O1s um7kKj5vpObG6d2Q9zspRA9JmSGmCHmWIiWIiWIiWIiWIiWIiWIiWIiWIiWIiWIiWIaYIeJo1sPe 4OK5C2tCVS3OmN5clN3IVHod9EOv6zWb0zkAAAAAAAAAAAAAAAAAMRJnwcVXltVuetyU3chUfp5+ 5YexhTgAAAAAAAAAAAAAAAAABjODUVxZNbnjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwaut rJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAA AAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjy Cx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1t ZNbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAA AAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQ WPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautr JrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAAA AAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyC x5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZ NbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAA AAAAAAABjODV1tZNbHjclN3IVH7+HqWTO1uxMgAAAAAAAAAAAAAAAAAYzg1Vb2NXB5XJTdyFRx5G jLc3XG9SS2MgAAAAAAAAAAAAAAAAD4+ohqq47GvTa3JTdyFR830nNm/7qp+gLVk8fuDcZgehLRBL RBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBKQohP0MbkT40OcG8uSm7kKj5vpObAJm45sd n98SO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3xxI7PX84JcQAN5 clN3IAAAAAAAAAAAAAAAAAAAAAAAf//aAAgBAgABBQD+G3//2gAIAQMAAQUA/ht//9oACAEBAAEF AFgq7/bL9narGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxn arGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qx narGdqsZ2qxnarCYVyhn78PQNo/MCUmJhssm48QEScNrGJGEMQgjEIIxCCMQgjEIIxCCMQgjEIIx CCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIQakYQOlI bGTCajw2R5SPLm/KK2gegbR+LVYzzDZGzFKyBaysYS3FYGSBBQkFCQUJBQkFCQUJBQkFCQUJBQkF CQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQNkCA9uK0R7WVrJ+ykMy6WI8BrW NY0IraB6BtAsdqbMHtttYxkvKFKxhCs4JpCtExKFMy5W5jWX22NgRAitoHoG0SsBsePZZFhSSkuw peFm5dhi3qRKYk1BbAjoraB6BtCcl/8ASYtUBjCkL8Lwp2fS3WCxpVDA/wA5lFbQPQNoShGNLbif CcM3+roX9VQz4ZFbQPQNoSLP0t7P04e5uql5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW 0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5F bQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnk VtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqe RW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp 5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6q nkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubq qeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5u qp5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m 6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5FbQPQNoSLlvb+nD3N1UvIraB6BtCTN8Jbj /ScM3+rob9VQ36ZFbQPQNoTUx/xGtcdjSlb9ZwsRvwt1jMYVRR/+5hFbQPQNokZinmbPOsaWVjsM XhZuOwpbxOsYWcjtjzCK2gegbQLDdv8ANtuuDGsgTJTMYZjeCaZjBHmSlZcbgxjL9dGxDBFbQPQN oDGtK2z31pBJXYrWQLmVrCz5Whk8QVpBWkFaQVpBWkFaQVpBWkFaQVpBWkFaQVpBWkFaQVpBWkFa QVpBWkFaQVpBWkFaQVpBWkFaQVpBWkDZ4gNPkYI9zKxk7dysZdr80zTGaZoRW0D0DaPzK3Oalmyy oYwEVEv8yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGV S4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXB1RL/JlUMMyauU1Mt/KK2gegbRxaK2jj/wD/ 2gAIAQICBj8AG3//2gAIAQMCBj8AG3//2gAIAQEBBj8Ar2djdfxW7G01az+Ok74VzEcvF7FWJ73Z o+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+ M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M9 7s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s 0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+Ms7O7u/5Leq5yVGfx0m/KIxzotYixTC5kpbbfsfFJir 9/0EWo74+5qHH8y/3IO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1U g7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1U4fmT+5803fP3Kn+D4qsVP v+n2LCd22/C5kpbbcUqVkX4+jf8AIiI34QTgQIECBAgQIECBAgQIECBAgQIECBAgQIECBAgQIEBe AqK1FRfuFqUE/SkWf4PhY4WE7tt+FzJS224JWqJw+f0ov/YnATgcMi4i8BeAtdifpX9yf+4WE7tt +FzJS22jKSfVeP4DUROCCcMmXgORU4KPpL/qvD8CwndtvwuZKW20dUVIcEE4Hxkyi8BHon7uC/2L Cd22/C5kpbbT5/8AoTKFG/iWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttp zKJlCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+Fz JS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzKJlCjZiwndtvwuZKW205lEyhRsxYTu 234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFG zFhO7bfhcyUttpzKJlCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZ RMoUbMWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzKJlCjZiwndtvwuZK W205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+FzJS22nMomUKNmLCd22 /C5kpbbTmUTKFGzFhO7bfhcyUttpzKJlCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2Y sJ3bb8LmSlttOZRMoUbMWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzKJ lCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+FzJS2 2nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzCZQo38SwndtvwuZKW20dTVfvQQ+cmUXiI xFhxUsJ3bb8LmSlttGVPp8/C/go1fkTjky8RyqsB9T6KvD8CwndtvwuZKW23BKNR3wqftX+qCcRO JwyLiLxF4i0Ka8V/cuFhO7bfhcyUttuCKi/CpBRtOs74cnBF/qJ+oiRIkSJEiRIkSJEiRIkSJEiR IkSJEiRIkSJEiRIkReIv6hadFfl31d9EFc5flViuFhO7bfhcyUttv2ERrvzNT/VT4qIrf+TqIdVD qodVDqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTq pqdVNTqpqdVNTqpqdVDqodVDqC/xorl0F/O74av+qfYsJ3bb8LmSlttyywndtvzD/9k=" + transform="matrix(0.24 0 0 0.24 182.5615 150.499)" + id="image56"></image></g></mask><g + opacity="0.35" + mask="url(#SVGID_3_)" + a:adobe-opacity-share="1" + id="g58"><path + a:adobe-opacity-share="0" + d="M184.562,236.826c0,5.965,4.835,10.8,10.8,10.8h59.663 c5.964,0,10.8-4.835,10.8-10.8v-73.527c0-5.964-4.835-10.8-10.8-10.8h-59.663c-5.964,0-10.8,4.835-10.8,10.8V236.826z" + id="path60" + fill="#1D2915" /></g></g><linearGradient + id="SVGID_4_" + gradientUnits="userSpaceOnUse" + x1="226.1924" + y1="159.7139" + x2="226.1924" + y2="200"><stop + offset="0.0123" + style="stop-color:#FFFFFF" + id="stop63" /><stop + offset="0.3788" + style="stop-color:#F8FBF3" + id="stop65" /><stop + offset="1" + style="stop-color:#F2F7E8" + id="stop67" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="0.4383" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="1" + style="stop-color:#F2F7E8" /></linearGradient><polygon + fill="url(#SVGID_4_)" + points="221.189,159.714 214.142,180.951 224.048,180.951 214.142,200 238.243,173.61 227.655,173.61 236.978,159.714 " + id="polygon69" /><g + id="g71"><g + id="g73"><g + id="g75"><image + overflow="visible" + opacity="0.75" + a:adobe-blending-mode="multiply" + a:adobe-opacity-share="1" + width="392" + height="242" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYwAAAD2CAYAAADF97BZAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAHohJREFUeNrsnYlu40gSBZMU5Z75 /4+dbUsiFwtY2JrqvIqHSEoRACFZPtqk3BV8WVcvAAAACXouAQAAIAwAAEAYAADwWgYuwSp0XAKA wzJxCRAGIgCANf8fIxaE8RIxIBaA8yeMDokgjLkNfLfyzwOAfWTRNX49EkEY5h9N6+sIAuC8/++n mXKZjJ/5UfIYPuyPRXut9WOEAXDuxOGJYEqKZPpEebyjMOYKoTO+BmEAfIYwSjG0JJFaHm8rjncS RkYE2uutwkAgAO8liezzTPqY3jl1vIMwooa+fi0SRvQzshIBgHMKYwpez5Su3jJ1nFUYLWWlznne KpHW5AEAx5fF5Aijfi0jDy91nFocZxRGJgnUMvDkkf3arDiQCMD+YshIwxKE93xy5CGJ1HFqcZxJ GEsE4b0WHa3JA2EAHEcYU8PjlJREdESp47TiOIMwIlG0yqEPPl4iDmQBcCxpZMtOmWNs+Fy2n6M7 kzSOLIy5oogk0SsfZwWCNADeSxhZMYzGYy2I8uslIY5TpY2jCiMzsikjCO2xDz4fiaNFGggDYD9h LJGF9uh9rq8+7hxxWLI4vDiOJozsKCdPFJoc5ry2JG0gDYDzJouxOrTXLJHUsuiKz4uROurS1GHL VEcShpcqNGFoZSZLBBfla6zXO0MeGXGQMgCOkyyyopgCMfzveDifs44yRdQlLKtEdei0cRRhaLKI UkXZoFtCeH7uUn3dJfF9UV8HwgA4tzDG6nktjYfy/OF8zhJLZ0hjEns01SHTxt7C8EpQmdKTlhQu lSguxmu1TLSfNac8hTQAji+MMZEsahHUx6g8743v1aQxOudzSGnsKYyoBOUlCk0StQQGRRrW4aUO bWRVpj8DYQDsI4xaFJEwPFk8FGHcDYGUR1/Jon7uzf84bIlqL2FkS1BWP8XFSRKDIozBEclgiMPq CJ8rDSQCsI0cWmWRTRaWDO7BYy2OXhFH2SE+BudymLSxhzAsWbSkCk8S3vNBkUdGGJE06pTUIgTE AbCOKLRylCYNqxyVTRV347gYX9sr4nhUotDKVPXw292l8WphtMrCSxWeEOrjqghDE0hUlrKkYaUL ZACwj1S8lBGli1oYWpL433Eznl8qWdxFL2trfRsiev/GIaTxSmFkJ99po5+0RBHJoXy8Bt+j9WmU /743qU/E7vxGGgD7JBBrCRCvs9sqRd2NZHErRDEY4iiTxV1p72ppiPx/IqDVr7GbNF4ljBZZaKnC E0UtBu3jq5E0PGFcgpJUH8gCcQDsJworXWQTRiSMWyWM5/Oheu3ZltzFLmk/lPbhkCOoXiEMreHM 9FVYsrhWz8vjS3lNE8dglKiyHd9ewqAsBbB/KcoThjbvwhpCG6WL8vgu2pRb0XbdnGpFKY26vbCG 3u4mja2Fkemz8EpQZWOulZq+gkdNIlFZaq4wBGkAHFYWIm2d3lG6uFeiKNPFt9Ku3ESfEOyJY3TS xi7S2FIYc2ThpQpLFF/Bx6U4auFckiWpFlkgCoBjiCPb8T01Jow6WVx/JHEtZPEt+oCaaD6XRUYa b1OSapXFEJSdsodVporKUZlRUpEsEAbAcaWhpYx6WK02lPamSKOWxVBIo1UY3QJpbC6PrYTROhLK SxW1LH5VUvhlvG5JQ0sXWv/FReYNp0UaAPvKYq4wxoQwvIQRlbojYayRNDaVxhbCaFmKXJNFPcrp q5LFL0UUGWlE6UJ7Y7MT9hAGwDmFEaUMb/5F3X/hjb70hulnZVFL4/Sd3l2iLNUHsrBKUL+M48v4 2EoX0ZvqlaIEYQCcWhalNKwNkrz5GPeftuRWtCk30ed8aUsYzU0WdZoo25ZaHJsJZMuSVMs8i6iv opbEX4FAnt+jdXZnZaEtby6IAuBtUsac/oxaGoPy6A2mWZoupiJldK8uTa0pjLmlKK2DOxLFX8br WllKG5Lbsn4UO+0BII1B/uzLqG9Av+XPKQHZNsU7H22IcF2e0qRx2ISRkYU1g3sISlB/KY9/OUlD 67vIyOKSKEO1JAzEAbCfKFqF4c0CL1PGUKSNm9hr1LXchHYJWYjoy4RYZSnZQhxbz8OIRDEYwvhl SOIvQxh/KenC6+hu7eSOpIEwAM4hjCXSuBRp47lW1F1p16wtoFvShSYLa++MUV7Un7GGMFpKUV66 qPssaln8bUijFoY1u9vbOGnp8NkucX0A4LWyEGmbCT6KvnzIWMjiUcgjsyGbdQOa+V0nyW/p2r2i NLVmSWqJLLR0Ycnib6ck5U3S85JFy8KCSzq5kQfA9pJokUX52AdJo6/EkVmwdM6ci2nG0TmyWE0c S4URDaPN9ltkZPG3U5bS5l1kFhecu2w55SeAfcl0FncJgXh9G30hivqxXIE2Gl3ZO6KIymPZo0xI m/VjrFWSmjsqanBkYfVd/K2kC6uj25JFZ7yxraJAEADHF8pUvTYFjbZUd+5T0UY8hfEQfapAZnRl lCpG0eeHaB/XKcOS5CriGFZ6Qyx5aPMuhiBZ/FJkoaUMTRblMNpoFvfS3fOQBcB55DEp/3e9DuJa GE9ZWO1bpvRkNeZWp7u1Z0emNDUp579YGsOCNyBKF9HIqEFp7K1U4Q2lteZcWOu4tM6xoAQF8H7S EKN0Uz9qd/B90Xh3ku+r6IxUMTpHuWWsdvRGacrr09g9YWTnW7RM0rPKU9oyIN7CgpYs1twxD3EA HJcp+f9UuxPvFGnMFUUXpANLGJ5Qyu+t/+1Ddnp3iXKUNu/iy0gYvyQ/Qa8cGaUt+5FJFiJtI5+Q A8D50kVGIpNy0zgtkIYY/0b5PLOnuHZcqpTRK0nIK0+9TBjZLVfnzOrOJI0vQxbafAuvzyJbfmK4 LMB7JAzv/+zU8H+9lEZL2zApopgMcURHVJrqRO+72a0Pw0oX0YZIVsKIylDWkuVav0UpK2upj7mi QA4A504YnkCmoLpQfm/r3hbWarmRHJ5rV3kpwytNaalqljiGhRc+U4qKNkb6ctJFnSa0uRaaLC7J ZEEZCgCBRCOoLHFMxd19JuVEndyeMLIpo98yZcwtSWWXL5/bf/El9kioL7H3tYhmW1rpYm4pCgDe RyCt4pCigRaxZ297w2fHIFWU6aJ8HOTf61uVbd5mKWOYcVFb08Wc/bm1RQTrVFH3WViy6INUgSgA oEUcWn9HL7kFEOtS1BiIojy+5P97cdSlqUfVDnspYzZLh9Vq+3Rn5mBcE6KwtlgtReEli16YiAcA 64vDayt65XszQ2ejhFFu3FTuxfFQksYo+kitXfowOrFHSnmlqGgLVi9daEt9ZCbmibAzHgBsK46u kIFUlY3pp416CmNIlqNulShuRVtYbuB0r26aR6MsNYm/d8aqwpi7DEhm74urU36K9rTQ1p23Fg9E FgCwpjjqmeFdlTK8ctS1eNT2DP+qZPFVSOMm+grcUV/G4s7v1j6MOcuYe3MwNGl8KV8b7cFd/w4i /pR8RAEAc8QRSUOqlPH8+jpljEVJqZbGl5Iq6qPc7e9eScPry5AlKWONeRjeUNpLUI7SEsUg9sxt bwZ3L/RVAMBr04bXCT5Wpam6XF+WpK7y7z6Ka5EqynQxiL2DaC/xaKnNJ+5Fayi1jpQagtKTNXN7 SKSLaClhZAEAa6cNSxrlXX5fpYyxaNdqadyVdnBuyli187ufeaG0foJMyhgMMdSlp0wZykoXIu3b qAIAzE0b2nNtBGl2YdbBaRsHJ2W0rMg9q23sGy5My2S9PnExhsTFyG6BmHkDAQBeLRFNGpeqNOXt RJppG7Wb6i6Qxiz6hpP3RNIHCSNj0swF6WaUopAFALwyZWRvri1xXIL2sWVqQbR67qrCaEkaLUNr 6wtxCWRh7ZVryQFJAMAe0ojazWe7dWlsI6/JhKG1l6KUoma1lf3Ci2RdiGyyuIg+CspbRLA3TD7n jQQA2EIe0Y21Nw1hUB6z0sgkDC8dLRZGNlVkR0hZpSdLFpfkBVhkTgCADVJGZoM5qyLjyaN1o7hV +jH6mTHL2gcjugjWBfHKUN1WJw8AsFG6iGSRLeNn2spoFOlqbWXfeDG6IHK1ysI76cyOeaQLADhr maqfIY2L5Pt5rQ7vzYfVZspUfXC0CsLq5LbGEgMAnC1laP0Z1giqls7ubBl/k07vaOiYtp6TdjKa JKJJJ9n5FqQLADhj2vCG20Y33NlSVNfwu62SMLqkNb2E0SviyMzgXrUOBwDw4pThrY6R6QPOVmo2 7fvNTNzrgs9F9bhIHH3ihC07C+kCAE4mE00ctUCiakymhN+vfZPdz4gm2fHFXSALK0V409pFWPID AM6XNrwUklnANSpZzRlS29x+zllLqiVpZBKHNwoqE6OQBgAcXRTeIoCd0x564siW8K2RUs0MMy9E 9tBOwNv4KFtjQxwA8C5C8drOLlmlya4h5a21Fy513q948llbdo48okglQn8FAJxLCt68Ma1Bt9pD 7fW1O7q7LYQRxausLaPaGivPAsC7yyTbZnZiTznIyENk4UipfuZJtp68VXLyxJGZoEfaAIAzSaJl TtuaCWOVdrJ18UHrJCNZRFErU3ZCCgDwjglDa+u6GQkjszjr5sLIJI2oA8dLGtKYMBAHAJxVDJ4s Mmv1ZWURlaNeKgxJnmBmT9kueZFFKEEBwGdJJjui9CU7j/YrnJTX6Gcn3m1SbwMAOEnyyDT4SxNF tGrtLGF4nc3euN7MbMKsGDIlKMQCAO8kjeyNdIs0Vm0vt+jDiGQS2TVbtgIAOKMkoopMa5uaEc4q 9C+8EF4UmyMpAIB3Tx4tfcGb32T3G52sVzN7iQkBAA4ogJYbbetjbxe9zFp8s8v8/Y4XCQAAkeiN uwSJQiQ3qbn1Jn/zhNHNuDCR5RAKAHyKLDKfjxJG9t/YpdNbpH1/7ZY4BgDw6TKJSvWtW0Espt/g ROes/eQtxYtQAAAOsJFc/6KTmxPJAADAF8RL29F+5xMHAEAGfz5fvHfFFu1tf8ILCgDwbrLIrAi+ xs/+CGEAACCX/FpTm9x4IwwAgPMkka2+/jDCoJwEAPAGbSoJAwDgwxr+owuDlAEAcHJIGAAAgDAA AD6At5jpDQAAJAwAAPikdIEwAAAAYQAAAMIAAACEAQAACAMAABAGAAAgDAAAAIQBAAAIAwAAEAYA ACAMAABAGAAAgDAAAABhAAAAIAwAAEAYAACAMAAAAGEAAADCAAAAhAEAAAgDAAAAYQAAAMIAAACE AQAACAMAABAGAAAgDAAAQBgAAAAIAwAAEAYAACAMAABAGAAAgDAAAABhAAAAwgAAAEAYAACAMAAA AGEAAADCAAAAhAEAAAgDAAAQBgAAAMIAAACEAQDwMUwIAwAASBgAAHDOlIEwAADgUMKYuNQAAOdu F0kYAABwGGGQLgAA1mtHd2tTSRgAAOeThvX58vhYYZBSAOBTJDAl0sXU0EauJhESBgDA/tKoG/U1 GvnVk0a/08UhNQAArJtENqff4KQydbTpyBcFAODA0titA7xf+MtPM09YuwDT1nEKAOCEaSLqw5he 1Wb2K51c5hedErYkUQDAJ0ohalen4KZ9esXN9h4zvefIBQDgE6QxSVyJmSRXllq9xN9vdBEiM2ai FwDAp0hjMm6sWxKGN9oqandTbW+/0clnkkXr8DFkAgBnl8KcG+dJ/AFFU9DGZqUQ3uT3G1yUKGJ5 1pyEkVIA8BkCySSOKHVMiTZ2tfazn3liU/IEopPPXBhkAQDvKIu5N9JTcGx2o903xpLopDIXyJNB JIgp+XsCAJxBHNkb6czN+ZT8Ppl7Q96vcNItJxHZUoKTRBAA8K4CiYbIPp+PDW1t5qb+ZcKQwIxZ C3oJA2kAwLumi0w7OiqSGKWtI3yV9rNPntyc2KQdkRk9cQAAvIscJidZWG3mqHy89IZ804SR6Zix RDFWJzlK23Axz4zIBQDOJBCRuDQ/OqLItKOrDx5asw/DkoRmxFH5mlH8OhzDbQHg3WQRtZuZhDE6 clky9201YURlqDFIGGODGT0rAwCcVRxRKX9MtJ8tJarF7WffcIJZY3mmtKJVFK+s+AYAcBYxRJ+L Sk5jcMzp12iq2myVMFpO0CpXtdoRgQDAGSQSdW5bCePRII1R8h3tL1lLaq4kyhN/SNwhHtkaUQDA UdOFVRXxkoUmh0fQfmZK/SILy/t94mS9dUsiI3on6J209jNF4o5w5AEAZxFHNM/iURxLZbFKGT+7 ltSUSBjRCKjoRB/BBaQjHADOKAmvKqP1UTyM9jFqQz2BaL/D6sJoPenROdHoKC+EVdfLCAJ5AMCR xJGpzHg32I9EW9pSltosYXiiECNWRXW4R0PUmrOoFgDAEdOFJpEoSTyPe/U4VxpzfvdFCSNKGi1W fF6Au7T1a7SsagsAsHe6EMmVo7yb63tSFF5ZalHq6Gc2utnRUZEkshdgSpw8ogCAI6YLWUEUd+fj pQkj3W6uMXEvEkdWEnfR63abxSsAgBeki7k32Hfj0BJH3W5uMlqqbzh5TyCtUSpzEVpKU6QMADhi uvCE8VBuqj1R3IMb72iY7WLmrlabnXuRsWXGng/xZ4KTMgDgiOlCGiowLdKIOr6jzetm7ZGx1bDa TN/F87glLkhLR44IczQAYL90kZnYbI2EqtvEW4M8Mqt/L2of+4YLEfVfaOb0TvJWXIybcWE8e86Z owEAsJUsrOkGmVLUXZFG1D5mb7BXm4vRz7worQkjEsVNsanVqROtzLjYogAAM2URdXA/GtrIW0Ic L524Nyy4UJm+jEdwEerj+vM4/DxeiuN/P6P7kdz487z7ed4rF6P7ea0rfueOv3EA2KAMJZLbEygr iqjNbE0X2u/YfEM9JC9MV/3gLlGWsmpz1vH98/uUx70QRl8cXXFIJY5IGoI4AGBFWbR0cFtTDeo2 8ltpH7W+jUyHt7fH92YJY3JEkZFFfVG+fxLFd5EsbkXCGKqEEQmjThmlLOp0QdoAgLVkUYujbrSt AUC3QBLWa9mEYW0V8fKSVH1xygbbGjJWlppuijQG5Yhk0SmJoa+k4EmDtAEAS0RRPnorz1ojoer2 sD40aUQDgzJbts5KGUPDxeoco0bjiy9KuhgUWVyLz1+MhOEJoyt+v1H5Gk0SpA0AyIoiksUYVFse jizqR00ac6YeTMnzWj1haHfpVsdOb0SwoUgadbK4FsmiTBnZhNFVKUNDEwdpAwCyohCZtyzSwyhD 1cdvI2lEKcOTxSpTEJb0YZSNb1mailLGUxpRGWqoRKHJonMa+k7aO8ERBwCiiEShVVesEaLlTbM1 2Oe3IwpLGLdkyvDKaZsnDE0cXSGLTMrISKNMFhdHFpYwpkIWnZM4InEgDwBEYcnCWnVWW+LDE0Ut jUgcmc7uVdeQWiIMcS5iJmXcqpLTt/w5IqpFFlGjXs/b6BrEQeoAQBTRpLxphiwsUXji8EpSWv+F yEqd3XOFMTl34V7KuFelpUtwaGWovlEW5UXqg5SRKU1NhmQA4NyCyIpCjGShDZ3V5lV8B3L4bXzu OyhFeSOkWs5/s4RhDVEt7+QfRUNfSqNMGV6qqKXRBymjlsTFKFPV3zsVH7eUpqagzAUAxxRDNmFk k8XDSBfaCKhaCv/5OTxpRB3eXt/FquvtrdGHUd+p18t2PIqGXytNXZTk4U3Sy7zxtTiespjEHmk1 JctVmWQDAOcSibXQamYDJGvobCmL34njP+L3YWRLUasOpS25zPy+srPZKhFpX+Md3pDZqA+j5Y9k 6UXrFn4eAPZPGNnyU3borCaLm1KG+k+VLLzDG17rSWOTdLFEGCJ+B7IllEgCEryWbaCjWZlrxVlE AXA+cSyRxST6sFlNFjdHFnU5yhPGb0cW1gipTSofwwpvRl3S0dZ+19JEn0waljCiIW7Px6EqS12K z2n9IyL+pEBGTQGcUxaZ5T2iDm5v8yNtUp7VZ/FPQ7Lw9gpqWdJ8t+XNPVlIUhqZklSXSBGj2JNn roU0xh9ZjIU4ns9HRxzWo9dBjlAAjlOGmgJJiCzbz8KSxbfofRSRLH47Zaho7oXIhpvKrTUPo1N+ wbFoOLPSyAgjMw66vJClLMpjlD9HYdXikMSjJocu+SYhFYBlMmhJFa2y0EZCZWRxE33IbC2Hf6rH WhatI6M230RurZKUNcy2FkerNLw33lvw6/mmXos3tlyj6iH6aKw+WRaLZIEgAPYTSKs0rEUEvdFQ 1uZH2qQ8r5/iH4k7uVtGRmlltdVYM2FYb9RYNbgZaXiNq/amWtseatJ4iD9JcKk0WjrnAWB7aXhr QXk3oJP4o6G0mdzakh9WZ/c/Ys/DiFanrTdM8q7BoUpSUWmqbOSz0rB+flSGeiSkcRF7rw1vhrlI bhgx0gDYVxhT0GjWd+FjsmJxF31TuGg2dzSk9rdRjlpj7+7DJYxsaapMG1oDG02Es5ZR90RRvsHP pdOfW79mpZFdUh1hABxfGN5EvKws6r6Let8Kq/8imt3tLWWe2fNis1LUFgnDeyNHpeF8JGThJYxo 8kx5J3AtJHFVUoa1LIkmjH6mMJAFwPbCyHZyjzOqFlay0Pa1aJnR7Y2KinbV82SxujS2Kklpo4Qm RRwtPzsShZUqvooL/0wX9QZN1gq5njhE2kZSIQ2A7WQxNT5qZai6P3SU3G559RIgVsqwEoW1wGA0 jFacEtQpEoYnjXLOQ7bxzAyh9UYtfBXiuMq/d/UbnKShiWOuNJAFwHGkYQnj0ZAublU5yts5L1qy /DuQRVSCispzpyhJlfLwImGLLKw+DC8yluIYKnFo0uiN8hTSAHgfYYwSz+HKlqIyW61qaULbqzsq Q2X7LTaTx7DRm9gF4sjKQpKi8IRx/XkjalnUfRmeNCxhRP0ZCAPgGMLwZDGJP4imlsXdKEdF+3Pf xO+rqDu4DyWLLRNG1J8RScMaAjc69UUrXVyrhOGVpYbGlIEwAM6TLsZkwshULW4N0rgpj9oM7nr4 bKss3qIkNVcaIvl16LWRUc9SVJkwhiphWH0ZLSlj7dngANAuCi1R1M+z6WIUe85FnTK+FWnclBRR J4rspLwWWWwujuGFb3KLNDL9F1Z0/DJKUbUwWstSnjSQBcDxpRHJIprRHaWMmyEIL1FEqSLb0X36 Tu9SFFlpTOKvSZ8dVntVRKEJo+78tvYWvyQSBsIAOFZJKhKG1p6MTtXCGimlPY9E8RB9BvdDkdok L1qN9ggJo0Ua2T0vvIRxlT/7MKwSVDS8NprINzdlIA6AdUQRJYy6HOUtLGi1KZnSlCWSjChaS1C7 yGKPklQkDS1teEnjUr3JQ/H4nKh3q4RxUaRxCRJGZngtHd8Ax0oYmXJUZq+LaB0p77WHxP0UD4nX htqlz2IvYWSkMUnbHhhjII5aCjcjTXjlqOxcjEgaiAJge3FkN0NqmYORKU9ZcmhJFNYM7sPI4tXC mFue0t703hFH+ca2pIkoXWRkkU0ZHogFoK1BbNk9L+rH8OZ5ZYRgPc+Iwis/7S6LPYThSUOTxyh/ 7hNei6N+oy/y7z0v7skk4fVdZIWxRBaIAmC+OLKyyHZ+eyth3wOpRENkWzc/OoQs9hJGNmlMSmNc v+F9lTZ6+fduehdFHPXn+oQoMsIQsffKQAwA24ukRRqZlOF1hkevWf0To1IWkzPIYk9hlCffGc8l SBudkjaejXmdNHrjMRLEnHSBMAD2k4WIP2CmRRqePEbxl/Cw0kRUftp1nsWRhdFaotI6xbW00RWl qmfi0NJDS5pAGADnF4ZIbk0pSxjWx1lJjOL3URwyVRxNGFrasGRRp43668dKFmVD/0gKwtqiNdrn m/kXAPsJQyS3rPmkNN7185bDks00s/R0WFkcSRiiJAxLIJNxh1+nkzFICr3zemY01JzlzZEGwD7C kERpKtv4j4mUUm9L3ZImpqNe+OHAfwzRwoWROLoqcXTiL1MepYmlu+0hCoDXlaZapZFJHlMghslJ FJnf7dCyOKoworSREYcYAukqeWTkQKoAeO+kIQl5eK+PkptDccpUcRZhiPgjqTKd4p2TRGSGIJYI A2kAbC+LrDBE8qOpWo45SWI6y0UfTvbHEZWp6mSSafQzH4vkJ+chDIB9hRHdxWdGKUWL/0Wd2G8l irMJQ5OBKOnDk4bX6GdSw1qLCyINgNcKo0UakUhE5o1yOrUozioMcWTRkjqyKSGbJOjgBjiuSLyG u6V/YU5fxFuI4szC0N6MOaljmiGDTOkJUQAcM31MM59PC37GW4jiXYShiUMkP7JK+16SBMBnp45s w9/6McI48B9GlDrq2eNTQjgIA+D9hLH11yCME6cOCdJHy89AGADnFEbm89PCr0UYb5A6ZIFAsn8o SATguIJo+fppxX8HYZz8D6n75DcfAGE0ff3HtxEDf1ipdNDyh9LxhwVwOmkgB4Sx6h9Kxx8aAGJB GLDmHxb9FwCIAGEAf6gA8Ln0XAIAAEAYAACAMAAAAGEAAADCAACAs/JfAQYAL3iXmIlSiu4AAAAA SUVORK5CYII=" + transform="matrix(0.24 0 0 0.24 179.2061 198.1514)" + id="image77"></image><g + id="g79"><radialGradient + id="SVGID_5_" + cx="225.1929" + cy="226.1387" + r="30.8299" + gradientTransform="matrix(1 0 0 0.75 0 56.5347)" + gradientUnits="userSpaceOnUse"><stop + offset="0.0123" + style="stop-color:#FFFFFF" + id="stop82" /><stop + offset="0.4828" + style="stop-color:#FDFEFB" + id="stop84" /><stop + offset="0.7611" + style="stop-color:#F8FBF3" + id="stop86" /><stop + offset="0.989" + style="stop-color:#F2F8E8" + id="stop88" /><stop + offset="1" + style="stop-color:#F2F7E8" + id="stop90" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="0.8025" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="1" + style="stop-color:#F2F7E8" /></radialGradient><path + fill="url(#SVGID_5_)" + d="M186.706,235.825c0,5.965,4.835,10.801,10.799,10.801h55.374c5.965,0,10.801-4.836,10.801-10.801 v-19.373c0-5.965-4.836-10.801-10.801-10.801h-55.374c-5.964,0-10.799,4.836-10.799,10.801V235.825z" + id="path92" /><path + fill="none" + stroke="#EDF5E5" + stroke-width="5" + stroke-miterlimit="10" + d="M186.706,235.825 c0,5.965,4.835,10.801,10.799,10.801h55.374c5.965,0,10.801-4.836,10.801-10.801v-19.373c0-5.965-4.836-10.801-10.801-10.801 h-55.374c-5.964,0-10.799,4.836-10.799,10.801V235.825z" + id="path94" /></g></g><path + opacity="0.74" + fill="#FFFFFF" + a:adobe-blending-mode="lighten" + d="M263.623,229.595c0.037-0.364,0.057-0.734,0.057-1.107 v-13.375c0-5.965-4.836-10.799-10.801-10.799h-55.374c-5.964,0-10.799,4.834-10.799,10.799v7.324 c7.545-1.012,15.699-1.566,24.213-1.566C231.959,220.87,250.812,224.252,263.623,229.595z" + id="path96" /><linearGradient + id="SVGID_6_" + gradientUnits="userSpaceOnUse" + x1="225.1929" + y1="204.3135" + x2="225.1929" + y2="246.626"><stop + offset="0.0123" + style="stop-color:#FFFFFF;stop-opacity:0" + id="stop99" /><stop + offset="0.0141" + style="stop-color:#FDFDFC;stop-opacity:2.231669e-04" + id="stop101" /><stop + offset="0.1344" + style="stop-color:#BEBEAF;stop-opacity:0.0148" + id="stop103" /><stop + offset="0.2565" + style="stop-color:#94957C;stop-opacity:0.0297" + id="stop105" /><stop + offset="0.3796" + style="stop-color:#747759;stop-opacity:0.0446" + id="stop107" /><stop + offset="0.5029" + style="stop-color:#5D633F;stop-opacity:0.0596" + id="stop109" /><stop + offset="0.6263" + style="stop-color:#4D552E;stop-opacity:0.0746" + id="stop111" /><stop + offset="0.75" + style="stop-color:#414B23;stop-opacity:0.0896" + id="stop113" /><stop + offset="0.8742" + style="stop-color:#3B461E;stop-opacity:0.1047" + id="stop115" /><stop + offset="1" + style="stop-color:#38441C;stop-opacity:0.12" + id="stop117" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF;stop-opacity:0" /><a:midPointStop + offset="0.2901" + style="stop-color:#FFFFFF;stop-opacity:0" /><a:midPointStop + offset="1" + style="stop-color:#38441C;stop-opacity:0.12" /></linearGradient><path + fill="url(#SVGID_6_)" + a:adobe-blending-mode="darken" + d="M263.68,221.954v13.871c0,5.965-4.836,10.801-10.801,10.801 h-55.374c-5.964,0-10.799-4.836-10.799-10.801v-13.871l0.038-7.704c0,0,0.923-9.937,11.173-9.937h54.962 c0,0,10.063,0.328,10.801,10.799V221.954z" + id="path119" /></g><g + id="g121"><g + id="g123"><image + overflow="visible" + opacity="0.25" + a:adobe-blending-mode="multiply" + a:adobe-opacity-share="1" + width="30" + height="30" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAuJJREFUeNrsl9trE0EUxjO7m5vW tKFN1RqLCmqlIvjgkz5I/cOFIqLggw9KsRHxUo1IdEtactG9+A1+A8dxNrsxK/rgwI9lt5ueb875 ZuZspfJ//Bhqjvc0AfCIHClIQEzSMkUoBqyCJbAKWrxXQoBmBL6AQzChmGQREWbmNQY/DS6Aa6AL mtZvdcDPoEcOQEgxUV5mVMYzH5wCZ8FFcJ0CLoN1UHeIGII34AV4BvbBW4qbzsqKctzruq+ALXAL 3ABXwAafNyjS9sQ3cAwG4BXYA0/AU/AejLOE+I4MtME22AH3wE2wyedNivSFQT3eB/y79kwHnGE2 v4IjinCaNrBEtJiBu2SLs686VkRWGRt8/wTL5jFwxIxMbSGB+Ac1qtcluEMBbWslFDV7QBFdlmBE bwxZtthVDn1dpgF3WIIOhakF9iCf2ajQK32W5hcRJgvnmYHb9ECzQAnyhif8o7PxkWImsiQeRSyJ fWCjJAGy5G2usKtgzc6wx5dWxT6wYhm2jKNBm/UcV90m/aLsdLVoonX+QJV8RvmcXNflNVOOKktQ Fz4p+6AMrBg/GUeeFWUHd51HyuXevz7+GRELNSRzjMwYnmhI5Laa/gEBYxEjskVE7Ih67AeOi3ZE BYc55j+xxzjgpBMpImZL1mNDMuDxm5aYBT2x1+wx+vZJ6lt94kl2Ux1uWl4JWZhy9g/AQ/DOPjt8 q0ULuLebhiRYYO8wPUTIdm+X1zDrKE/FKjH95TL3eP83MiIF7FHAY2ZkYpfadxhoRE80WJ66EKIK BE9YAiPgPkW8dPUSFUfDGnMpHVmKvQJCEoofcsamBLs0fOgSUMnomo2QQ66UAbMTi4+hmOk2mGZW B39OE+rgj5iBcNb3h5qxk9boDb1SLrEh2c75+NlnCfT1A4OP8nZiVeAT0IhZY0Ni+gHP8oEpQ59Z HHP2uRtfkeUnxTj7AWHqMU0ZiRVX2ld5kZ4jnSewHN8FGACSOOKkAlOGAAAAAABJRU5ErkJggg==" + transform="matrix(0.24 0 0 0.24 199.0298 216.5547)" + id="image125"></image><g + id="g127"><radialGradient + id="SVGID_7_" + cx="202.6289" + cy="219.7041" + r="2.9995" + gradientTransform="matrix(1 0 0 0.75 0 54.926)" + gradientUnits="userSpaceOnUse"><stop + offset="0.0123" + style="stop-color:#FFFFFF" + id="stop130" /><stop + offset="0.4235" + style="stop-color:#FAFCF6" + id="stop132" /><stop + offset="1" + style="stop-color:#F2F7E8" + id="stop134" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="0.6235" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="1" + style="stop-color:#F2F7E8" /></radialGradient><circle + fill="url(#SVGID_7_)" + cx="202.629" + cy="219.704" + r="2.999" + id="circle136" /></g></g><g + id="g138"><image + overflow="visible" + opacity="0.25" + a:adobe-blending-mode="multiply" + a:adobe-opacity-share="1" + width="30" + height="30" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAtFJREFUeNrsmP1LFEEYx292Ts3V 9ujFrCiwFyPShH4I+imoiPqbhYKIoKigN0W8SulNIrOU63S921u/A9+BYdm9mbndg4IGPiynuzOf eea52WeuVvvf/Joo8VwA6rxm+0lBD3R5TYctpu6XYBRE4DiYzMhpqRbYBDtgHyQ+gsIzQmMUOg3O gzkwzciZTUXqO1gCH8E3CsauERSOUiOgAc6AC2ABXAYXwZECsV/gPVgBb8AH8AVsg45NTjhKTYGr 4Aa4AmYZqYjLmpdj+4ySilwTLIOn4C34YZOTjlLXwH1wC8xzKSMureQym0g+O85ITxP1uU3hPS6r t5j63zFK3QM3uYwNQ0g45KUSPMSJNLjsLS71blHUZJ9Ox5lDSuo2k32SHYsBvslKcAIc5jJvUK7r I1ZntK6Du8yryBJhW9P73hi3jg2ym7ek0hKtO0z4E5xx2RYYOany7DPYyotaUPCwyoVL3KemKpLS TX+h5jhGI88jT0x9/U9yrzoHwoL7ykQtZN8LHGvURUxy05xhntWH8I7WOTzDsaSLmOAMQl6DIYgF mTGEi5iWEyWqD9dtpHCMoPaXtn9KrHSR59CsYxSJ6SKv1e9FW6L1MmM4iXWMIu8ri7u04mjF7HuJ Y3VcxLqciaqfVlnYJRWKJexzlWNs5r2SZMGMNOp1cRYc5atEVBCtPVazD8AzHzHdQUKZUyzywoIT kY9Uh9XrC4o1WTimPmI9ouv9iAXfIHKm1GtKvSyKlq2C1Una5sMTLBRHPN4MOvIxpV6BRfCEJU/s W8Ganf4xzoaCf5dGaS36JHnMKnWNUg/BY35uD1rza7ku5bY4658cMDHkEt6nUZP4TQG1dI/Ic/CJ /SVVHHglS2J94pnluXLecuB9x3Nlk5+3jUlV9hOBMAQjCpn1lMikgFrCdQrtGEKp62CDlCtaMLQc eNu+QmV/7XGp2cyN2rsdCDAAoyXZx8WJpTUAAAAASUVORK5CYII=" + transform="matrix(0.24 0 0 0.24 213.9448 216.5547)" + id="image140"></image><g + id="g142"><radialGradient + id="SVGID_8_" + cx="217.5439" + cy="219.7041" + r="2.9995" + gradientTransform="matrix(1 0 0 0.75 0 54.926)" + gradientUnits="userSpaceOnUse"><stop + offset="0.0123" + style="stop-color:#FFFFFF" + id="stop145" /><stop + offset="0.4235" + style="stop-color:#FAFCF6" + id="stop147" /><stop + offset="1" + style="stop-color:#F2F7E8" + id="stop149" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="0.6235" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="1" + style="stop-color:#F2F7E8" /></radialGradient><circle + fill="url(#SVGID_8_)" + cx="217.544" + cy="219.704" + r="2.999" + id="circle151" /></g></g><g + id="g153"><image + overflow="visible" + opacity="0.25" + a:adobe-blending-mode="multiply" + a:adobe-opacity-share="1" + width="30" + height="30" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAttJREFUeNrsmO9r00Acxptc1m6d Fn9M125sU4RVpyjiSwXB/9wXulciiE4dhpUMpwzFUa02XdP4HDwHR7hcLk0mCh58WOnI9548973k uTYa/0e54c15nQ8E8TJ1UpKQ2Z8QJgUtgDa4CC6AliZOiYrBCfgGfoLTsgK9OQStgE2wDa6DDv+v hhQwBAdgH0TgS1mBLsIEBV0F18BNcJvC1sCyQdgIHFHYG/AODMAxBSZVhQXgHJ15AO5T2Aa4TMHC 0GMJBXwFhxT2Erygkz/AtGhim1NS1A3wCDwGO+AKBS3QKS+nrlp6eQProKe5G4LvNucCS0+1uXQP wRNwj6JaFkH6SgitNxeJ0BwNueSzMsIC3ulduiX/roJmpp9cWkVQ1CrrqB17ws+TPGdM3y3Rftnk fTpVVlS2ZpN1+qy7znl8V2HSrUvcdbKnutryVRk+63RZd5vzBC7ClFvyMXALbHEDiJreNGpDbbH+ Wp5rJmEd7sQ+n13NCq8uU881WbfPeTquwtq0u1ezW1nXepyn7SJM9dgSCc4oPBTO4Rus9jKJwatZ lGeZy+rYXzH+GWEpXxEq5Kl8VecwBcnURVjMgCcZn5GwsTZH7CJMD3khL5zWLGzKuiHnGZpe5CZh I6bO9wx7v+bN7YYxY70j1o/yEoZpKSdMmntMoMq1tIYlVG7ts/4x50tddmXCEDfgxRETZ1JRWMI6 EesObGFRWCyfaa+oDl8jQd4DscApJUr21S54Dj7wu1JBUW2Ct1rybDDRntditUtPnWor8Aw8Zd2h rXdFQdGYd6WfbPTYnOeeEiSv/cTDyC5FvbL1luspSSXPFUYUmaHu8KS0yfjdMpySYp6QIop6TZdC njEnRTvdpVc8Lt0yBW4wS+04HHj3+Fg4pKARnUxdJnVNBL7hSNal4OxPBFLAZ/CRzumn8NR1wrKR xdfy1KLlwDvmw3RaRlDVX3s8h8dGWiUE/BZgAMf82R9IYLF+AAAAAElFTkSuQmCC" + transform="matrix(0.24 0 0 0.24 228.8599 216.5547)" + id="image155"></image><g + id="g157"><radialGradient + id="SVGID_9_" + cx="232.459" + cy="219.7041" + r="2.9995" + gradientTransform="matrix(1 0 0 0.75 0 54.926)" + gradientUnits="userSpaceOnUse"><stop + offset="0.0123" + style="stop-color:#FFFFFF" + id="stop160" /><stop + offset="0.4235" + style="stop-color:#FAFCF6" + id="stop162" /><stop + offset="1" + style="stop-color:#F2F7E8" + id="stop164" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="0.6235" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="1" + style="stop-color:#F2F7E8" /></radialGradient><circle + fill="url(#SVGID_9_)" + cx="232.459" + cy="219.704" + r="2.999" + id="circle166" /></g></g><g + id="g168"><image + overflow="visible" + opacity="0.25" + a:adobe-blending-mode="multiply" + a:adobe-opacity-share="1" + width="30" + height="30" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAt9JREFUeNrsl91rE0EUxTOzm69a 05YmVWsUFdRKRfDBJ32Q+ocLRUTBBx+UYiOitlqRaEos2UT3w3P1jIzrbHZNVuiDAz9CNru5Z+69 M3O2Uvk/fg414zOCDzSxRwJiEJGkTBGKAatgEayCFr8rS4AwAp/BIRhTTDyPCDPzGoOfAhfANdAF zdT/SMBPoEf2wYBiQldmVAEBHjgJzoCL4DoFXAZroO4QMQRvwAvwDOyCtxQ3SWdF5QiQui+DDXAL 3ABXwDqvNygy3RPfwBHog1dgBzwBT8E7ENhCvJwMrIBNsAXugZvgPK83KdKzGlTzu8/fpWc64DSz +RV8oYhfTetPEdFiBu6SDc6+6lgRWZNo8P4Flk0zcMiMSGkSP+MPalQvJbhDASuplVB0RfkU0WUJ RuyNIcsWucoh15bYgFssQYfC1Bz7kcdsVNgrByzNHyJMFs4xA7fZA80CJcgb2uofycYHihlrh4hF ax9YL0mAGT7LKivsKmjLpLXjplVrH1ie0ryzlkWa9SxXnWR5QTv6ocUmWuMDqlLu8Di5ruk1Vzmq LEGdD5QtQln7yI8YespZUXbwzBi6cgzGsRTx14ZkxvFbDJeI9Laa/AMBgRUjTIsI6Yh69ANH0xzR DMMc8x/pMcTwjNIiIlqyHg1Jn8dvUmIWZGKv6THk/Jh4GWqFE3RTHW5auoQsTDj7B+Ah2JOzI8vU RNxQ2pYh8efYO4yHGNDubfNzkHWUJ9YqMf5yiZ7AmyEjtoAdCnjMjIj5TbycBhqxJxosT90SogoE j1kCI+A+Rbw0XmKaxzQlCXjz2GpOXUBITPFDztiUYJsNPzAC8kQklpBDrpQ+sxNZL0MR020wZlaC P2cTSvBHzMAg/f6hCu6qNfaGrJRLNCSbOS8/uyyBfL5n8JFrJy7a7Solpk1DYrynTvWBKcMBsxhw 9nEZL8S2GNtzuJo6YFOG1oor7a28iOdI8gLb47sAAwCDFN6m03jgxgAAAABJRU5ErkJggg==" + transform="matrix(0.24 0 0 0.24 243.7749 216.5547)" + id="image170"></image><g + id="g172"><radialGradient + id="SVGID_10_" + cx="247.374" + cy="219.7041" + r="2.9995" + gradientTransform="matrix(1 0 0 0.75 0 54.926)" + gradientUnits="userSpaceOnUse"><stop + offset="0.0123" + style="stop-color:#FFFFFF" + id="stop175" /><stop + offset="0.4235" + style="stop-color:#FAFCF6" + id="stop177" /><stop + offset="1" + style="stop-color:#F2F7E8" + id="stop179" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="0.6235" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="1" + style="stop-color:#F2F7E8" /></radialGradient><circle + fill="url(#SVGID_10_)" + cx="247.374" + cy="219.704" + r="2.999" + id="circle181" /></g></g><g + id="g183"><image + overflow="visible" + opacity="0.25" + a:adobe-blending-mode="multiply" + a:adobe-opacity-share="1" + width="30" + height="30" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAn9JREFUeNrsl+lrE0EYxvdKjSZW YxEPxBsVrNdHQTxA/KMFBRGPDwoVVIpoq3jUeJUG25qk2fVZ+A28WTabxG4lHzrwgxw78z7zzMw7 73reBDR/jOcCUREhn21LRCy6osfn0kT4BN0h9oiDoiGmTN8Efoum+CHWEBRvRoSbeZXgR8QZcVEc F7syfTcI/kq8Fgviu1jlv3hcET627xXHxFlxWZwXJ8RMxgmPIKkTn8UbMSdeinfiq1hnmUYS4QTs F5fENQSc4rfUgahgT7TFivgk5sVj8VQs4kqukGiAgCviDiKOijr/BUOWL7t/9uGaVyTEighYggsI uI79NQYfdY9FPF8x/WL2xiJLk9hOoelcJehtcYslqI8hYNDGrvP9G5t1PbtRQ+NIg/W/KWaxNNpk DnK5JZ35TzbuCq70ibAu3BBXxWHW1i8hGbpc0+akNLNuBDAtTopz4kBJAuxEC8cPzIlI88BpOoQl Xw1TuDtLsqvZkxbwUA2FjZxEVJYbdROj4mWOpVuzCMoWYGPlxggm4SrfFmFFJOTzDUi2KFY8KIYT sUoSWRadLRDSM0XPMgVPn4guOT0tSN6KVtHd/w8tYWJfqDHeM+m+jBkTeIEaoEmKTUp0oXD80Kjt kU4PkVSqJWTOhIDpFf5APBFLOOPliYhxZgYR00MKmVEEuKWeQ8Q8ruRe5Xb3po7s5CqvDSjnxhVw XzzjFu3k5XTbuuziNYLvZolCk+KHBU8n8QcBL8Rd8VB8yCto8kTEDNBCTIdBg4wQvyD4L6rsdOb3 xKNhhW44IKm4wZaghSAnoIdrHWhz/m3wlOfiI86OXPJPzMvPxLwG/tcX4u3m2l8BBgBQ/dU5d1Za tAAAAABJRU5ErkJggg==" + transform="matrix(0.24 0 0 0.24 199.0298 230.2217)" + id="image185"></image><g + id="g187"><radialGradient + id="SVGID_11_" + cx="202.6289" + cy="233.3711" + r="2.999" + gradientTransform="matrix(1 0 0 0.75 0 58.3428)" + gradientUnits="userSpaceOnUse"><stop + offset="0.0123" + style="stop-color:#FFFFFF" + id="stop190" /><stop + offset="0.4235" + style="stop-color:#FAFCF6" + id="stop192" /><stop + offset="1" + style="stop-color:#F2F7E8" + id="stop194" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="0.6235" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="1" + style="stop-color:#F2F7E8" /></radialGradient><circle + fill="url(#SVGID_11_)" + cx="202.629" + cy="233.37" + r="2.999" + id="circle196" /></g></g><g + id="g198"><image + overflow="visible" + opacity="0.25" + a:adobe-blending-mode="multiply" + a:adobe-opacity-share="1" + width="30" + height="30" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNrsmM9r1EAUx3cz2XW1 il2wLLagIh5aeilUBC967EX/XA/1It5aUaiC2JNY/EWp0lZkG3c3id+Bz0AIaXayibKHDnzIJfPm s29eZl/Sas3paNeYZ0SHaz5OKmIx5pr+azF7fyh6oi+WxXURZGJZiUScim/iWERiUkWwXTFDlxG6 I1bFBnKd3P1jpPbEvviE4JlvBtueUl1xQ9wVa2ITsdtkzOTmxGTsALE34oP4KH6I0TS5tofUJXFT PBCPxToZ67OlZTUWkSmbsffipXglvos/ZXLGI1N2qx6Kp+KRuFcgVYRh/oJYEgNxle08EUNqsbJY SDAnZa8r1FlYoQzc02sFF5n/W/wskzMlAReopydkaoVtDWocL1bqGtv8Bblx0YSgJFt9xNbJXLfG uZctjQEx11gj9M2YDXCFiVviflmAGeQCYtlt/MxTOvbJmEFkFZqSyu9GNr7xEXNP4gbnVK/mFhZl rUdsd0B3fcQCDs3lcw7PJobJrRH4iE37g24qa6VrBK05HRdiTYjVbvI8xtQ1isSyTd4pE5secW6N xEdslGnyDmhd0oazFRF7j7VGPmIxPdQ+HNMWNzUmBfFj3+7C1YDtMG7RT3UaONMS+jErtC1e05tV EksyPdkAyToHbsqW2e51R7ygs42qNooJaU/oPF2TF8wgl2SkdsVz8Y5sJVXFUvryX6TfNXld5HwE U37cWUbqGdfDsto1njVxQjscQ8jc8+SckO25jqipHTK1i+Ro1peR7FM6pKH7StAhC7uam7CQI+J+ J7RNTb0lU7Vf3+b6hXeuPxH8948qF6Pq+CvAAGGezDColMK7AAAAAElFTkSuQmCC" + transform="matrix(0.24 0 0 0.24 213.9448 230.2217)" + id="image200"></image><g + id="g202"><radialGradient + id="SVGID_12_" + cx="217.5439" + cy="233.3711" + r="2.999" + gradientTransform="matrix(1 0 0 0.75 0 58.3428)" + gradientUnits="userSpaceOnUse"><stop + offset="0.0123" + style="stop-color:#FFFFFF" + id="stop205" /><stop + offset="0.4235" + style="stop-color:#FAFCF6" + id="stop207" /><stop + offset="1" + style="stop-color:#F2F7E8" + id="stop209" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="0.6235" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="1" + style="stop-color:#F2F7E8" /></radialGradient><circle + fill="url(#SVGID_12_)" + cx="217.544" + cy="233.37" + r="2.999" + id="circle211" /></g></g><g + id="g213"><image + overflow="visible" + opacity="0.25" + a:adobe-blending-mode="multiply" + a:adobe-opacity-share="1" + width="30" + height="30" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlRJREFUeNrsmM9LG0EUx5PdjTTW otDYWmoOQm2M/YGXnrxI/3IvnnoRW7TagocotqjQtLYp5pffgc/CECc7u+uGpuDAB2Y32Tff9+bN 7Jstlaa0lXM+E4gIAsd/BqIHpj+cpLBY0Ix4JBbhwYg4I+SvOIdf4jqrwHIOQUvihXgtVsWCQ9gP 8UV8El/Ft6wCyyl+DxH0XLwUb8UbxD0V1RE7ZtCO+I6oj2JPHIlTBPZ94sqe3yIi0hCb4h1Reibm iOK4HDPRuRJnRO+D2BGHRLSXJC7yRGpeNMV7sYXAeQSFCU6FRHIGB56IGveMI/uIGxu5JGFzTN0W wpqIijIsmpDFYZ55hah4xRpxP7MIM4NWWHEbTGGDKY1ybi8VKyVM/l2wYjtM+S1xrvww9x6KulgX K0QqvOOeGafGCnbrjOPScOtmnPA1Hm7Sr+TcjF2Rq2F3nb4zNVzCZsWyWMOr2XFe5WgB9urYX+ba KywkF1bJh8d4WWSrYLdhbdBhmohVrddNtYApLOUZI0jxgp6EMO8YQWlK272wuwobFlHkeVqqMVzC OlaR15mQMO8Yo8L6VpFnypNL0S1YWBe7h4wTVxneiP0RJ+KzaHE9KEjUAHst7J9wnWoqe7z9TVly QL9bwJQOsXOB3X36vbTVhfHqN16Zh49F2xXujK2PnWPsthhnkLYeiz0ziblrVZ55CkV7Ftrk1Q52 z5NmIkowdsUBIrIqz7SltR2la0vUNhxhP3PNP7RCf4CouPIs4jDS9p2U/svj21QfeKf6E8E/+ahy 37K2GwEGAJb/2mQI89WQAAAAAElFTkSuQmCC" + transform="matrix(0.24 0 0 0.24 228.8599 230.2217)" + id="image215"></image><g + id="g217"><radialGradient + id="SVGID_13_" + cx="232.459" + cy="233.3711" + r="2.999" + gradientTransform="matrix(1 0 0 0.75 0 58.3428)" + gradientUnits="userSpaceOnUse"><stop + offset="0.0123" + style="stop-color:#FFFFFF" + id="stop220" /><stop + offset="0.4235" + style="stop-color:#FAFCF6" + id="stop222" /><stop + offset="1" + style="stop-color:#F2F7E8" + id="stop224" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="0.6235" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="1" + style="stop-color:#F2F7E8" /></radialGradient><circle + fill="url(#SVGID_13_)" + cx="232.459" + cy="233.37" + r="2.999" + id="circle226" /></g></g><g + id="g228"><image + overflow="visible" + opacity="0.25" + a:adobe-blending-mode="multiply" + a:adobe-opacity-share="1" + width="30" + height="30" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnpJREFUeNrsl2lrE1EUhmdLjSZ2 sYgL4lqsYN0+CuIC4o8WFERcPii0YEsQtYpL3cVgW7PMjO+F55ZhmMlMzATyoRceSDKZc957zplz zzjOBCz3P+/xRE34fE6uWESiJ0I+VybCxekeMSMOizkxlbATwx/xRXwXWwiKRhFhd17H+TFxVlwU J8W+lJ0+zlfFmngjvolNrkXDinAJ+6w4IRbFZXFenBLzqUg4ODGR+CheimXxQrwWn8U2aSolwgo4 KC6Jawg4w28mAsGAmuiI3+KDaInH4qlYJyo7QoISAq6IO4g4Lppc8wrSl66fA0TNSQvJE+GRggsI uE74GxgvW8gB/68l7ouojXVSE/s5N9dxelvcIgXNIQTkFXaT718pViMiyjIa8OiZ/N8US4Q0GLEf 2d5iauYHhWtqpu8PiMINcVUcJbduBY3R9poOT4rpJdteRi1Mi9PinDhUkQC7/Cz7aRH2iTB9YIEb /IqPiSmiu0Sza3gZf2qgcC6jEVUVjWbCR83LOR8CqFpAMu07PrxJOMp3ReSJiOnnfYjH5DdK+sgS sUkT+SW6YxASJoYe46OXFtGjp5uB5JVop8/+EVfMxj4xY7w1m/YywtRmGmqhtlNhNMIs+36O2pB2 fYSmUq+gc8ZsyBzhD8QTsWEikyciomjnETFdMMiUEWBTvYyIFlGJ/ILqNRHZy1HeyBnnhhVwXzzj FO06BSHuUcVbON9Piuy7hlvCudnEXwSsiLvioXhnB5oiEREG2ojpYtRLCXEHOP/JlG12fk88yhp0 /RJNxRrbgDaCrICQqHWhw/OfdG54Lt4T2dIj/8S8/EzMa+DYX4h3l13/BBgABM7SO70ZkkMAAAAA SUVORK5CYII=" + transform="matrix(0.24 0 0 0.24 243.7749 230.2217)" + id="image230"></image><g + id="g232"><radialGradient + id="SVGID_14_" + cx="247.374" + cy="233.3711" + r="2.999" + gradientTransform="matrix(1 0 0 0.75 0 58.3428)" + gradientUnits="userSpaceOnUse"><stop + offset="0.0123" + style="stop-color:#FFFFFF" + id="stop235" /><stop + offset="0.4235" + style="stop-color:#FAFCF6" + id="stop237" /><stop + offset="1" + style="stop-color:#F2F7E8" + id="stop239" /><a:midPointStop + offset="0.0123" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="0.6235" + style="stop-color:#FFFFFF" /><a:midPointStop + offset="1" + style="stop-color:#F2F7E8" /></radialGradient><circle + fill="url(#SVGID_14_)" + cx="247.374" + cy="233.37" + r="2.999" + id="circle241" /></g></g></g></g><path + d="m 529.664,248.155 h 18.498 l -2.809,18.064 h 5.59 37.586 l 2.6,-17.718 c 4.98,-1.091 9.133,-3.455 12.512,-6.693 3.084,4.075 8.566,7.37 18.252,7.37 6.338,0 12.775,-1.807 17.174,-3.687 4.254,2.399 9.463,3.687 15.459,3.687 3.088,0 6.236,-0.355 9.426,-1.023 h 67.135 l 3.354,-24.827 -5.445,-0.764 1.879,-13.356 c 0.371,-2.386 0.449,-4.66 0.449,-6.156 l -0.008,-0.375 c -0.457,-12.191 -8.139,-19.765 -20.045,-19.765 -2.404,0 -4.623,0.314 -6.676,0.852 h -34.189 l -0.035,0.244 c -2.527,-0.701 -5.41,-1.096 -8.686,-1.096 -3.801,0 -7.406,0.555 -10.76,1.598 l 0.105,-0.746 h -12.467 l 1.826,-12.951 H 613.08 l -1.846,7.658 c -1.373,5.704 -2.213,5.793 -4.453,6.03 l -4.508,0.477 c -3.049,-1.424 -6.357,-2.065 -9.602,-2.065 -2.135,0 -4.275,0.284 -6.416,0.852 h -19.291 c 0.502,-1.772 0.775,-3.674 0.775,-5.678 0,-9.601 -6.846,-16.305 -16.646,-16.305 -11.055,0 -18.775,7.721 -18.775,18.776 0,0.951 0.082,1.869 0.219,2.764 -2.135,-0.288 -4.277,-0.409 -5.553,-0.409 -2.053,0 -4.072,0.288 -6.045,0.852 h -31.342 c -2.74,-0.553 -5.641,-0.852 -8.537,-0.852 -7.138,0 -13.492,1.674 -18.808,4.723 l -3.451,-1.461 c -3.711,-1.571 -11.232,-3.262 -18.979,-3.262 -8.933,0 -16.383,2.56 -21.576,7.016 -3.265,-4.473 -8.523,-7.016 -15.228,-7.016 -4.822,0 -9.021,1.477 -12.572,3.44 -2.996,-2.204 -6.796,-3.44 -11.115,-3.44 -2.327,0 -4.48,0.315 -6.476,0.852 h -33.963 l -0.035,0.245 c -2.526,-0.702 -5.41,-1.097 -8.687,-1.097 -20.458,0 -35.307,16.031 -35.307,38.117 0,17.363 10.785,28.149 28.148,28.149 3.087,0 6.236,-0.356 9.426,-1.023 h 88.816 c 3.706,0.676 7.669,1.023 11.154,1.023 8.907,0 16.278,-2.375 21.51,-6.593 4.872,4.252 11.585,6.593 19.728,6.593 3.053,0 6.206,-0.368 9.286,-1.023 h 44.664 2.069 z" + id="path243" + inkscape:connector-curvature="0" + style="fill:#f5f5f5" /><g + id="g245" + transform="translate(0,16)"><g + id="g247"><path + d="m 340.308,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.095,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z" + id="path249" + inkscape:connector-curvature="0" + style="fill:#383838" /><path + d="m 394.07,221.7 -0.171,-0.255 1.789,-10.055 2.642,-18.063 c 0.512,-3.749 0.341,-5.623 -1.96,-5.623 -2.642,0 -5.794,2.727 -9.372,5.879 l -2.727,19.512 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 -0.852,6.305 h -18.404 l -0.171,-0.341 1.875,-10.82 2.471,-17.212 c 0.512,-3.237 0.682,-5.453 -1.789,-5.453 -3.238,0 -7.413,3.664 -9.714,5.709 l -2.642,19.512 c -0.17,1.363 -0.17,1.534 1.108,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.767,-1.789 l -4.176,-1.534 0.938,-6.476 h 16.871 l -0.938,6.987 0.256,0.085 c 4.43,-3.749 9.116,-7.924 15.592,-7.924 4.687,0 7.839,2.641 8.18,7.753 l 0.256,0.086 c 4.175,-3.664 9.202,-7.839 15.252,-7.839 6.22,0 8.775,3.152 8.946,9.202 0,1.618 -0.171,3.493 -0.426,5.538 l -3.067,21.897 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.175,0.597 -0.852,6.305 H 394.07 z" + id="path251" + inkscape:connector-curvature="0" + style="fill:#383838" /><path + d="m 443.995,190.771 -0.17,-4.431 c 0,-0.682 -0.085,-1.108 -1.022,-1.363 -1.022,-0.256 -2.642,-0.427 -4.771,-0.427 -3.579,0 -6.391,1.108 -6.391,4.09 0,2.727 2.982,3.749 6.731,5.027 6.05,2.045 13.888,4.431 13.888,13.463 0,11.076 -9.372,15.592 -20.193,15.592 -8.009,0 -14.91,-1.959 -16.273,-2.981 l 1.618,-12.355 8.691,0.512 0.255,4.941 c 0,0.597 0.171,1.108 0.938,1.363 1.278,0.427 3.238,0.768 6.05,0.768 4.687,0 7.327,-1.79 7.327,-4.687 0,-3.408 -3.152,-4.175 -8.009,-5.624 -6.135,-1.874 -12.78,-4.26 -12.78,-13.206 0,-10.48 9.116,-14.996 19.597,-14.996 6.646,0 12.866,1.533 15.081,2.471 l -1.704,12.354 -8.863,-0.511 z" + id="path253" + inkscape:connector-curvature="0" + style="fill:#383838" /><path + d="m 489.748,218.548 c -4.175,2.386 -10.395,4.175 -16.444,4.175 -13.036,0 -18.575,-7.583 -18.575,-18.574 0,-18.83 11.588,-27.691 25.988,-27.691 6.475,0 11.843,1.874 14.229,3.578 l -1.874,13.377 -8.691,-0.426 -0.255,-5.794 c 0,-0.597 -0.086,-0.938 -0.597,-1.192 -1.022,-0.427 -2.557,-0.597 -4.175,-0.597 -5.624,0 -11.418,4.601 -11.418,17.382 0,7.839 3.493,10.395 8.436,10.395 4.346,0 8.436,-1.448 11.247,-2.556 l 2.129,7.923 z" + id="path255" + inkscape:connector-curvature="0" + style="fill:#383838" /><path + d="m 491.364,221.7 0.853,-6.39 3.919,-0.512 c 1.193,-0.17 1.363,-0.426 1.534,-1.704 l 3.578,-25.987 c 0.086,-0.938 -0.085,-1.534 -0.852,-1.789 l -4.261,-1.534 0.938,-6.476 h 16.87 l -1.107,7.669 0.256,0.17 c 3.323,-4.771 8.095,-8.69 13.548,-8.69 1.874,0 5.112,0.341 6.561,0.767 l -2.13,15.507 -9.969,-0.341 -0.256,-4.431 c -0.086,-0.767 -0.256,-1.022 -0.938,-1.022 -1.619,0 -4.26,1.96 -6.646,4.431 l -2.981,21.643 c -0.171,1.363 -0.085,1.619 1.192,1.704 l 8.095,0.682 -0.938,6.305 h -27.266 z" + id="path257" + inkscape:connector-curvature="0" + style="fill:#383838" /><path + d="m 536.094,221.7 -0.17,-0.426 2.045,-11.503 3.152,-22.749 c 0.17,-0.938 -0.086,-1.534 -0.853,-1.79 l -4.175,-1.448 0.852,-6.476 h 18.149 l -5.027,35.786 c -0.171,1.363 -0.085,1.534 1.192,1.704 l 4.09,0.597 -0.852,6.305 h -18.403 z m 5.879,-57.598 c 0,-5.453 3.238,-8.775 8.776,-8.775 4.175,0 6.646,2.215 6.646,6.305 0,5.368 -3.322,8.861 -8.861,8.861 -4.176,-0.001 -6.561,-2.387 -6.561,-6.391 z" + id="path259" + inkscape:connector-curvature="0" + style="fill:#383838" /><path + d="m 556.796,239.764 -0.17,-0.341 2.471,-14.229 5.282,-38.087 c 0.171,-1.022 -0.085,-1.534 -0.767,-1.789 l -4.175,-1.534 0.938,-6.476 h 17.041 l -1.022,6.816 0.255,0.085 c 5.027,-4.686 10.311,-7.753 15.678,-7.753 7.328,0 12.44,4.686 12.44,17.041 0,11.758 -4.601,29.225 -20.449,29.225 -5.538,0 -8.605,-2.13 -11.759,-4.345 l -1.874,12.78 c -0.085,0.938 0.085,1.278 1.192,1.363 l 8.606,0.853 -0.938,6.39 h -22.749 z m 17.041,-30.247 c 2.13,1.789 4.942,3.322 8.095,3.322 6.901,0 9.458,-9.713 9.458,-17.211 0,-5.027 -1.193,-8.351 -4.431,-8.351 -3.408,0 -7.754,3.664 -10.821,6.391 l -2.301,15.849 z" + id="path261" + inkscape:connector-curvature="0" + style="fill:#383838" /><path + d="m 635.777,219.4 c -3.749,1.789 -9.458,3.322 -14.229,3.322 -8.521,0 -12.099,-2.981 -12.099,-9.969 0,-1.107 0.085,-2.386 0.256,-3.749 l 3.066,-22.323 c 0.086,-0.512 0.086,-0.853 -0.511,-0.853 h -5.879 l 1.107,-7.839 c 7.242,-0.767 10.906,-4.431 13.122,-13.633 h 7.924 l -1.704,12.1 c -0.085,0.596 -0.085,0.852 0.597,0.852 h 11.758 l -1.193,8.521 h -12.439 l -2.812,20.364 c -0.171,1.107 -0.256,1.96 -0.256,2.727 0,2.982 1.278,4.26 4.942,4.26 2.385,0 4.771,-0.596 6.816,-1.363 l 1.534,7.583 z" + id="path263" + inkscape:connector-curvature="0" + style="fill:#383838" /><path + d="m 671.817,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.094,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z" + id="path265" + inkscape:connector-curvature="0" + style="fill:#383838" /><path + d="m 703.596,221.7 -0.17,-0.255 1.874,-10.396 2.471,-17.723 c 0.512,-3.578 0.341,-5.879 -2.215,-5.879 -3.664,0 -8.18,3.578 -11.077,6.135 l -2.641,19.512 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.768,-1.789 l -4.175,-1.534 0.938,-6.476 h 16.87 l -0.937,6.987 0.255,0.085 c 4.771,-4.09 9.373,-7.924 16.02,-7.924 6.475,0 9.798,3.322 10.054,10.139 0,1.363 -0.085,3.067 -0.341,4.687 l -3.067,21.812 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 L 722,221.7 h -18.404 z" + id="path267" + inkscape:connector-curvature="0" + style="fill:#383838" /></g><g + id="g269"><linearGradient + id="SVGID_15_" + gradientUnits="userSpaceOnUse" + x1="324.1611" + y1="239.7637" + x2="324.1611" + y2="155.3275"><stop + offset="0" + style="stop-color:#000000" + id="stop272" /><stop + offset="1" + style="stop-color:#000000;stop-opacity:0" + id="stop274" /><a:midPointStop + offset="0" + style="stop-color:#000000" /><a:midPointStop + offset="0.6933" + style="stop-color:#000000" /><a:midPointStop + offset="1" + style="stop-color:#000000;stop-opacity:0" /></linearGradient><path + d="m 340.308,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.095,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z" + id="path276" + style="fill:url(#SVGID_15_)" + inkscape:connector-curvature="0" /><linearGradient + id="SVGID_16_" + gradientUnits="userSpaceOnUse" + x1="377.45459" + y1="239.7637" + x2="377.45459" + y2="155.3277"><stop + offset="0" + style="stop-color:#000000" + id="stop279" /><stop + offset="1" + style="stop-color:#000000;stop-opacity:0" + id="stop281" /><a:midPointStop + offset="0" + style="stop-color:#000000" /><a:midPointStop + offset="0.6933" + style="stop-color:#000000" /><a:midPointStop + offset="1" + style="stop-color:#000000;stop-opacity:0" /></linearGradient><path + d="m 394.07,221.7 -0.171,-0.255 1.789,-10.055 2.642,-18.063 c 0.512,-3.749 0.341,-5.623 -1.96,-5.623 -2.642,0 -5.794,2.727 -9.372,5.879 l -2.727,19.512 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 -0.852,6.305 h -18.404 l -0.171,-0.341 1.875,-10.82 2.471,-17.212 c 0.512,-3.237 0.682,-5.453 -1.789,-5.453 -3.238,0 -7.413,3.664 -9.714,5.709 l -2.642,19.512 c -0.17,1.363 -0.17,1.534 1.108,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.767,-1.789 l -4.176,-1.534 0.938,-6.476 h 16.871 l -0.938,6.987 0.256,0.085 c 4.43,-3.749 9.116,-7.924 15.592,-7.924 4.687,0 7.839,2.641 8.18,7.753 l 0.256,0.086 c 4.175,-3.664 9.202,-7.839 15.252,-7.839 6.22,0 8.775,3.152 8.946,9.202 0,1.618 -0.171,3.493 -0.426,5.538 l -3.067,21.897 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.175,0.597 -0.852,6.305 H 394.07 z" + id="path283" + style="fill:url(#SVGID_16_)" + inkscape:connector-curvature="0" /><linearGradient + id="SVGID_17_" + gradientUnits="userSpaceOnUse" + x1="435.17719" + y1="239.7637" + x2="435.17719" + y2="155.3275"><stop + offset="0" + style="stop-color:#000000" + id="stop286" /><stop + offset="1" + style="stop-color:#000000;stop-opacity:0" + id="stop288" /><a:midPointStop + offset="0" + style="stop-color:#000000" /><a:midPointStop + offset="0.6933" + style="stop-color:#000000" /><a:midPointStop + offset="1" + style="stop-color:#000000;stop-opacity:0" /></linearGradient><path + d="m 443.995,190.771 -0.17,-4.431 c 0,-0.682 -0.085,-1.108 -1.022,-1.363 -1.022,-0.256 -2.642,-0.427 -4.771,-0.427 -3.579,0 -6.391,1.108 -6.391,4.09 0,2.727 2.982,3.749 6.731,5.027 6.05,2.045 13.888,4.431 13.888,13.463 0,11.076 -9.372,15.592 -20.193,15.592 -8.009,0 -14.91,-1.959 -16.273,-2.981 l 1.618,-12.355 8.691,0.512 0.255,4.941 c 0,0.597 0.171,1.108 0.938,1.363 1.278,0.427 3.238,0.768 6.05,0.768 4.687,0 7.327,-1.79 7.327,-4.687 0,-3.408 -3.152,-4.175 -8.009,-5.624 -6.135,-1.874 -12.78,-4.26 -12.78,-13.206 0,-10.48 9.116,-14.996 19.597,-14.996 6.646,0 12.866,1.533 15.081,2.471 l -1.704,12.354 -8.863,-0.511 z" + id="path290" + style="fill:url(#SVGID_17_)" + inkscape:connector-curvature="0" /><linearGradient + id="SVGID_18_" + gradientUnits="userSpaceOnUse" + x1="474.83691" + y1="239.7637" + x2="474.83691" + y2="155.3275"><stop + offset="0" + style="stop-color:#000000" + id="stop293" /><stop + offset="1" + style="stop-color:#000000;stop-opacity:0" + id="stop295" /><a:midPointStop + offset="0" + style="stop-color:#000000" /><a:midPointStop + offset="0.6933" + style="stop-color:#000000" /><a:midPointStop + offset="1" + style="stop-color:#000000;stop-opacity:0" /></linearGradient><path + d="m 489.748,218.548 c -4.175,2.386 -10.395,4.175 -16.444,4.175 -13.036,0 -18.575,-7.583 -18.575,-18.574 0,-18.83 11.588,-27.691 25.988,-27.691 6.475,0 11.843,1.874 14.229,3.578 l -1.874,13.377 -8.691,-0.426 -0.255,-5.794 c 0,-0.597 -0.086,-0.938 -0.597,-1.192 -1.022,-0.427 -2.557,-0.597 -4.175,-0.597 -5.624,0 -11.418,4.601 -11.418,17.382 0,7.839 3.493,10.395 8.436,10.395 4.346,0 8.436,-1.448 11.247,-2.556 l 2.129,7.923 z" + id="path297" + style="fill:url(#SVGID_18_)" + inkscape:connector-curvature="0" /><linearGradient + id="SVGID_19_" + gradientUnits="userSpaceOnUse" + x1="512.28223" + y1="239.7637" + x2="512.28223" + y2="155.3277"><stop + offset="0" + style="stop-color:#000000" + id="stop300" /><stop + offset="1" + style="stop-color:#000000;stop-opacity:0" + id="stop302" /><a:midPointStop + offset="0" + style="stop-color:#000000" /><a:midPointStop + offset="0.6933" + style="stop-color:#000000" /><a:midPointStop + offset="1" + style="stop-color:#000000;stop-opacity:0" /></linearGradient><path + d="m 491.364,221.7 0.853,-6.39 3.919,-0.512 c 1.193,-0.17 1.363,-0.426 1.534,-1.704 l 3.578,-25.987 c 0.086,-0.938 -0.085,-1.534 -0.852,-1.789 l -4.261,-1.534 0.938,-6.476 h 16.87 l -1.107,7.669 0.256,0.17 c 3.323,-4.771 8.095,-8.69 13.548,-8.69 1.874,0 5.112,0.341 6.561,0.767 l -2.13,15.507 -9.969,-0.341 -0.256,-4.431 c -0.086,-0.767 -0.256,-1.022 -0.938,-1.022 -1.619,0 -4.26,1.96 -6.646,4.431 l -2.981,21.643 c -0.171,1.363 -0.085,1.619 1.192,1.704 l 8.095,0.682 -0.938,6.305 h -27.266 z" + id="path304" + style="fill:url(#SVGID_19_)" + inkscape:connector-curvature="0" /><linearGradient + id="SVGID_20_" + gradientUnits="userSpaceOnUse" + x1="546.65918" + y1="239.7637" + x2="546.65918" + y2="155.32719"><stop + offset="0" + style="stop-color:#000000" + id="stop307" /><stop + offset="1" + style="stop-color:#000000;stop-opacity:0" + id="stop309" /><a:midPointStop + offset="0" + style="stop-color:#000000" /><a:midPointStop + offset="0.6933" + style="stop-color:#000000" /><a:midPointStop + offset="1" + style="stop-color:#000000;stop-opacity:0" /></linearGradient><path + d="m 536.094,221.7 -0.17,-0.426 2.045,-11.503 3.152,-22.749 c 0.17,-0.938 -0.086,-1.534 -0.853,-1.79 l -4.175,-1.448 0.852,-6.476 h 18.149 l -5.027,35.786 c -0.171,1.363 -0.085,1.534 1.192,1.704 l 4.09,0.597 -0.852,6.305 h -18.403 z m 5.879,-57.598 c 0,-5.453 3.238,-8.775 8.776,-8.775 4.175,0 6.646,2.215 6.646,6.305 0,5.368 -3.322,8.861 -8.861,8.861 -4.176,-0.001 -6.561,-2.387 -6.561,-6.391 z" + id="path311" + style="fill:url(#SVGID_20_)" + inkscape:connector-curvature="0" /><linearGradient + id="SVGID_21_" + gradientUnits="userSpaceOnUse" + x1="580.69629" + y1="239.7637" + x2="580.69629" + y2="155.32719"><stop + offset="0" + style="stop-color:#000000" + id="stop314" /><stop + offset="1" + style="stop-color:#000000;stop-opacity:0" + id="stop316" /><a:midPointStop + offset="0" + style="stop-color:#000000" /><a:midPointStop + offset="0.6933" + style="stop-color:#000000" /><a:midPointStop + offset="1" + style="stop-color:#000000;stop-opacity:0" /></linearGradient><path + d="m 556.796,239.764 -0.17,-0.341 2.471,-14.229 5.282,-38.087 c 0.171,-1.022 -0.085,-1.534 -0.767,-1.789 l -4.175,-1.534 0.938,-6.476 h 17.041 l -1.022,6.816 0.255,0.085 c 5.027,-4.686 10.311,-7.753 15.678,-7.753 7.328,0 12.44,4.686 12.44,17.041 0,11.758 -4.601,29.225 -20.449,29.225 -5.538,0 -8.605,-2.13 -11.759,-4.345 l -1.874,12.78 c -0.085,0.938 0.085,1.278 1.192,1.363 l 8.606,0.853 -0.938,6.39 h -22.749 z m 17.041,-30.247 c 2.13,1.789 4.942,3.322 8.095,3.322 6.901,0 9.458,-9.713 9.458,-17.211 0,-5.027 -1.193,-8.351 -4.431,-8.351 -3.408,0 -7.754,3.664 -10.821,6.391 l -2.301,15.849 z" + id="path318" + style="fill:url(#SVGID_21_)" + inkscape:connector-curvature="0" /><linearGradient + id="SVGID_22_" + gradientUnits="userSpaceOnUse" + x1="622.7832" + y1="239.7637" + x2="622.7832" + y2="155.3268"><stop + offset="0" + style="stop-color:#000000" + id="stop321" /><stop + offset="1" + style="stop-color:#000000;stop-opacity:0" + id="stop323" /><a:midPointStop + offset="0" + style="stop-color:#000000" /><a:midPointStop + offset="0.6933" + style="stop-color:#000000" /><a:midPointStop + offset="1" + style="stop-color:#000000;stop-opacity:0" /></linearGradient><path + d="m 635.777,219.4 c -3.749,1.789 -9.458,3.322 -14.229,3.322 -8.521,0 -12.099,-2.981 -12.099,-9.969 0,-1.107 0.085,-2.386 0.256,-3.749 l 3.066,-22.323 c 0.086,-0.512 0.086,-0.853 -0.511,-0.853 h -5.879 l 1.107,-7.839 c 7.242,-0.767 10.906,-4.431 13.122,-13.633 h 7.924 l -1.704,12.1 c -0.085,0.596 -0.085,0.852 0.597,0.852 h 11.758 l -1.193,8.521 h -12.439 l -2.812,20.364 c -0.171,1.107 -0.256,1.96 -0.256,2.727 0,2.982 1.278,4.26 4.942,4.26 2.385,0 4.771,-0.596 6.816,-1.363 l 1.534,7.583 z" + id="path325" + style="fill:url(#SVGID_22_)" + inkscape:connector-curvature="0" /><linearGradient + id="SVGID_23_" + gradientUnits="userSpaceOnUse" + x1="655.6709" + y1="239.7637" + x2="655.6709" + y2="155.3275"><stop + offset="0" + style="stop-color:#000000" + id="stop328" /><stop + offset="1" + style="stop-color:#000000;stop-opacity:0" + id="stop330" /><a:midPointStop + offset="0" + style="stop-color:#000000" /><a:midPointStop + offset="0.6933" + style="stop-color:#000000" /><a:midPointStop + offset="1" + style="stop-color:#000000;stop-opacity:0" /></linearGradient><path + d="m 671.817,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.094,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z" + id="path332" + style="fill:url(#SVGID_23_)" + inkscape:connector-curvature="0" /><linearGradient + id="SVGID_24_" + gradientUnits="userSpaceOnUse" + x1="697.92969" + y1="239.7637" + x2="697.92969" + y2="155.3277"><stop + offset="0" + style="stop-color:#000000" + id="stop335" /><stop + offset="1" + style="stop-color:#000000;stop-opacity:0" + id="stop337" /><a:midPointStop + offset="0" + style="stop-color:#000000" /><a:midPointStop + offset="0.6933" + style="stop-color:#000000" /><a:midPointStop + offset="1" + style="stop-color:#000000;stop-opacity:0" /></linearGradient><path + d="m 703.596,221.7 -0.17,-0.255 1.874,-10.396 2.471,-17.723 c 0.512,-3.578 0.341,-5.879 -2.215,-5.879 -3.664,0 -8.18,3.578 -11.077,6.135 l -2.641,19.512 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.768,-1.789 l -4.175,-1.534 0.938,-6.476 h 16.87 l -0.937,6.987 0.255,0.085 c 4.771,-4.09 9.373,-7.924 16.02,-7.924 6.475,0 9.798,3.322 10.054,10.139 0,1.363 -0.085,3.067 -0.341,4.687 l -3.067,21.812 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 L 722,221.7 h -18.404 z" + id="path339" + style="fill:url(#SVGID_24_)" + inkscape:connector-curvature="0" /></g></g><g + id="g4141" + transform="matrix(0.81856441,0,0,0.81856441,79.234731,-94.128741)"><g + id="g4143"></g><g + id="g4165"><linearGradient + y2="155.3275" + x2="324.1611" + y1="239.7637" + x1="324.1611" + gradientUnits="userSpaceOnUse" + id="linearGradient4167"><stop + id="stop4169" + style="stop-color:#000000" + offset="0" /><stop + id="stop4171" + style="stop-color:#000000;stop-opacity:0" + offset="1" /><a:midPointStop + style="stop-color:#000000" + offset="0" /><a:midPointStop + style="stop-color:#000000" + offset="0.6933" /><a:midPointStop + style="stop-color:#000000;stop-opacity:0" + offset="1" /></linearGradient><linearGradient + y2="155.3277" + x2="377.45459" + y1="239.7637" + x1="377.45459" + gradientUnits="userSpaceOnUse" + id="linearGradient4175"><stop + id="stop4177" + style="stop-color:#000000" + offset="0" /><stop + id="stop4179" + style="stop-color:#000000;stop-opacity:0" + offset="1" /><a:midPointStop + style="stop-color:#000000" + offset="0" /><a:midPointStop + style="stop-color:#000000" + offset="0.6933" /><a:midPointStop + style="stop-color:#000000;stop-opacity:0" + offset="1" /></linearGradient><linearGradient + y2="155.3275" + x2="435.17719" + y1="239.7637" + x1="435.17719" + gradientUnits="userSpaceOnUse" + id="linearGradient4183"><stop + id="stop4185" + style="stop-color:#000000" + offset="0" /><stop + id="stop4187" + style="stop-color:#000000;stop-opacity:0" + offset="1" /><a:midPointStop + style="stop-color:#000000" + offset="0" /><a:midPointStop + style="stop-color:#000000" + offset="0.6933" /><a:midPointStop + style="stop-color:#000000;stop-opacity:0" + offset="1" /></linearGradient><linearGradient + y2="155.3275" + x2="474.83691" + y1="239.7637" + x1="474.83691" + gradientUnits="userSpaceOnUse" + id="linearGradient4191"><stop + id="stop4193" + style="stop-color:#000000" + offset="0" /><stop + id="stop4195" + style="stop-color:#000000;stop-opacity:0" + offset="1" /><a:midPointStop + style="stop-color:#000000" + offset="0" /><a:midPointStop + style="stop-color:#000000" + offset="0.6933" /><a:midPointStop + style="stop-color:#000000;stop-opacity:0" + offset="1" /></linearGradient><linearGradient + y2="155.3277" + x2="512.28223" + y1="239.7637" + x1="512.28223" + gradientUnits="userSpaceOnUse" + id="linearGradient4199"><stop + id="stop4201" + style="stop-color:#000000" + offset="0" /><stop + id="stop4203" + style="stop-color:#000000;stop-opacity:0" + offset="1" /><a:midPointStop + style="stop-color:#000000" + offset="0" /><a:midPointStop + style="stop-color:#000000" + offset="0.6933" /><a:midPointStop + style="stop-color:#000000;stop-opacity:0" + offset="1" /></linearGradient><linearGradient + y2="155.32719" + x2="546.65918" + y1="239.7637" + x1="546.65918" + gradientUnits="userSpaceOnUse" + id="linearGradient4207"><stop + id="stop4209" + style="stop-color:#000000" + offset="0" /><stop + id="stop4211" + style="stop-color:#000000;stop-opacity:0" + offset="1" /><a:midPointStop + style="stop-color:#000000" + offset="0" /><a:midPointStop + style="stop-color:#000000" + offset="0.6933" /><a:midPointStop + style="stop-color:#000000;stop-opacity:0" + offset="1" /></linearGradient><linearGradient + y2="155.32719" + x2="580.69629" + y1="239.7637" + x1="580.69629" + gradientUnits="userSpaceOnUse" + id="linearGradient4215"><stop + id="stop4217" + style="stop-color:#000000" + offset="0" /><stop + id="stop4219" + style="stop-color:#000000;stop-opacity:0" + offset="1" /><a:midPointStop + style="stop-color:#000000" + offset="0" /><a:midPointStop + style="stop-color:#000000" + offset="0.6933" /><a:midPointStop + style="stop-color:#000000;stop-opacity:0" + offset="1" /></linearGradient><linearGradient + y2="155.3268" + x2="622.7832" + y1="239.7637" + x1="622.7832" + gradientUnits="userSpaceOnUse" + id="linearGradient4223"><stop + id="stop4225" + style="stop-color:#000000" + offset="0" /><stop + id="stop4227" + style="stop-color:#000000;stop-opacity:0" + offset="1" /><a:midPointStop + style="stop-color:#000000" + offset="0" /><a:midPointStop + style="stop-color:#000000" + offset="0.6933" /><a:midPointStop + style="stop-color:#000000;stop-opacity:0" + offset="1" /></linearGradient><linearGradient + y2="155.3275" + x2="655.6709" + y1="239.7637" + x1="655.6709" + gradientUnits="userSpaceOnUse" + id="linearGradient4231"><stop + id="stop4233" + style="stop-color:#000000" + offset="0" /><stop + id="stop4235" + style="stop-color:#000000;stop-opacity:0" + offset="1" /><a:midPointStop + style="stop-color:#000000" + offset="0" /><a:midPointStop + style="stop-color:#000000" + offset="0.6933" /><a:midPointStop + style="stop-color:#000000;stop-opacity:0" + offset="1" /></linearGradient><linearGradient + y2="155.3277" + x2="697.92969" + y1="239.7637" + x1="697.92969" + gradientUnits="userSpaceOnUse" + id="linearGradient4239"><stop + id="stop4241" + style="stop-color:#000000" + offset="0" /><stop + id="stop4243" + style="stop-color:#000000;stop-opacity:0" + offset="1" /><a:midPointStop + style="stop-color:#000000" + offset="0" /><a:midPointStop + style="stop-color:#000000" + offset="0.6933" /><a:midPointStop + style="stop-color:#000000;stop-opacity:0" + offset="1" /></linearGradient></g></g></svg> + </a> + + <div class="spinner" id='spinner'></div> + <div class="emscripten" id="status">Downloading...</div> + +<span id='controls'> + <span><input type="checkbox" id="resize">Resize canvas</span> + <span><input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer </span> + <span><input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked, + document.getElementById('resize').checked)"> + </span> +</span> + + <div class="emscripten"> + <progress value="0" max="100" id="progress" hidden=1></progress> + </div> + + + <div class="emscripten_border"> + <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas> + </div> + <textarea id="output" rows="8"></textarea> + + <script type='text/javascript'> + var statusElement = document.getElementById('status'); + var progressElement = document.getElementById('progress'); + var spinnerElement = document.getElementById('spinner'); + + var Module = { + TOTAL_MEMORY: $GODOTTMEM, + preRun: [], + postRun: [], + print: (function() { + var element = document.getElementById('output'); + if (element) element.value = ''; // clear browser cache + return function(text) { + if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); + // These replacements are necessary if you render to raw HTML + //text = text.replace(/&/g, "&"); + //text = text.replace(/</g, "<"); + //text = text.replace(/>/g, ">"); + //text = text.replace('\n', '<br>', 'g'); + console.log(text); + if (element) { + element.value += text + "\n"; + element.scrollTop = element.scrollHeight; // focus on bottom + } + }; + })(), + printErr: function(text) { + if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); + if (0) { // XXX disabled for safety typeof dump == 'function') { + dump(text + '\n'); // fast, straight to the real console + } else { + console.error(text); + } + }, + canvas: (function() { + var canvas = document.getElementById('canvas'); + + // As a default initial behavior, pop up an alert when webgl context is lost. To make your + // application robust, you may want to override this behavior before shipping! + // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 + canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); + + return canvas; + })(), + setStatus: function(text) { + if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' }; + if (text === Module.setStatus.text) return; + var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); + var now = Date.now(); + if (m && now - Date.now() < 30) return; // if this is a progress update, skip it if too soon + if (m) { + text = m[1]; + progressElement.value = parseInt(m[2])*100; + progressElement.max = parseInt(m[4])*100; + progressElement.hidden = false; + spinnerElement.hidden = false; + } else { + progressElement.value = null; + progressElement.max = null; + progressElement.hidden = true; + if (!text) spinnerElement.style.display = 'none'; + } + statusElement.innerHTML = text; + }, + totalDependencies: 0, + monitorRunDependencies: function(left) { + this.totalDependencies = Math.max(this.totalDependencies, left); + Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); + } + }; + Module.setStatus('Downloading...'); + window.onerror = function(event) { + // TODO: do not warn on ok events like simulating an infinite loop or exitStatus + Module.setStatus('Exception thrown, see JavaScript console'); + spinnerElement.style.display = 'none'; + Module.setStatus = function(text) { + if (text) Module.printErr('[post-exception status] ' + text); + }; + }; + </script> + <script type="text/javascript" src="$GODOTFS"></script> + <script> + + (function() { + var memoryInitializer = '$GODOTMEM'; + if (typeof Module['locateFile'] === 'function') { + memoryInitializer = Module['locateFile'](memoryInitializer); + } else if (Module['memoryInitializerPrefixURL']) { + memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer; + } + var xhr = Module['memoryInitializerRequest'] = new XMLHttpRequest(); + xhr.open('GET', memoryInitializer, true); + xhr.responseType = 'arraybuffer'; + xhr.send(null); + })(); + + var script = document.createElement('script'); + script.src = "$GODOTJS"; + document.body.appendChild(script); + +</script> + </body> +</html> diff --git a/tools/html_fs/filesystem.js b/tools/html_fs/godotfs.js index 93cc30556b..93cc30556b 100644 --- a/tools/html_fs/filesystem.js +++ b/tools/html_fs/godotfs.js diff --git a/version.py b/version.py index c723dd2935..284bda9520 100644 --- a/version.py +++ b/version.py @@ -1,7 +1,8 @@ short_name="godot" name="Godot Engine" -major=1 -minor=1 -status="stable" +major=2 +minor=0 +status="alpha" + |