Skip to content

Commit 913e6ab

Browse files
committed
Implement image/ptex file thumbnails in file dialog
1 parent 8e437b5 commit 913e6ab

4 files changed

Lines changed: 70 additions & 5 deletions

File tree

material_maker/panels/graph_edit/graph_edit.gd

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -785,10 +785,24 @@ func load_from_recovery(filename) -> bool:
785785

786786
# Save
787787

788+
func generate_project_thumbnail() -> String:
789+
var preview_vp : SubViewport
790+
if not has_node("PreviewViewport"):
791+
preview_vp = load("res://material_maker/tools/share/preview_viewport.tscn").instantiate()
792+
add_child(preview_vp)
793+
else:
794+
preview_vp = get_node("PreviewViewport")
795+
await mm_globals.main_window.update_preview_3d([preview_vp])
796+
var t : ImageTexture = await preview_vp.get_preview(0)
797+
var img : Image = t.get_image()
798+
@warning_ignore("integer_division")
799+
img.resize(48, 48 * t.get_height() / t.get_width(), Image.INTERPOLATE_LANCZOS)
800+
return Marshalls.raw_to_base64(img.save_webp_to_buffer(true, 0.75))
801+
788802
func save() -> bool:
789803
var status = false
790804
if save_path != "":
791-
status = save_file(save_path)
805+
status = await save_file(save_path)
792806
else:
793807
status = await save_as()
794808
return status
@@ -799,7 +813,7 @@ func save_as() -> bool:
799813
add_child(dialog)
800814
var status = await dialog.enter_text("Save", "Select a file name", save_path.get_file() if save_path != null else "")
801815
if status.ok:
802-
if save_file(status.text.get_file().get_basename()+".ptex"):
816+
if await save_file(status.text.get_file().get_basename()+".ptex"):
803817
top_generator.emit_signal("hierarchy_changed")
804818
else:
805819
var dialog = preload("res://material_maker/windows/file_dialog/file_dialog.tscn").instantiate()
@@ -811,16 +825,17 @@ func save_as() -> bool:
811825
dialog.current_dir = mm_globals.config.get_value("path", "project", mm_globals.get_home_directory())
812826
var files = await dialog.select_files()
813827
if files.size() == 1:
814-
if save_file(files[0]):
828+
if await save_file(files[0]):
815829
main_window.add_recent(save_path)
816830
mm_globals.config.set_value("path", "project", save_path.get_base_dir())
817831
top_generator.emit_signal("hierarchy_changed")
818832
return true
819833
return false
820834

821-
func save_file(filename:String) -> bool:
835+
func save_file(filename : String) -> bool:
822836
mm_loader.current_project_path = filename.get_base_dir()
823837
var data = top_generator.serialize()
838+
data["project_thumbnail"] = await generate_project_thumbnail()
824839
mm_loader.current_project_path = ""
825840
var e: Error
826841
if OS.get_name() == "HTML5":

material_maker/theme/default.tres

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1249,7 +1249,6 @@ CodeEdit/colors/type_color = Color(1, 1, 0.5, 1)
12491249
CodeEdit/styles/focus = SubResource("StyleBoxEmpty_m27ao")
12501250
CodeEdit/styles/normal = SubResource("StyleBoxFlat_oy0ko")
12511251
FileDialog/colors/file_disabled_color = Color(0.301961, 0.305882, 0.309804, 1)
1252-
FileDialog/colors/file_icon_color = Color(0.698039, 0.698039, 0.698039, 1)
12531252
FileDialog/colors/folder_icon_color = Color(0.698039, 0.698039, 0.698039, 1)
12541253
FileDialog/styles/panel = SubResource("StyleBoxFlat_ck0hb")
12551254
GraphEdit/colors/connection_knife = Color(0.99215686, 0.9843137, 1, 1)

material_maker/tools/share/share_button.gd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ func send_asset(asset_type : String, asset_data : Dictionary, preview_textures :
144144
if asset_info.is_empty():
145145
return
146146
var png_image = asset_info.preview_texture.get_image().save_png_to_buffer()
147+
148+
# strip project thumbnail
149+
asset_data.erase("project_thumbnail")
150+
147151
asset_info.type = asset_type
148152
asset_info.mm_version = ProjectSettings.get_setting("application/config/actual_release")
149153
asset_info.image_text = "data:image/png;base64,"+Marshalls.raw_to_base64(png_image)

material_maker/windows/file_dialog/file_dialog.gd

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ var recents_list : ItemList = null
99

1010
var left_panel : VSplitContainer
1111

12+
enum Thumbnail {
13+
IMAGE,
14+
PROJECT,
15+
}
16+
1217
func _context_menu_about_to_popup(context_menu : PopupMenu):
1318
context_menu.position = get_window().position + Vector2i(
1419
get_mouse_position() * _content_scale_factor)
1520

1621
func _ready() -> void:
22+
FileDialog.set_get_thumbnail_callback(thumb_callback)
1723
load_fav_recents()
1824
if file_mode == FileMode.FILE_MODE_SAVE_FILE:
1925
ok_button_text = tr("Save")
@@ -109,3 +115,44 @@ func load_fav_recents() -> void:
109115
if mm_globals.config.has_section_key("file_dialog", "favorites"):
110116
if json.parse(mm_globals.config.get_value("file_dialog", "favorites")) == OK:
111117
set_favorite_list(json.data)
118+
119+
#region thumbnail generation
120+
121+
var default_file_thumbnail : DPITexture = get_theme_icon("file_thumbnail", "FileDialog")
122+
123+
func thumb_callback(path : String) -> Texture2D:
124+
var t : Thread = Thread.new()
125+
var tex : Texture2D = default_file_thumbnail
126+
match path.get_extension().to_lower():
127+
"bmp", "exr", "hdr", "jpg", "jpeg", "png", "svg", "tga", "webp", "dds":
128+
tex = ImageTexture.new()
129+
t.start(thumb_generate.bind(t, path, tex, Thumbnail.IMAGE))
130+
"ptex":
131+
tex = ImageTexture.new()
132+
t.start(thumb_generate.bind(t, path, tex, Thumbnail.PROJECT))
133+
return tex
134+
135+
func thumb_set(thread : Thread, image : Image, tex : Texture2D) -> void:
136+
if thread.is_started():
137+
tex = await thread.wait_to_finish()
138+
if tex and image and not image.is_invisible():
139+
tex.set_image(image)
140+
141+
func thumb_generate(thread : Thread, path : String, tex : Texture2D,
142+
type : Thumbnail) -> Texture2D:
143+
var img : Image = default_file_thumbnail.get_image()
144+
match type:
145+
Thumbnail.IMAGE:
146+
if path.get_extension().to_lower() == "dds":
147+
img.load_dds_from_buffer(FileAccess.get_file_as_bytes(path))
148+
else:
149+
img = Image.load_from_file(path)
150+
Thumbnail.PROJECT:
151+
var f := FileAccess.open(path, FileAccess.READ)
152+
var ptex : Dictionary = JSON.parse_string(f.get_as_text())
153+
if ptex and ptex.has("project_thumbnail"):
154+
img.load_webp_from_buffer(Marshalls.base64_to_raw(ptex.project_thumbnail))
155+
thumb_set.call_deferred(thread, img, tex)
156+
return tex
157+
158+
#endregion

0 commit comments

Comments
 (0)