/*************************************************************************/ /* object_format_binary.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "object_format_binary.h" #include "resource.h" #include "io/resource_loader.h" #include "print_string.h" #include "object_type_db.h" #include "globals.h" #include "os/os.h" #include "version.h" #define print_bl(m_what) #ifdef OLD_SCENE_FORMAT_ENABLED enum { SECTION_RESOURCE=0, SECTION_OBJECT=1, SECTION_META_OBJECT=2, SECTION_PROPERTY=3, SECTION_END=4, //numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization) VARIANT_NIL=1, VARIANT_BOOL=2, VARIANT_INT=3, VARIANT_REAL=4, VARIANT_STRING=5, VARIANT_VECTOR2=10, VARIANT_RECT2=11, VARIANT_VECTOR3=12, VARIANT_PLANE=13, VARIANT_QUAT=14, VARIANT_AABB=15, VARIANT_MATRIX3=16, VARIANT_TRANSFORM=17, VARIANT_MATRIX32=18, VARIANT_COLOR=20, VARIANT_IMAGE=21, VARIANT_NODE_PATH=22, VARIANT_RID=23, VARIANT_OBJECT=24, VARIANT_INPUT_EVENT=25, VARIANT_DICTIONARY=26, VARIANT_ARRAY=30, VARIANT_RAW_ARRAY=31, VARIANT_INT_ARRAY=32, VARIANT_REAL_ARRAY=33, VARIANT_STRING_ARRAY=34, VARIANT_VECTOR3_ARRAY=35, VARIANT_COLOR_ARRAY=36, VARIANT_VECTOR2_ARRAY=37, IMAGE_ENCODING_EMPTY=0, IMAGE_ENCODING_RAW=1, IMAGE_ENCODING_PNG=2, //not yet IMAGE_ENCODING_JPG=3, IMAGE_FORMAT_GRAYSCALE=0, IMAGE_FORMAT_INTENSITY=1, IMAGE_FORMAT_GRAYSCALE_ALPHA=2, IMAGE_FORMAT_RGB=3, IMAGE_FORMAT_RGBA=4, IMAGE_FORMAT_INDEXED=5, IMAGE_FORMAT_INDEXED_ALPHA=6, IMAGE_FORMAT_BC1=7, IMAGE_FORMAT_BC2=8, IMAGE_FORMAT_BC3=9, IMAGE_FORMAT_BC4=10, IMAGE_FORMAT_BC5=11, IMAGE_FORMAT_CUSTOM=12, OBJECT_EMPTY=0, OBJECT_EXTERNAL_RESOURCE=1, OBJECT_INTERNAL_RESOURCE=2, }; void ObjectFormatSaverBinary::_pad_buffer(int p_bytes) { int extra = 4-(p_bytes%4); if (extra<4) { for(int i=0;istore_8(0); //pad to 32 } } void ObjectFormatSaverBinary::write_property(int p_idx,const Variant& p_property) { f->store_32(SECTION_PROPERTY); f->store_32(p_idx); switch(p_property.get_type()) { case Variant::NIL: { f->store_32(VARIANT_NIL); // don't store anything } break; case Variant::BOOL: { f->store_32(VARIANT_BOOL); bool val=p_property; f->store_32(val); } break; case Variant::INT: { f->store_32(VARIANT_INT); int val=p_property; f->store_32(val); } break; case Variant::REAL: { f->store_32(VARIANT_REAL); real_t val=p_property; f->store_real(val); } break; case Variant::STRING: { f->store_32(VARIANT_STRING); String val=p_property; save_unicode_string(val); } break; case Variant::VECTOR2: { f->store_32(VARIANT_VECTOR2); Vector2 val=p_property; f->store_real(val.x); f->store_real(val.y); } break; case Variant::RECT2: { f->store_32(VARIANT_RECT2); Rect2 val=p_property; f->store_real(val.pos.x); f->store_real(val.pos.y); f->store_real(val.size.x); f->store_real(val.size.y); } break; case Variant::VECTOR3: { f->store_32(VARIANT_VECTOR3); Vector3 val=p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); } break; case Variant::PLANE: { f->store_32(VARIANT_PLANE); Plane val=p_property; f->store_real(val.normal.x); f->store_real(val.normal.y); f->store_real(val.normal.z); f->store_real(val.d); } break; case Variant::QUAT: { f->store_32(VARIANT_QUAT); Quat val=p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); f->store_real(val.w); } break; case Variant::_AABB: { f->store_32(VARIANT_AABB); AABB val=p_property; f->store_real(val.pos.x); f->store_real(val.pos.y); f->store_real(val.pos.z); f->store_real(val.size.x); f->store_real(val.size.y); f->store_real(val.size.z); } break; case Variant::MATRIX32: { f->store_32(VARIANT_MATRIX32); Matrix32 val=p_property; f->store_real(val.elements[0].x); f->store_real(val.elements[0].y); f->store_real(val.elements[1].x); f->store_real(val.elements[1].y); f->store_real(val.elements[2].x); f->store_real(val.elements[2].y); } break; case Variant::MATRIX3: { f->store_32(VARIANT_MATRIX3); Matrix3 val=p_property; f->store_real(val.elements[0].x); f->store_real(val.elements[0].y); f->store_real(val.elements[0].z); f->store_real(val.elements[1].x); f->store_real(val.elements[1].y); f->store_real(val.elements[1].z); f->store_real(val.elements[2].x); f->store_real(val.elements[2].y); f->store_real(val.elements[2].z); } break; case Variant::TRANSFORM: { f->store_32(VARIANT_TRANSFORM); Transform val=p_property; f->store_real(val.basis.elements[0].x); f->store_real(val.basis.elements[0].y); f->store_real(val.basis.elements[0].z); f->store_real(val.basis.elements[1].x); f->store_real(val.basis.elements[1].y); f->store_real(val.basis.elements[1].z); f->store_real(val.basis.elements[2].x); f->store_real(val.basis.elements[2].y); f->store_real(val.basis.elements[2].z); f->store_real(val.origin.x); f->store_real(val.origin.y); f->store_real(val.origin.z); } break; case Variant::COLOR: { f->store_32(VARIANT_COLOR); Color val=p_property; f->store_real(val.r); f->store_real(val.g); f->store_real(val.b); f->store_real(val.a); } break; case Variant::IMAGE: { f->store_32(VARIANT_IMAGE); Image val =p_property; if (val.empty()) { f->store_32(IMAGE_ENCODING_EMPTY); break; } f->store_32(IMAGE_ENCODING_RAW); //raw encoding f->store_32(val.get_width()); f->store_32(val.get_height()); f->store_32(val.get_mipmaps()); switch(val.get_format()) { case Image::FORMAT_GRAYSCALE: f->store_32(IMAGE_FORMAT_GRAYSCALE ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255 case Image::FORMAT_INTENSITY: f->store_32(IMAGE_FORMAT_INTENSITY ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255 case Image::FORMAT_GRAYSCALE_ALPHA: f->store_32(IMAGE_FORMAT_GRAYSCALE_ALPHA ); break; ///< two bytes per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255. alpha 0-255 case Image::FORMAT_RGB: f->store_32(IMAGE_FORMAT_RGB ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B case Image::FORMAT_RGBA: f->store_32(IMAGE_FORMAT_RGBA ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B: f->store_32(IMAGE_FORMAT_ ); break; one byte A case Image::FORMAT_INDEXED: f->store_32(IMAGE_FORMAT_INDEXED ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*3 bytes of palette case Image::FORMAT_INDEXED_ALPHA: f->store_32(IMAGE_FORMAT_INDEXED_ALPHA ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*4 bytes of palette (alpha) case Image::FORMAT_BC1: f->store_32(IMAGE_FORMAT_BC1 ); break; // DXT1 case Image::FORMAT_BC2: f->store_32(IMAGE_FORMAT_BC2 ); break; // DXT3 case Image::FORMAT_BC3: f->store_32(IMAGE_FORMAT_BC3 ); break; // DXT5 case Image::FORMAT_BC4: f->store_32(IMAGE_FORMAT_BC4 ); break; // ATI1 case Image::FORMAT_BC5: f->store_32(IMAGE_FORMAT_BC5 ); break; // ATI2 case Image::FORMAT_CUSTOM: f->store_32(IMAGE_FORMAT_CUSTOM ); break; default: {} } int dlen = val.get_data().size(); f->store_32(dlen); DVector::Read r = val.get_data().read(); f->store_buffer(r.ptr(),dlen); _pad_buffer(dlen); } break; case Variant::NODE_PATH: { f->store_32(VARIANT_NODE_PATH); save_unicode_string(p_property); } break; case Variant::_RID: { f->store_32(VARIANT_RID); WARN_PRINT("Can't save RIDs"); RID val = p_property; f->store_32(val.get_id()); } break; case Variant::OBJECT: { f->store_32(VARIANT_OBJECT); RES res = p_property; if (res.is_null()) { f->store_32(OBJECT_EMPTY); return; // don't save it } if (res->get_path().length() && res->get_path().find("::")==-1) { f->store_32(OBJECT_EXTERNAL_RESOURCE); save_unicode_string(res->get_type()); String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); save_unicode_string(path); } else { if (!resource_map.has(res)) { f->store_32(OBJECT_EMPTY); ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); ERR_FAIL(); } f->store_32(OBJECT_INTERNAL_RESOURCE); f->store_32(resource_map[res]); //internal resource } } break; case Variant::INPUT_EVENT: { f->store_32(VARIANT_INPUT_EVENT); WARN_PRINT("Can't save InputEvent (maybe it could..)"); } break; case Variant::DICTIONARY: { f->store_32(VARIANT_DICTIONARY); Dictionary d = p_property; f->store_32(d.size()); List keys; d.get_key_list(&keys); for(List::Element *E=keys.front();E;E=E->next()) { //if (!_check_type(dict[E->get()])) // continue; write_property(0,E->get()); write_property(0,d[E->get()]); } } break; case Variant::ARRAY: { f->store_32(VARIANT_ARRAY); Array a=p_property; f->store_32(a.size()); for(int i=0;istore_32(VARIANT_RAW_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); f->store_buffer(r.ptr(),len); _pad_buffer(len); } break; case Variant::INT_ARRAY: { f->store_32(VARIANT_INT_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_32(r[i]); } break; case Variant::REAL_ARRAY: { f->store_32(VARIANT_REAL_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_real(r[i]); } } break; case Variant::STRING_ARRAY: { f->store_32(VARIANT_STRING_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_32(VARIANT_VECTOR3_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_real(r[i].x); f->store_real(r[i].y); f->store_real(r[i].z); } } break; case Variant::VECTOR2_ARRAY: { f->store_32(VARIANT_VECTOR2_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_real(r[i].x); f->store_real(r[i].y); } } break; case Variant::COLOR_ARRAY: { f->store_32(VARIANT_COLOR_ARRAY); DVector arr = p_property; int len=arr.size(); f->store_32(len); DVector::Read r = arr.read(); for(int i=0;istore_real(r[i].r); f->store_real(r[i].g); f->store_real(r[i].b); f->store_real(r[i].a); } } break; default: { ERR_EXPLAIN("Invalid variant"); ERR_FAIL(); } } } void ObjectFormatSaverBinary::_find_resources(const Variant& p_variant) { switch(p_variant.get_type()) { case Variant::OBJECT: { RES res = p_variant.operator RefPtr(); if (res.is_null()) return; if (!bundle_resources && res->get_path().length() && res->get_path().find("::") == -1 ) return; if (resource_map.has(res)) return; List property_list; res->get_property_list(&property_list); for(List::Element *E=property_list.front();E;E=E->next()) { if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) { _find_resources(res->get(E->get().name)); } } SavedObject *so = memnew( SavedObject ); _save_obj(res.ptr(),so); so->meta=res.get_ref_ptr(); resource_map[ res ] = saved_resources.size(); saved_resources.push_back(so); } break; case Variant::ARRAY: { Array varray=p_variant; int len=varray.size(); for(int i=0;i keys; d.get_key_list(&keys); for(List::Element *E=keys.front();E;E=E->next()) { Variant v = d[E->get()]; _find_resources(v); } } break; default: {} } } Error ObjectFormatSaverBinary::_save_obj(const Object *p_object,SavedObject *so) { if (optimizer.is_valid()) { //use optimizer List props; optimizer->get_property_list(p_object,&props); for(List::Element *E=props.front();E;E=E->next()) { if (skip_editor && String(E->get().name).begins_with("__editor")) continue; _find_resources(E->get().value); SavedObject::SavedProperty sp; sp.name_idx=get_string_index(E->get().name); sp.value=E->get().value; so->properties.push_back(sp); } } else { //use classic way List property_list; p_object->get_property_list( &property_list ); for(List::Element *E=property_list.front();E;E=E->next()) { if (skip_editor && E->get().name.begins_with("__editor")) continue; if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) { SavedObject::SavedProperty sp; sp.name_idx=get_string_index(E->get().name); sp.value = p_object->get(E->get().name); _find_resources(sp.value); so->properties.push_back(sp); } } } return OK; } Error ObjectFormatSaverBinary::save(const Object *p_object,const Variant &p_meta) { ERR_FAIL_COND_V(!f,ERR_UNCONFIGURED); ERR_EXPLAIN("write_object should supply either an object, a meta, or both"); ERR_FAIL_COND_V(!p_object && p_meta.get_type()==Variant::NIL, ERR_INVALID_PARAMETER); SavedObject *so = memnew( SavedObject ); if (p_object) so->type=p_object->get_type(); _find_resources(p_meta); so->meta=p_meta; Error err = _save_obj(p_object,so); ERR_FAIL_COND_V( err, ERR_INVALID_DATA ); saved_objects.push_back(so); return OK; } void ObjectFormatSaverBinary::save_unicode_string(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); } ObjectFormatSaverBinary::ObjectFormatSaverBinary(FileAccess *p_file,const String& p_magic,const String& p_local_path,uint32_t p_flags,const Ref& p_optimizer) { optimizer=p_optimizer; relative_paths=p_flags&ObjectSaver::FLAG_RELATIVE_PATHS; skip_editor=p_flags&ObjectSaver::FLAG_OMIT_EDITOR_PROPERTIES; bundle_resources=p_flags&ObjectSaver::FLAG_BUNDLE_RESOURCES; big_endian=p_flags&ObjectSaver::FLAG_SAVE_BIG_ENDIAN; f=p_file; // should be already opened local_path=p_local_path; magic=p_magic; bin_meta_idx = get_string_index("__bin_meta__"); //is often used, so create } int ObjectFormatSaverBinary::get_string_index(const String& p_string) { StringName s=p_string; if (string_map.has(s)) return string_map[s]; string_map[s]=strings.size(); strings.push_back(s); return strings.size()-1; } ObjectFormatSaverBinary::~ObjectFormatSaverBinary() { static const uint8_t header[4]={'O','B','D','B'}; f->store_buffer(header,4); if (big_endian) { f->store_32(1); f->set_endian_swap(true); } else f->store_32(0); f->store_32(0); //64 bits file, false for now f->store_32(VERSION_MAJOR); f->store_32(VERSION_MINOR); save_unicode_string(magic); for(int i=0;i<16;i++) f->store_32(0); // reserved f->store_32(strings.size()); //string table size for(int i=0;imeta; ERR_CONTINUE(!resource_map.has(res)); f->store_32(SECTION_RESOURCE); size_t skip_pos = f->get_pos(); f->store_64(0); // resource skip seek pos save_unicode_string(res->get_type()); if (res->get_path().length() && res->get_path().find("::") == -1 ) save_unicode_string(res->get_path()); else save_unicode_string("local://"+itos(i)); List::Element *SE = so->properties.front(); while(SE) { write_property(SE->get().name_idx,SE->get().value); SE=SE->next(); } f->store_32(SECTION_END); size_t end=f->get_pos(); f->seek(skip_pos); f->store_64(end); f->seek_end(); memdelete( so ); } if (!saved_objects.empty()) { for(List::Element *E=saved_objects.front();E;E=E->next()) { SavedObject *so = E->get(); size_t section_end; if (so->type!="") { f->store_32(SECTION_OBJECT); section_end=f->get_pos(); f->store_64(0); //section end save_unicode_string(so->type); } else { f->store_32(SECTION_META_OBJECT); section_end=f->get_pos(); f->store_64(0); //section end } if (so->meta.get_type()!=Variant::NIL) write_property(bin_meta_idx,so->meta); List::Element *SE = so->properties.front(); while(SE) { write_property(SE->get().name_idx,SE->get().value); SE=SE->next(); } f->store_32(SECTION_END); size_t end=f->get_pos(); f->seek(section_end); f->store_64(end); f->seek_end(); memdelete(so); //no longer needed } } f->store_32(SECTION_END); f->close(); memdelete(f); } ObjectFormatSaver* ObjectFormatSaverInstancerBinary::instance(const String& p_file,const String& p_magic,uint32_t p_flags,const Ref& p_optimizer) { FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE); ERR_FAIL_COND_V( !f, NULL ); String local_path = Globals::get_singleton()->localize_path(p_file); return memnew( ObjectFormatSaverBinary( f, p_magic,local_path,p_flags,p_optimizer ) ); } void ObjectFormatSaverInstancerBinary::get_recognized_extensions(List *p_extensions) const { p_extensions->push_back("bin"); } ObjectFormatSaverInstancerBinary::~ObjectFormatSaverInstancerBinary() { } /************************************************/ /************************************************/ /************************************************/ /************************************************/ /************************************************/ void ObjectFormatLoaderBinary::_advance_padding(uint32_t p_len) { uint32_t extra = 4-(p_len%4); if (extra<4) { for(uint32_t i=0;iget_8(); //pad to 32 } } Error ObjectFormatLoaderBinary::parse_property(Variant& r_v, int &r_index) { uint32_t prop = f->get_32(); if (prop==SECTION_END) return ERR_FILE_EOF; ERR_FAIL_COND_V(prop!=SECTION_PROPERTY,ERR_FILE_CORRUPT); r_index = f->get_32(); uint32_t type = f->get_32(); print_bl("find property of type: "+itos(type)); switch(type) { case VARIANT_NIL: { r_v=Variant(); } break; case VARIANT_BOOL: { r_v=bool(f->get_32()); } break; case VARIANT_INT: { r_v=int(f->get_32()); } break; case VARIANT_REAL: { r_v=f->get_real(); } break; case VARIANT_STRING: { r_v=get_unicode_string(); } break; case VARIANT_VECTOR2: { Vector2 v; v.x=f->get_real(); v.y=f->get_real(); r_v=v; } break; case VARIANT_RECT2: { Rect2 v; v.pos.x=f->get_real(); v.pos.y=f->get_real(); v.size.x=f->get_real(); v.size.y=f->get_real(); r_v=v; } break; case VARIANT_VECTOR3: { Vector3 v; v.x=f->get_real(); v.y=f->get_real(); v.z=f->get_real(); r_v=v; } break; case VARIANT_PLANE: { Plane v; v.normal.x=f->get_real(); v.normal.y=f->get_real(); v.normal.z=f->get_real(); v.d=f->get_real(); r_v=v; } break; case VARIANT_QUAT: { Quat v; v.x=f->get_real(); v.y=f->get_real(); v.z=f->get_real(); v.w=f->get_real(); r_v=v; } break; case VARIANT_AABB: { AABB v; v.pos.x=f->get_real(); v.pos.y=f->get_real(); v.pos.z=f->get_real(); v.size.x=f->get_real(); v.size.y=f->get_real(); v.size.z=f->get_real(); r_v=v; } break; case VARIANT_MATRIX32: { Matrix32 v; v.elements[0].x=f->get_real(); v.elements[0].y=f->get_real(); v.elements[1].x=f->get_real(); v.elements[1].y=f->get_real(); v.elements[2].x=f->get_real(); v.elements[2].y=f->get_real(); r_v=v; } break; case VARIANT_MATRIX3: { Matrix3 v; v.elements[0].x=f->get_real(); v.elements[0].y=f->get_real(); v.elements[0].z=f->get_real(); v.elements[1].x=f->get_real(); v.elements[1].y=f->get_real(); v.elements[1].z=f->get_real(); v.elements[2].x=f->get_real(); v.elements[2].y=f->get_real(); v.elements[2].z=f->get_real(); r_v=v; } break; case VARIANT_TRANSFORM: { Transform v; v.basis.elements[0].x=f->get_real(); v.basis.elements[0].y=f->get_real(); v.basis.elements[0].z=f->get_real(); v.basis.elements[1].x=f->get_real(); v.basis.elements[1].y=f->get_real(); v.basis.elements[1].z=f->get_real(); v.basis.elements[2].x=f->get_real(); v.basis.elements[2].y=f->get_real(); v.basis.elements[2].z=f->get_real(); v.origin.x=f->get_real(); v.origin.y=f->get_real(); v.origin.z=f->get_real(); r_v=v; } break; case VARIANT_COLOR: { Color v; v.r=f->get_real(); v.g=f->get_real(); v.b=f->get_real(); v.a=f->get_real(); r_v=v; } break; case VARIANT_IMAGE: { uint32_t encoding = f->get_32(); if (encoding==IMAGE_ENCODING_EMPTY) { r_v=Variant(); break; } if (encoding==IMAGE_ENCODING_RAW) { uint32_t width = f->get_32(); uint32_t height = f->get_32(); uint32_t mipmaps = f->get_32(); uint32_t format = f->get_32(); Image::Format fmt; switch(format) { case IMAGE_FORMAT_GRAYSCALE: { fmt=Image::FORMAT_GRAYSCALE; } break; case IMAGE_FORMAT_INTENSITY: { fmt=Image::FORMAT_INTENSITY; } break; case IMAGE_FORMAT_GRAYSCALE_ALPHA: { fmt=Image::FORMAT_GRAYSCALE_ALPHA; } break; case IMAGE_FORMAT_RGB: { fmt=Image::FORMAT_RGB; } break; case IMAGE_FORMAT_RGBA: { fmt=Image::FORMAT_RGBA; } break; case IMAGE_FORMAT_INDEXED: { fmt=Image::FORMAT_INDEXED; } break; case IMAGE_FORMAT_INDEXED_ALPHA: { fmt=Image::FORMAT_INDEXED_ALPHA; } break; case IMAGE_FORMAT_BC1: { fmt=Image::FORMAT_BC1; } break; case IMAGE_FORMAT_BC2: { fmt=Image::FORMAT_BC2; } break; case IMAGE_FORMAT_BC3: { fmt=Image::FORMAT_BC3; } break; case IMAGE_FORMAT_BC4: { fmt=Image::FORMAT_BC4; } break; case IMAGE_FORMAT_BC5: { fmt=Image::FORMAT_BC5; } break; case IMAGE_FORMAT_CUSTOM: { fmt=Image::FORMAT_CUSTOM; } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); } } uint32_t datalen = f->get_32(); print_bl("width: "+itos(width)); print_bl("height: "+itos(height)); print_bl("mipmaps: "+itos(mipmaps)); print_bl("format: "+itos(format)); print_bl("datalen: "+itos(datalen)); DVector imgdata; imgdata.resize(datalen); DVector::Write w = imgdata.write(); f->get_buffer(w.ptr(),datalen); _advance_padding(datalen); w=DVector::Write(); r_v=Image(width,height,mipmaps,fmt,imgdata); } } break; case VARIANT_NODE_PATH: { r_v=NodePath(get_unicode_string()); } break; case VARIANT_RID: { r_v=f->get_32(); } break; case VARIANT_OBJECT: { uint32_t type=f->get_32(); switch(type) { case OBJECT_EMPTY: { //do none } break; case OBJECT_INTERNAL_RESOURCE: { uint32_t index=f->get_32(); String path = local_path+"::"+itos(index); RES res = ResourceLoader::load(path); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); } r_v=res; } break; case OBJECT_EXTERNAL_RESOURCE: { String type = get_unicode_string(); String path = get_unicode_string(); 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(local_path.get_base_dir()+"/"+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); } break; } } break; case VARIANT_INPUT_EVENT: { } break; case VARIANT_DICTIONARY: { int len=f->get_32(); Dictionary d; for(int i=0;iget_32(); Array a; a.resize(len); for(int i=0;iget_32(); DVector array; array.resize(len); DVector::Write w = array.write(); f->get_buffer(w.ptr(),len); _advance_padding(len); w=DVector::Write(); r_v=array; } break; case VARIANT_INT_ARRAY: { uint32_t len = f->get_32(); DVector array; array.resize(len); DVector::Write w = array.write(); f->get_buffer((uint8_t*)w.ptr(),len*4); w=DVector::Write(); r_v=array; } break; case VARIANT_REAL_ARRAY: { uint32_t len = f->get_32(); DVector array; array.resize(len); DVector::Write w = array.write(); f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)); w=DVector::Write(); r_v=array; } break; case VARIANT_STRING_ARRAY: { uint32_t len = f->get_32(); DVector array; array.resize(len); DVector::Write w = array.write(); for(int i=0;i::Write(); r_v=array; } break; case VARIANT_VECTOR2_ARRAY: { uint32_t len = f->get_32(); DVector array; array.resize(len); DVector::Write w = array.write(); if (sizeof(Vector2)==8) { f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*2); } else { ERR_EXPLAIN("Vector2 size is NOT 8!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w=DVector::Write(); r_v=array; } break; case VARIANT_VECTOR3_ARRAY: { uint32_t len = f->get_32(); DVector array; array.resize(len); DVector::Write w = array.write(); if (sizeof(Vector3)==12) { f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*3); } else { ERR_EXPLAIN("Vector3 size is NOT 12!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w=DVector::Write(); r_v=array; } break; case VARIANT_COLOR_ARRAY: { uint32_t len = f->get_32(); DVector array; array.resize(len); DVector::Write w = array.write(); if (sizeof(Color)==16) { f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*4); } else { ERR_EXPLAIN("Color size is NOT 16!"); ERR_FAIL_V(ERR_UNAVAILABLE); } w=DVector::Write(); r_v=array; } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); } break; } return OK; //never reach anyway } Error ObjectFormatLoaderBinary::load(Object **p_object,Variant &p_meta) { while(true) { if (f->eof_reached()) { ERR_EXPLAIN("Premature end of file at: "+local_path); ERR_FAIL_V(ERR_FILE_CORRUPT); } RES resource; Object *obj=NULL; bool meta=false; uint32_t section = f->get_32(); switch(section) { case SECTION_RESOURCE: { print_bl("resource found"); size_t section_end = f->get_64(); print_bl("section end: "+itos(section_end)); String type = get_unicode_string(); String path = get_unicode_string(); print_bl("path: "+path); if (path.begins_with("local://")) { //built-in resource (but really external) path=path.replace("local://",local_path+"::"); } if (ResourceCache::has(path)) { f->seek(section_end); continue; } //load properties obj = ObjectTypeDB::instance(type); if (!obj) { ERR_EXPLAIN("Object of unrecognized type '"+type+"' in file: "+type); } ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT); Resource *r = obj->cast_to(); if (!r) { memdelete(obj); //bye ERR_EXPLAIN("Object type in resource field not a resource, type is: "+obj->get_type()); ERR_FAIL_COND_V(!obj->cast_to(),ERR_FILE_CORRUPT); } resource = RES( r ); r->set_path(path); } break; case SECTION_META_OBJECT: meta=true; print_bl("meta found"); case SECTION_OBJECT: { uint64_t section_end = f->get_64(); if (!meta) { print_bl("object"); String type = get_unicode_string(); if (ObjectTypeDB::can_instance(type)) { obj = ObjectTypeDB::instance(type); if (!obj) { ERR_EXPLAIN("Object of unrecognized type in file: "+type); } ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT); } else { f->seek(section_end); return ERR_SKIP; }; } } break; case SECTION_END: { return ERR_FILE_EOF; } break; default: { ERR_EXPLAIN("Invalid Section ID '"+itos(section)+"' in file: "+local_path); ERR_FAIL_V(ERR_FILE_CORRUPT); } } //load properties while(true) { int name_idx; Variant v; Error err; err = parse_property(v,name_idx); print_bl("prop idx "+itos(name_idx)+" value: "+String(v)); if (err==ERR_FILE_EOF) break; if (err!=OK) { ERR_EXPLAIN("File Corrupted"); ERR_FAIL_COND_V(err!=OK,ERR_FILE_CORRUPT); } if (resource.is_null() && name_idx==0) { //0 is __bin_meta__ p_meta=v; continue; } else if (!obj) { ERR_EXPLAIN("Normal property found in meta object."); ERR_FAIL_V(ERR_FILE_CORRUPT); } Map::Element *E=string_map.find(name_idx); if (!E) { ERR_EXPLAIN("Property ID has no matching name: "+itos(name_idx)); ERR_FAIL_V(ERR_FILE_CORRUPT); } obj->set(E->get(),v); } if (!obj) { *p_object=NULL; return OK; // it was a meta object } if (resource.is_null()) { //regular object *p_object=obj; return OK; } else { resource_cache.push_back(resource); //keep it in mem until finished loading } } } ObjectFormatLoaderBinary::~ObjectFormatLoaderBinary() { if (f) { if (f->is_open()) f->close(); memdelete(f); } } String ObjectFormatLoaderBinary::get_unicode_string() { uint32_t len = f->get_32(); if (len>str_buf.size()) { str_buf.resize(len); } f->get_buffer((uint8_t*)&str_buf[0],len); String s; s.parse_utf8(&str_buf[0]); return s; } ObjectFormatLoaderBinary::ObjectFormatLoaderBinary(FileAccess *p_f,bool p_endian_swap,bool p_use64) { f=p_f; endian_swap=p_endian_swap; use_real64=p_use64; //load string table uint32_t string_table_size = f->get_32(); print_bl("string table size: "+itos(string_table_size)); for(int i=0;iget_buffer(header,4); if (header[0]!='O' || header[1]!='B' || header[2]!='D' || header[3]!='B') { ERR_EXPLAIN("File not in valid binary format: "+p_file); ERR_FAIL_V(NULL); } uint32_t big_endian = f->get_32(); #ifdef BIG_ENDIAN_ENABLED bool 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 uint32_t ver_major=f->get_32(); uint32_t ver_minor=f->get_32(); print_bl("big endian: "+itos(big_endian)); print_bl("endian swap: "+itos(endian_swap)); print_bl("real64: "+itos(use_real64)); print_bl("major: "+itos(ver_major)); print_bl("minor: "+itos(ver_minor)); if (ver_major>VERSION_MAJOR || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) { f->close(); memdelete(f); ERR_EXPLAIN("File Format '"+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+p_file); ERR_FAIL_V(NULL); } uint32_t magic_len = f->get_32(); Vector magic; magic.resize(magic_len); f->get_buffer((uint8_t*)&magic[0],magic_len); String magic_str; magic_str.parse_utf8(&magic[0]); print_bl("magic: "+magic_str); if (magic_str!=p_magic) { f->close(); memdelete(f); ERR_EXPLAIN("File magic mismatch, found '"+magic_str+"' in : "+p_file); ERR_FAIL_V(NULL); } print_bl("skipping 32"); for(int i=0;i<16;i++) f->get_32(); //skip a few reserved fields if (f->eof_reached()) { f->close(); memdelete(f); ERR_EXPLAIN("Premature End Of File: "+p_file); ERR_FAIL_V(NULL); } print_bl("creating loader"); ObjectFormatLoaderBinary *loader = memnew( ObjectFormatLoaderBinary(f,endian_swap,use_real64) ); loader->local_path=p_file; return loader; } void ObjectFormatLoaderInstancerBinary::get_recognized_extensions(List *p_extensions) const { p_extensions->push_back("bin"); } #endif