diff --git a/material_maker/panels/graph_edit/graph_edit.gd b/material_maker/panels/graph_edit/graph_edit.gd index ee4079441..4af999d6c 100644 --- a/material_maker/panels/graph_edit/graph_edit.gd +++ b/material_maker/panels/graph_edit/graph_edit.gd @@ -785,10 +785,24 @@ func load_from_recovery(filename) -> bool: # Save +func generate_project_thumbnail() -> String: + var preview_vp : SubViewport + if not has_node("PreviewViewport"): + preview_vp = load("res://material_maker/tools/share/preview_viewport.tscn").instantiate() + add_child(preview_vp) + else: + preview_vp = get_node("PreviewViewport") + await mm_globals.main_window.update_preview_3d([preview_vp]) + var t : ImageTexture = await preview_vp.get_preview(0) + var img : Image = t.get_image() + @warning_ignore("integer_division") + img.resize(48, 48 * t.get_height() / t.get_width(), Image.INTERPOLATE_LANCZOS) + return Marshalls.raw_to_base64(img.save_webp_to_buffer(true, 0.75)) + func save() -> bool: var status = false if save_path != "": - status = save_file(save_path) + status = await save_file(save_path) else: status = await save_as() return status @@ -799,7 +813,7 @@ func save_as() -> bool: add_child(dialog) var status = await dialog.enter_text("Save", "Select a file name", save_path.get_file() if save_path != null else "") if status.ok: - if save_file(status.text.get_file().get_basename()+".ptex"): + if await save_file(status.text.get_file().get_basename()+".ptex"): top_generator.emit_signal("hierarchy_changed") else: var dialog = preload("res://material_maker/windows/file_dialog/file_dialog.tscn").instantiate() @@ -811,16 +825,17 @@ func save_as() -> bool: dialog.current_dir = mm_globals.config.get_value("path", "project", mm_globals.get_home_directory()) var files = await dialog.select_files() if files.size() == 1: - if save_file(files[0]): + if await save_file(files[0]): main_window.add_recent(save_path) mm_globals.config.set_value("path", "project", save_path.get_base_dir()) top_generator.emit_signal("hierarchy_changed") return true return false -func save_file(filename:String) -> bool: +func save_file(filename : String) -> bool: mm_loader.current_project_path = filename.get_base_dir() var data = top_generator.serialize() + data["project_thumbnail"] = await generate_project_thumbnail() mm_loader.current_project_path = "" var e: Error if OS.get_name() == "HTML5": diff --git a/material_maker/theme/default.tres b/material_maker/theme/default.tres index f19d6072b..f9deb4c90 100644 --- a/material_maker/theme/default.tres +++ b/material_maker/theme/default.tres @@ -1249,7 +1249,6 @@ CodeEdit/colors/type_color = Color(1, 1, 0.5, 1) CodeEdit/styles/focus = SubResource("StyleBoxEmpty_m27ao") CodeEdit/styles/normal = SubResource("StyleBoxFlat_oy0ko") FileDialog/colors/file_disabled_color = Color(0.301961, 0.305882, 0.309804, 1) -FileDialog/colors/file_icon_color = Color(0.698039, 0.698039, 0.698039, 1) FileDialog/colors/folder_icon_color = Color(0.698039, 0.698039, 0.698039, 1) FileDialog/styles/panel = SubResource("StyleBoxFlat_ck0hb") GraphEdit/colors/connection_knife = Color(0.99215686, 0.9843137, 1, 1) diff --git a/material_maker/tools/share/share_button.gd b/material_maker/tools/share/share_button.gd index 062b6e274..6821bbd01 100644 --- a/material_maker/tools/share/share_button.gd +++ b/material_maker/tools/share/share_button.gd @@ -144,6 +144,10 @@ func send_asset(asset_type : String, asset_data : Dictionary, preview_textures : if asset_info.is_empty(): return var png_image = asset_info.preview_texture.get_image().save_png_to_buffer() + + # strip project thumbnail + asset_data.erase("project_thumbnail") + asset_info.type = asset_type asset_info.mm_version = ProjectSettings.get_setting("application/config/actual_release") asset_info.image_text = "data:image/png;base64,"+Marshalls.raw_to_base64(png_image) diff --git a/material_maker/windows/file_dialog/file_dialog.gd b/material_maker/windows/file_dialog/file_dialog.gd index 9beb07029..861e94d8e 100644 --- a/material_maker/windows/file_dialog/file_dialog.gd +++ b/material_maker/windows/file_dialog/file_dialog.gd @@ -9,11 +9,17 @@ var recents_list : ItemList = null var left_panel : VSplitContainer +enum Thumbnail { + IMAGE, + PROJECT, +} + func _context_menu_about_to_popup(context_menu : PopupMenu): context_menu.position = get_window().position + Vector2i( get_mouse_position() * _content_scale_factor) func _ready() -> void: + FileDialog.set_get_thumbnail_callback(thumb_callback) load_fav_recents() if file_mode == FileMode.FILE_MODE_SAVE_FILE: ok_button_text = tr("Save") @@ -109,3 +115,44 @@ func load_fav_recents() -> void: if mm_globals.config.has_section_key("file_dialog", "favorites"): if json.parse(mm_globals.config.get_value("file_dialog", "favorites")) == OK: set_favorite_list(json.data) + +#region thumbnail generation + +var default_file_thumbnail : DPITexture = get_theme_icon("file_thumbnail", "FileDialog") + +func thumb_callback(path : String) -> Texture2D: + var t : Thread = Thread.new() + var tex : Texture2D = default_file_thumbnail + match path.get_extension().to_lower(): + "bmp", "exr", "hdr", "jpg", "jpeg", "png", "svg", "tga", "webp", "dds": + tex = ImageTexture.new() + t.start(thumb_generate.bind(t, path, tex, Thumbnail.IMAGE)) + "ptex": + tex = ImageTexture.new() + t.start(thumb_generate.bind(t, path, tex, Thumbnail.PROJECT)) + return tex + +func thumb_set(thread : Thread, image : Image, tex : Texture2D) -> void: + if thread.is_started(): + tex = await thread.wait_to_finish() + if tex and image and not image.is_invisible(): + tex.set_image(image) + +func thumb_generate(thread : Thread, path : String, tex : Texture2D, + type : Thumbnail) -> Texture2D: + var img : Image = default_file_thumbnail.get_image() + match type: + Thumbnail.IMAGE: + if path.get_extension().to_lower() == "dds": + img.load_dds_from_buffer(FileAccess.get_file_as_bytes(path)) + else: + img = Image.load_from_file(path) + Thumbnail.PROJECT: + var f := FileAccess.open(path, FileAccess.READ) + var ptex : Dictionary = JSON.parse_string(f.get_as_text()) + if ptex and ptex.has("project_thumbnail"): + img.load_webp_from_buffer(Marshalls.base64_to_raw(ptex.project_thumbnail)) + thumb_set.call_deferred(thread, img, tex) + return tex + +#endregion