248 lines
8.6 KiB
GDScript
248 lines
8.6 KiB
GDScript
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
|