Ref<Texture> EditorResourcePreview::_generate_preview(const QueueItem &p_item, const String &cache_base) { String type; if (p_item.resource.is_valid()) type = p_item.resource->get_class(); else type = ResourceLoader::get_resource_type(p_item.path); if (type == "") return Ref<Texture>(); //could not guess type Ref<Texture> generated; for (int i = 0; i < preview_generators.size(); i++) { if (!preview_generators[i]->handles(type)) continue; if (p_item.resource.is_valid()) { generated = preview_generators[i]->generate(p_item.resource); } else { generated = preview_generators[i]->generate_from_path(p_item.path); } break; } if (!p_item.resource.is_valid()) { // cache the preview in case it's a resource on disk if (generated.is_valid()) { int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); thumbnail_size *= EDSCALE; //wow it generated a preview... save cache ResourceSaver::save(cache_base + ".png", generated); FileAccess *f = FileAccess::open(cache_base + ".txt", FileAccess::WRITE); f->store_line(itos(thumbnail_size)); f->store_line(itos(FileAccess::get_modified_time(p_item.path))); f->store_line(FileAccess::get_md5(p_item.path)); memdelete(f); } else { //print_line("was not generated"); } } return generated; }
void ResourceCache::dump(const char *p_file, bool p_short) { #ifdef DEBUG_ENABLED lock->read_lock(); Map<String, int> type_count; FileAccess *f = NULL; if (p_file) { f = FileAccess::open(p_file, FileAccess::WRITE); ERR_FAIL_COND(!f); } const String *K = NULL; while ((K = resources.next(K))) { Resource *r = resources[*K]; if (!type_count.has(r->get_class())) { type_count[r->get_class()] = 0; } type_count[r->get_class()]++; if (!p_short) { if (f) f->store_line(r->get_class() + ": " + r->get_path()); } } for (Map<String, int>::Element *E = type_count.front(); E; E = E->next()) { if (f) f->store_line(E->key() + " count: " + itos(E->get())); } if (f) { f->close(); memdelete(f); } lock->read_unlock(); #endif }
void CreateDialog::_save_favorite_list() { FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE); if (f) { for (int i = 0; i < favorite_list.size(); i++) { f->store_line(favorite_list[i]); } memdelete(f); } }
void CreateDialog::_save_favorite_list() { FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE); if (f) { for (int i = 0; i < favorite_list.size(); i++) { String l = favorite_list[i]; String name = l.split(" ")[0]; if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) continue; f->store_line(l); } memdelete(f); } }
void EditorResourcePreview::_thread() { while (!exit) { preview_sem->wait(); preview_mutex->lock(); if (queue.size()) { QueueItem item = queue.front()->get(); queue.pop_front(); if (cache.has(item.path)) { //already has it because someone loaded it, just let it know it's ready String path = item.path; if (item.resource.is_valid()) { path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below) } _preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata); preview_mutex->unlock(); } else { preview_mutex->unlock(); Ref<ImageTexture> texture; Ref<ImageTexture> small_texture; int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); thumbnail_size *= EDSCALE; if (item.resource.is_valid()) { _generate_preview(texture, small_texture, item, String()); //adding hash to the end of path (should be ID:<objid>:<hash>) because of 5 argument limit to call_deferred _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata); } else { String temp_path = EditorSettings::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); //does not have it, try to load a cached thumbnail String file = cache_base + ".txt"; FileAccess *f = FileAccess::open(file, FileAccess::READ); if (!f) { // No cache found, generate _generate_preview(texture, small_texture, item, cache_base); } else { uint64_t modtime = FileAccess::get_modified_time(item.path); int tsize = f->get_line().to_int64(); bool has_small_texture = f->get_line().to_int(); uint64_t last_modtime = f->get_line().to_int64(); bool cache_valid = true; if (tsize != thumbnail_size) { cache_valid = false; memdelete(f); } else if (last_modtime != modtime) { String last_md5 = f->get_line(); String md5 = FileAccess::get_md5(item.path); memdelete(f); if (last_md5 != md5) { cache_valid = false; } else { //update modified time f = FileAccess::open(file, FileAccess::WRITE); f->store_line(itos(modtime)); f->store_line(itos(has_small_texture)); f->store_line(md5); memdelete(f); } } else { memdelete(f); } if (cache_valid) { Ref<Image> img; img.instance(); Ref<Image> small_img; small_img.instance(); if (img->load(cache_base + ".png") != OK) { cache_valid = false; } else { texture.instance(); texture->create_from_image(img, Texture::FLAG_FILTER); if (has_small_texture) { if (small_img->load(cache_base + "_small.png") != OK) { cache_valid = false; } else { small_texture.instance(); small_texture->create_from_image(small_img, Texture::FLAG_FILTER); } } } } if (!cache_valid) { _generate_preview(texture, small_texture, item, cache_base); } } _preview_ready(item.path, texture, small_texture, item.id, item.function, item.userdata); } } } else { preview_mutex->unlock(); } } }
void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, const QueueItem &p_item, const String &cache_base) { String type; if (p_item.resource.is_valid()) type = p_item.resource->get_class(); else type = ResourceLoader::get_resource_type(p_item.path); if (type == "") { r_texture = Ref<ImageTexture>(); r_small_texture = Ref<ImageTexture>(); return; //could not guess type } int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); thumbnail_size *= EDSCALE; r_texture = Ref<ImageTexture>(); r_small_texture = Ref<ImageTexture>(); for (int i = 0; i < preview_generators.size(); i++) { if (!preview_generators[i]->handles(type)) continue; Ref<Texture> generated; if (p_item.resource.is_valid()) { generated = preview_generators[i]->generate(p_item.resource, Vector2(thumbnail_size, thumbnail_size)); } else { generated = preview_generators[i]->generate_from_path(p_item.path, Vector2(thumbnail_size, thumbnail_size)); } r_texture = generated; if (r_texture.is_valid() && preview_generators[i]->should_generate_small_preview()) { int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_icon("Object", "EditorIcons")->get_width(); // Kind of a workaround to retreive the default icon size small_thumbnail_size *= EDSCALE; Ref<Image> small_image = r_texture->get_data(); small_image->resize(small_thumbnail_size, small_thumbnail_size, Image::INTERPOLATE_CUBIC); r_small_texture.instance(); r_small_texture->create_from_image(small_image); } break; } if (!p_item.resource.is_valid()) { // cache the preview in case it's a resource on disk if (r_texture.is_valid()) { //wow it generated a preview... save cache bool has_small_texture = r_small_texture.is_valid(); ResourceSaver::save(cache_base + ".png", r_texture); if (has_small_texture) { ResourceSaver::save(cache_base + "_small.png", r_small_texture); } FileAccess *f = FileAccess::open(cache_base + ".txt", FileAccess::WRITE); f->store_line(itos(thumbnail_size)); f->store_line(itos(has_small_texture)); f->store_line(itos(FileAccess::get_modified_time(p_item.path))); f->store_line(FileAccess::get_md5(p_item.path)); memdelete(f); } } }
void ok_pressed() { if (!_test_path()) return; String dir; if (import_mode) { dir=project_path->get_text(); } else { DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (d->change_dir(project_path->get_text())!=OK) { error->set_text("Invalid Path for Project (changed anything?)"); memdelete(d); return; } dir=d->get_current_dir(); memdelete(d); FileAccess *f = FileAccess::open(dir.plus_file("/engine.cfg"),FileAccess::WRITE); if (!f) { error->set_text("Couldn't create engine.cfg in project path"); } else { f->store_line("; Engine configuration file."); f->store_line("; It's best to edit using the editor UI, not directly,"); f->store_line("; becausethe parameters that go here are not obvious."); f->store_line("; "); f->store_line("; Format: "); f->store_line("; [section] ; section goes between []"); f->store_line("; param=value ; assign values to parameters"); f->store_line("\n"); f->store_line("[application]"); f->store_line("name=\""+project_name->get_text()+"\""); f->store_line("icon=\"icon.png\""); memdelete(f); ResourceSaver::save(dir.plus_file("/icon.png"),get_icon("DefaultProjectIcon","EditorIcons")); } } dir=dir.replace("\\","/"); if (dir.ends_with("/")) dir=dir.substr(0,dir.length()-1); String proj=dir.replace("/","::"); EditorSettings::get_singleton()->set("projects/"+proj,dir); EditorSettings::get_singleton()->save(); hide(); emit_signal("project_created"); }
Error ResourceInteractiveLoaderText::rename_dependencies(FileAccess *p_f, const String &p_path,const Map<String,String>& p_map) { open(p_f,true); ERR_FAIL_COND_V(error!=OK,error); ignore_resource_parsing=true; //FileAccess FileAccess *fw = NULL; String base_path=local_path.get_base_dir(); uint64_t tag_end = f->get_pos(); while(true) { Error err = VariantParser::parse_tag(&stream,lines,error_text,next_tag,&rp); if (err!=OK) { if (fw) { memdelete(fw); } error=ERR_FILE_CORRUPT; ERR_FAIL_V(error); } if (next_tag.name!="ext_resource") { //nothing was done if (!fw) return OK; break; } else { if (!fw) { fw=FileAccess::open(p_path+".depren",FileAccess::WRITE); if (is_scene) { fw->store_line("[gd_scene load_steps="+itos(resources_total)+" format="+itos(FORMAT_VERSION)+"]\n"); } else { fw->store_line("[gd_resource type=\""+res_type+"\" load_steps="+itos(resources_total)+" format="+itos(FORMAT_VERSION)+"]\n"); } } if (!next_tag.fields.has("path") || !next_tag.fields.has("id") || !next_tag.fields.has("type")) { memdelete(fw); error=ERR_FILE_CORRUPT; ERR_FAIL_V(error); } String path = next_tag.fields["path"]; int index = next_tag.fields["id"]; String type = next_tag.fields["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); } fw->store_line("[ext_resource path=\""+path+"\" type=\""+type+"\" id="+itos(index)+"]"); tag_end = f->get_pos(); } } f->seek(tag_end); uint8_t c=f->get_8(); while(!f->eof_reached()) { fw->store_8(c); c=f->get_8(); } f->close(); 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; }
Error ResourceInteractiveLoaderText::rename_dependencies(FileAccess *p_f, const String &p_path,const Map<String,String>& p_map) { #if 0 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); //f**k 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<ResourceInteractiveLoaderText> ria = memnew( ResourceInteractiveLoaderText ); 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 ResourceFormatSaverText::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); #endif return OK; }
void EditorFileSystem::_reimport_file(const String &p_file) { print_line("REIMPORTING: " + p_file); EditorFileSystemDirectory *fs = NULL; int cpos = -1; bool found = _find_file(p_file, &fs, cpos); ERR_FAIL_COND(!found); //try to obtain existing params Map<StringName, Variant> params; String importer_name; if (FileAccess::exists(p_file + ".import")) { //use existing Ref<ConfigFile> cf; cf.instance(); Error err = cf->load(p_file + ".import"); if (err == OK) { List<String> sk; cf->get_section_keys("params", &sk); for (List<String>::Element *E = sk.front(); E; E = E->next()) { params[E->get()] = cf->get_value("params", E->get()); } importer_name = cf->get_value("remap", "importer"); } } else { late_added_files.insert(p_file); //imported files do not call update_file(), but just in case.. } Ref<ResourceImporter> importer; bool load_default = false; //find the importer if (importer_name != "") { importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name); } if (importer.is_null()) { //not found by name, find by extension importer = ResourceFormatImporter::get_singleton()->get_importer_by_extension(p_file.get_extension()); load_default = true; if (importer.is_null()) { ERR_PRINT("BUG: File queued for import, but can't be imported!"); ERR_FAIL(); } } //mix with default params, in case a parameter is missing List<ResourceImporter::ImportOption> opts; importer->get_import_options(&opts); for (List<ResourceImporter::ImportOption>::Element *E = opts.front(); E; E = E->next()) { if (!params.has(E->get().option.name)) { //this one is not present params[E->get().option.name] = E->get().default_value; } } if (load_default && ProjectSettings::get_singleton()->get("importer_defaults/" + importer->get_importer_name())) { //use defaults if exist Dictionary d = ProjectSettings::get_singleton()->get("importer_defaults/" + importer->get_importer_name()); List<Variant> v; d.get_key_list(&v); for (List<Variant>::Element *E = v.front(); E; E = E->next()) { params[E->get()] = d[E->get()]; } } //finally, perform import!! String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(p_file); List<String> import_variants; List<String> gen_files; Error err = importer->import(p_file, base_path, params, &import_variants, &gen_files); if (err != OK) { ERR_PRINTS("Error importing: " + p_file); } //as import is complete, save the .import file FileAccess *f = FileAccess::open(p_file + ".import", FileAccess::WRITE); ERR_FAIL_COND(!f); //write manually, as order matters ([remap] has to go first for performance). f->store_line("[remap]"); f->store_line(""); f->store_line("importer=\"" + importer->get_importer_name() + "\""); if (importer->get_resource_type() != "") { f->store_line("type=\"" + importer->get_resource_type() + "\""); } if (importer->get_save_extension() == "") { //no path } else if (import_variants.size()) { //import with variants for (List<String>::Element *E = import_variants.front(); E; E = E->next()) { String path = base_path.c_escape() + "." + E->get() + "." + importer->get_save_extension(); f->store_line("path." + E->get() + "=\"" + path + "\""); } } else { f->store_line("path=\"" + base_path + "." + importer->get_save_extension() + "\""); } f->store_line(""); if (gen_files.size()) { f->store_line("[gen]"); Array genf; for (List<String>::Element *E = gen_files.front(); E; E = E->next()) { genf.push_back(E->get()); } String value; VariantWriter::write_to_string(genf, value); f->store_line("files=" + value); f->store_line(""); } f->store_line("[params]"); f->store_line(""); //store options in provided order, to avoid file changing. Order is also important because first match is accepted first. for (List<ResourceImporter::ImportOption>::Element *E = opts.front(); E; E = E->next()) { String base = E->get().option.name; String value; VariantWriter::write_to_string(params[base], value); f->store_line(base + "=" + value); } f->close(); memdelete(f); //update modified times, to avoid reimport fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file); fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file + ".import"); fs->files[cpos]->deps = _get_dependencies(p_file); fs->files[cpos]->type = importer->get_resource_type(); //if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it //to reload properly if (ResourceCache::has(p_file)) { Resource *r = ResourceCache::get(p_file); if (r->get_import_path() != String()) { String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(p_file); r->set_import_path(dst_path); r->set_import_last_modified_time(0); } } }
void ok_pressed() { if (!_test_path()) return; String dir; if (mode==MODE_IMPORT) { dir=project_path->get_text(); } else { DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (d->change_dir(project_path->get_text())!=OK) { error->set_text(TTR("Invalid project path (changed anything?).")); memdelete(d); return; } dir=d->get_current_dir(); memdelete(d); if (mode==MODE_NEW) { FileAccess *f = FileAccess::open(dir.plus_file("/engine.cfg"),FileAccess::WRITE); if (!f) { error->set_text(TTR("Couldn't create engine.cfg in project path.")); } else { f->store_line("; Engine configuration file."); f->store_line("; It's best edited using the editor UI and not directly,"); f->store_line("; since the parameters that go here are not all obvious."); f->store_line("; "); f->store_line("; Format: "); f->store_line("; [section] ; section goes between []"); f->store_line("; param=value ; assign values to parameters"); f->store_line("\n"); f->store_line("[application]"); f->store_line("\n"); f->store_line("name=\""+project_name->get_text()+"\""); f->store_line("icon=\"res://icon.png\""); memdelete(f); ResourceSaver::save(dir.plus_file("/icon.png"),get_icon("DefaultProjectIcon","EditorIcons")); } } else if (mode==MODE_INSTALL) { FileAccess *src_f=NULL; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); unzFile pkg = unzOpen2(zip_path.utf8().get_data(), &io); if (!pkg) { dialog_error->set_text("Error opening package file, not in zip format."); return; } int ret = unzGoToFirstFile(pkg); Vector<String> failed_files; int idx=0; while(ret==UNZ_OK) { //get filename unz_file_info info; char fname[16384]; ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0); String path=fname; int depth=1; //stuff from github comes with tag bool skip=false; while(depth>0) { int pp = path.find("/"); if (pp==-1) { skip=true; break; } path=path.substr(pp+1,path.length()); depth--; } if (skip || path==String()) { // } else if (path.ends_with("/")) { // a dir path=path.substr(0,path.length()-1); DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); da->make_dir(dir.plus_file(path)); memdelete(da); } else { Vector<uint8_t> data; data.resize(info.uncompressed_size); //read unzOpenCurrentFile(pkg); unzReadCurrentFile(pkg,data.ptr(),data.size()); unzCloseCurrentFile(pkg); FileAccess *f=FileAccess::open(dir.plus_file(path),FileAccess::WRITE); if (f) { f->store_buffer(data.ptr(),data.size()); memdelete(f); } else { failed_files.push_back(path); } } idx++; ret = unzGoToNextFile(pkg); } unzClose(pkg); if (failed_files.size()) { String msg=TTR("The following files failed extraction from package:")+"\n\n"; for(int i=0;i<failed_files.size();i++) { if (i>15) { msg+="\nAnd "+itos(failed_files.size()-i)+" more files."; break; } msg+=failed_files[i]+"\n"; } dialog_error->set_text(msg); dialog_error->popup_centered_minsize(); } else { dialog_error->set_text(TTR("Package Installed Successfully!")); dialog_error->popup_centered_minsize(); } } } dir=dir.replace("\\","/"); if (dir.ends_with("/")) dir=dir.substr(0,dir.length()-1); String proj=dir.replace("/","::"); EditorSettings::get_singleton()->set("projects/"+proj,dir); EditorSettings::get_singleton()->save(); hide(); emit_signal("project_created"); }
void EditorResourcePreview::_thread() { //print_line("begin thread"); while (!exit) { //print_line("wait for semaphore"); preview_sem->wait(); preview_mutex->lock(); //print_line("blue team go"); if (queue.size()) { QueueItem item = queue.front()->get(); queue.pop_front(); if (cache.has(item.path)) { //already has it because someone loaded it, just let it know it's ready if (item.resource.is_valid()) { item.path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below) } _preview_ready(item.path, cache[item.path].preview, item.id, item.function, item.userdata); preview_mutex->unlock(); } else { preview_mutex->unlock(); Ref<Texture> texture; //print_line("pop from queue "+item.path); int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size"); thumbnail_size *= EDSCALE; if (item.resource.is_valid()) { texture = _generate_preview(item, String()); //adding hash to the end of path (should be ID:<objid>:<hash>) because of 5 argument limit to call_deferred _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, item.id, item.function, item.userdata); } else { String temp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp"); String cache_base = Globals::get_singleton()->globalize_path(item.path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); //does not have it, try to load a cached thumbnail String file = cache_base + ".txt"; //print_line("cachetxt at "+file); FileAccess *f = FileAccess::open(file, FileAccess::READ); if (!f) { //print_line("generate because not cached"); //generate texture = _generate_preview(item, cache_base); } else { uint64_t modtime = FileAccess::get_modified_time(item.path); int tsize = f->get_line().to_int64(); uint64_t last_modtime = f->get_line().to_int64(); bool cache_valid = true; if (tsize != thumbnail_size) { cache_valid = false; memdelete(f); } else if (last_modtime != modtime) { String last_md5 = f->get_line(); String md5 = FileAccess::get_md5(item.path); memdelete(f); if (last_md5 != md5) { cache_valid = false; } else { //update modified time f = FileAccess::open(file, FileAccess::WRITE); f->store_line(itos(modtime)); f->store_line(md5); memdelete(f); } } else { memdelete(f); } if (cache_valid) { texture = ResourceLoader::load(cache_base + ".png", "ImageTexture", true); if (!texture.is_valid()) { //well f**k cache_valid = false; } } if (!cache_valid) { texture = _generate_preview(item, cache_base); } } //print_line("notify of preview ready"); _preview_ready(item.path, texture, item.id, item.function, item.userdata); } } } else { preview_mutex->unlock(); } } }