extends Node var environments = [] var environment_textures = [] onready var base_dir : String = MMPaths.get_resource_dir() var ro_environments = 0 const DEFAULT_ENVIRONMENT = { "name": "Wide Street", "hdri_url": "https://hdrihaven.com/files/hdris/wide_street_01_2k.hdr", "show_color": false, "color": { "type": "Color", "r": 0, "g": 0, "b": 0, "a": 1 }, "sky_energy": 1.1, "ambient_light_color": { "type": "Color", "r": 0, "g": 0, "b": 0, "a": 1 }, "ambient_light_energy": 1, "ambient_light_sky_contribution": 1, "sun_color": { "type": "Color", "r": 1, "g": 1, "b": 1, "a": 1 }, "sun_energy": 0, "sun_direction": 0, "sun_angle": 90 } signal environment_updated(index) signal name_updated(index, text) signal thumbnail_updated(index, texture) func _ready(): set_physics_process(false) if environments.empty(): environments = load_environment(base_dir+"/environments/environments.json") if environments.empty(): environments = load_environment("res://material_maker/environments/environments.json") ro_environments = environments.size() environments += load_environment("user://environments.json") for i in environments.size(): var texture : ImageTexture = ImageTexture.new() if environments[i].has("thumbnail"): var image : Image = Image.new() image.load_png_from_buffer(Marshalls.base64_to_raw(environments[i].thumbnail)) texture.create_from_image(image) environment_textures.push_back({ thumbnail=texture }) func add_environment(data : Dictionary): environments.push_back(data) environment_textures.push_back({ thumbnail=ImageTexture.new() }) emit_signal("name_updated", environments.size()-1, data.name) emit_signal("environment_updated", environments.size()-1) update_thumbnail(environments.size()-1) func get_environment(index : int) -> Dictionary: return environments[index] func load_environment(file_path : String) -> Array: var array : Array = [] var file = File.new() if file.open(file_path, File.READ) == OK: array = parse_json(file.get_as_text()) file.close() return array func _exit_tree() -> void: for i in environments.size(): var image : Image = environment_textures[i].thumbnail.get_data() environments[i].thumbnail = Marshalls.raw_to_base64(image.save_png_to_buffer()) var file = File.new() file.open("user://environments.json", File.WRITE) file.store_string(JSON.print(environments.slice(3, environments.size()-1))) file.close() func get_environment_list() -> Array: var list = [] for i in environments.size(): var env = environments[i] var env_textures = environment_textures[i] var item = { name = env.name if env.has("name") else "unnamed", thumbnail = env_textures.thumbnail } list.push_back(item) return list func create_environment_menu(menu : PopupMenu) -> void: menu.clear() for e in get_environment_list(): menu.add_icon_item(e.thumbnail, e.name) func is_read_only(index) -> bool: return index < ro_environments func set_value(index, variable, value, force = false): if index < ro_environments || index >= environments.size(): return var serialized_value = MMType.serialize_value(value) if force or environments[index][variable] != serialized_value: environments[index][variable] = serialized_value if variable == "hdri_url": var status = read_hdr(index, value) while status is GDScriptFunctionState: status = yield(status, "completed") emit_signal("environment_updated", index) elif variable == "name": emit_signal("name_updated", index, value) else: emit_signal("environment_updated", index) update_thumbnail(index) func apply_environment(index : int, e : Environment, s : DirectionalLight) -> void: if index < 0 || index >= environments.size(): return var env : Dictionary = environments[index] var env_textures : Dictionary = environment_textures[index] e.background_mode = Environment.BG_COLOR_SKY if env.show_color else Environment.BG_SKY e.background_color = MMType.deserialize_value(env.color) if !e.has_meta("hdri") or e.get_meta("hdri") != env.hdri_url: if !env_textures.has("hdri"): var status = read_hdr(index, env.hdri_url) while status is GDScriptFunctionState: status = yield(status, "completed") if env_textures.has("hdri"): e.background_sky.panorama = env_textures.hdri else: e.background_sky.panorama = null e.set_meta("hdri", env.hdri_url) e.background_energy = env.sky_energy e.ambient_light_color = MMType.deserialize_value(env.ambient_light_color) e.ambient_light_energy = env.ambient_light_energy e.ambient_light_sky_contribution = env.ambient_light_sky_contribution e.ambient_light_sky_contribution = env.ambient_light_sky_contribution s.light_color = MMType.deserialize_value(env.sun_color) s.light_energy = env.sun_energy s.rotation_degrees.y = env.sun_direction s.rotation_degrees.x = -env.sun_angle var progress_window = null var accept_dialog : AcceptDialog = null func on_accept_dialog_closed(): accept_dialog = null func read_hdr(index : int, url : String) -> bool: while progress_window != null: yield(get_tree(), "idle_frame") environment_textures[index].erase("hdri") var dir : Directory = Directory.new() if set_hdr(index, base_dir+"/environments/hdris/"+url.get_file()): return true if set_hdr(index, "res://material_maker/environments/hdris/"+url.get_file()): return true var file_path : String = "user://hdris/"+url.get_file() if set_hdr(index, file_path): return true if OS.get_name() == "HTML5": return false Directory.new().make_dir_recursive("user://hdris") $HTTPRequest.download_file = file_path var error = $HTTPRequest.request(url) if error == OK: progress_window = preload("res://material_maker/windows/progress_window/progress_window.tscn").instance() mm_globals.main_window.add_child(progress_window) progress_window.set_text("Downloading HDRI file") progress_window.set_progress(0) set_physics_process(true) yield($HTTPRequest, "request_completed") progress_window.queue_free() progress_window = null set_physics_process(false) if set_hdr(index, file_path): update_thumbnail(index) return true if accept_dialog == null: accept_dialog = AcceptDialog.new() accept_dialog.window_title = "HDRI download error" accept_dialog.dialog_text = "Failed to download %s" % url mm_globals.main_window.add_child(accept_dialog) accept_dialog.connect("confirmed", accept_dialog, "queue_free") accept_dialog.connect("popup_hide", accept_dialog, "queue_free") accept_dialog.connect("tree_exiting", self, "on_accept_dialog_closed") accept_dialog.popup_centered() return false func _physics_process(_delta) -> void: progress_window.set_progress(float($HTTPRequest.get_downloaded_bytes())/float($HTTPRequest.get_body_size())) func set_hdr(index, hdr_path) -> bool: print("Setting hdr "+hdr_path) var hdr : Texture = load(hdr_path) if hdr == null: hdr = ImageTexture.new() if hdr.load(hdr_path) != OK: return false environment_textures[index].hdri = hdr return true func new_environment(index : int) -> void: var new_environment : Dictionary if index >= 0: new_environment = environments[index].duplicate() else: new_environment = DEFAULT_ENVIRONMENT environments.push_back(new_environment) environment_textures.push_back({ thumbnail=ImageTexture.new() }) emit_signal("name_updated", environments.size()-1, new_environment.name) emit_signal("environment_updated", environments.size()-1) update_thumbnail(environments.size()-1) func delete_environment(index : int) -> void: environments.remove(index) environment_textures.remove(index) var thumbnail_update_list = [] var rendering = false func update_thumbnail(index) -> void: while rendering: yield(get_tree(), "idle_frame") if thumbnail_update_list.find(index) == -1: thumbnail_update_list.push_back(index) $Timer.wait_time = 0.5 $Timer.one_shot = true $Timer.stop() $Timer.start() onready var preview_generator : Viewport = $PreviewGenerator func create_preview(index : int, size : int = 64) -> Image: apply_environment(index, $PreviewGenerator/CameraPosition/CameraRotation1/CameraRotation2/Camera.environment, $PreviewGenerator/Sun) preview_generator.size = Vector2(size, size) preview_generator.render_target_update_mode = Viewport.UPDATE_ONCE preview_generator.update_worlds() yield(get_tree(), "idle_frame") yield(get_tree(), "idle_frame") return preview_generator.get_texture().get_data() func do_update_thumbnail() -> void: rendering = true for index in thumbnail_update_list: var image = create_preview(index) while image is GDScriptFunctionState: image = yield(image, "completed") if image != null: var t : ImageTexture = environment_textures[index].thumbnail t.create_from_image(image) emit_signal("thumbnail_updated", index, t) thumbnail_update_list = [] rendering = false