399 lines
12 KiB
GDScript
399 lines
12 KiB
GDScript
extends Node
|
|
|
|
class Layer:
|
|
var name : String
|
|
var index : int
|
|
var hidden : bool
|
|
var albedo : Texture
|
|
var mr : Texture
|
|
var emission : Texture
|
|
var depth : Texture
|
|
var layers : Array = []
|
|
|
|
var albedo_alpha : float = 1.0
|
|
var metallic_alpha : float = 1.0
|
|
var roughness_alpha : float = 1.0
|
|
var emission_alpha : float = 1.0
|
|
var depth_alpha : float = 1.0
|
|
|
|
func set_alpha(channel : String, value : float) -> void:
|
|
set(channel+"_alpha", value)
|
|
|
|
func update_color_rects(channel : String, parent_alpha : float = 1.0) -> void:
|
|
var alpha = parent_alpha * get(channel+"_alpha")
|
|
for cr in get(channel+"_color_rects"):
|
|
cr.modulate.a = alpha
|
|
for l in layers:
|
|
l.update_color_rects(channel, alpha)
|
|
|
|
var albedo_color_rects : Array = []
|
|
var metallic_color_rects : Array = []
|
|
var roughness_color_rects : Array = []
|
|
var emission_color_rects : Array = []
|
|
var depth_color_rects : Array = []
|
|
|
|
export(NodePath) var painter = null
|
|
|
|
var texture_size = 0
|
|
var layers : Array = []
|
|
var selected_layer : Layer
|
|
|
|
onready var tree = $Tree
|
|
onready var albedo = $Albedo
|
|
onready var metallic = $Metallic
|
|
onready var roughness = $Roughness
|
|
onready var mr = $MR
|
|
onready var emission = $Emission
|
|
onready var depth = $Depth
|
|
onready var painter_node = get_node(painter) if painter != null else null
|
|
|
|
onready var nm_viewport = $NormalMap
|
|
onready var nm_rect = $NormalMap/Rect
|
|
onready var nm_material = $NormalMap/Rect.get_material()
|
|
|
|
onready var layers_pane = get_node("/root/MainWindow").layout.get_panel("Layers")
|
|
|
|
const CHANNELS : Array = [ "albedo", "mr", "emission", "depth" ]
|
|
|
|
func _ready():
|
|
pass
|
|
|
|
func set_texture_size(s : float):
|
|
if texture_size == s:
|
|
return
|
|
texture_size = s
|
|
var size = Vector2(s, s)
|
|
var selected_layer_save = selected_layer
|
|
var result = select_layer(null)
|
|
while result is GDScriptFunctionState:
|
|
result = yield(result, "completed")
|
|
resize_layers(s)
|
|
albedo.size = size
|
|
metallic.size = size
|
|
roughness.size = size
|
|
mr.size = size
|
|
$MR/Metallic.texture = metallic.get_texture()
|
|
$MR/Metallic.rect_size = size
|
|
$MR/Roughness.texture = roughness.get_texture()
|
|
$MR/Roughness.rect_size = size
|
|
emission.size = size
|
|
depth.size = size
|
|
nm_viewport.size = size
|
|
nm_rect.rect_size = size
|
|
nm_material.set_shader_param("epsilon", 1/s)
|
|
nm_material.set_shader_param("tex", depth.get_texture())
|
|
nm_material.set_shader_param("seams", painter_node.mesh_seams_tex)
|
|
painter_node.set_texture_size(s)
|
|
select_layer(selected_layer_save)
|
|
while result is GDScriptFunctionState:
|
|
result = yield(result, "completed")
|
|
_on_Painter_painted()
|
|
|
|
func find_parent_array(layer : Layer, layer_array : Array = layers):
|
|
for l in layer_array:
|
|
if l == layer:
|
|
return layer_array
|
|
var rv = find_parent_array(layer, l.layers)
|
|
if rv != null:
|
|
return rv
|
|
return null
|
|
|
|
func resize_layers(size : int, layers_array : Array = layers):
|
|
for l in layers_array:
|
|
for c in CHANNELS:
|
|
if l.get(c) != null:
|
|
var texture : ImageTexture = l.get(c)
|
|
var image : Image = Image.new()
|
|
image.copy_from(texture.get_data())
|
|
image.resize(size, size)
|
|
texture.create_from_image(image)
|
|
resize_layers(size, l.layers)
|
|
|
|
func get_albedo_texture():
|
|
return albedo.get_texture()
|
|
|
|
func get_metallic_texture():
|
|
return metallic.get_texture()
|
|
|
|
func get_roughness_texture():
|
|
return roughness.get_texture()
|
|
|
|
func get_mr_texture():
|
|
return mr.get_texture()
|
|
|
|
func get_emission_texture():
|
|
return emission.get_texture()
|
|
|
|
func get_normal_map():
|
|
return nm_viewport.get_texture()
|
|
|
|
func get_depth_texture():
|
|
return depth.get_texture()
|
|
|
|
func _on_Tree_selection_changed(old_selected : TreeItem, new_selected : TreeItem) -> void:
|
|
select_layer(new_selected.get_meta("layer"))
|
|
|
|
func select_layer(layer : Layer) -> void:
|
|
if layer == selected_layer:
|
|
return
|
|
if painter_node == null:
|
|
painter_node = get_node(painter)
|
|
for c in CHANNELS:
|
|
if selected_layer != null:
|
|
var old_texture : Texture = selected_layer.get(c)
|
|
var new_texture = ImageTexture.new()
|
|
if old_texture != null:
|
|
new_texture.create_from_image(old_texture.get_data())
|
|
selected_layer.set(c, new_texture)
|
|
if layer != null:
|
|
if layer.get(c) != null:
|
|
painter_node.call("init_"+c+"_texture", Color(1.0, 1.0, 1.0, 1.0), layer.get(c))
|
|
else:
|
|
painter_node.call("init_"+c+"_texture")
|
|
layer.set(c, painter_node.call("get_"+c+"_texture"))
|
|
selected_layer = layer
|
|
yield(get_tree(), "idle_frame")
|
|
yield(get_tree(), "idle_frame")
|
|
_on_layers_changed()
|
|
|
|
func get_unused_layer_name(layers_array : Array) -> String:
|
|
return "New layer"
|
|
|
|
func layer_index_is_used(index : int, layers_array : Array) -> bool:
|
|
for l in layers_array:
|
|
if l.index == index or layer_index_is_used(index, l.layers):
|
|
return true
|
|
return false
|
|
|
|
func get_unused_layer_index() -> int:
|
|
var index : int = 0
|
|
while layer_index_is_used(index, layers):
|
|
index += 1
|
|
return index
|
|
|
|
func add_layer() -> void:
|
|
var layer = Layer.new()
|
|
layer.name = get_unused_layer_name(layers)
|
|
layer.index = get_unused_layer_index()
|
|
layer.hidden = false
|
|
var image : Image = Image.new()
|
|
image.create(texture_size, texture_size, false, Image.FORMAT_RGBA8)
|
|
image.fill(Color(0, 0, 0, 0))
|
|
for c in CHANNELS:
|
|
var texture = ImageTexture.new()
|
|
texture.create_from_image(image)
|
|
layer.set(c, texture)
|
|
layers.push_front(layer)
|
|
select_layer(layer)
|
|
|
|
func duplicate_layer(source_layer : Layer) -> void:
|
|
var layer = Layer.new()
|
|
layer.name = source_layer.name+" (copy)"
|
|
layer.index = get_unused_layer_index()
|
|
layer.hidden = false
|
|
for c in CHANNELS:
|
|
var texture = ImageTexture.new()
|
|
texture.create_from_image(source_layer.get(c).get_data())
|
|
layer.set(c, texture)
|
|
layers.push_front(layer)
|
|
select_layer(layer)
|
|
|
|
func remove_layer(layer : Layer) -> void:
|
|
var need_reselect : bool = (layer == selected_layer)
|
|
var layers_array : Array = find_parent_array(layer)
|
|
layers_array.erase(layer)
|
|
if need_reselect:
|
|
selected_layer = null
|
|
if !layers.empty():
|
|
select_layer(layers[0])
|
|
return
|
|
_on_layers_changed()
|
|
|
|
func move_layer_into(layer : Layer, target_layer : Layer, index : int = -1) -> void:
|
|
var array : Array = find_parent_array(layer)
|
|
var orig_index = array.find(layer)
|
|
array.erase(layer)
|
|
var target_array = target_layer.layers if target_layer != null else layers
|
|
if index == -1:
|
|
index = target_array.size()
|
|
elif array == target_array and index > orig_index:
|
|
index -= 1
|
|
target_array.insert(index, layer)
|
|
_on_layers_changed()
|
|
|
|
func move_layer_up(layer : Layer) -> void:
|
|
var array : Array = find_parent_array(layer)
|
|
var orig_index = array.find(layer)
|
|
if orig_index > 0:
|
|
array.erase(layer)
|
|
array.insert(orig_index-1, layer)
|
|
_on_layers_changed()
|
|
|
|
func move_layer_down(layer : Layer) -> void:
|
|
var array : Array = find_parent_array(layer)
|
|
var orig_index = array.find(layer)
|
|
if orig_index < array.size()-1:
|
|
array.erase(layer)
|
|
array.insert(orig_index+1, layer)
|
|
_on_layers_changed()
|
|
|
|
func update_alpha(channel : String) -> void:
|
|
for l in layers:
|
|
l.update_color_rects(channel)
|
|
|
|
func _on_layers_changed() -> void:
|
|
var list = []
|
|
get_visible_layers(list)
|
|
update_layers_renderer(list)
|
|
for c in [ "albedo", "metallic", "roughness", "emission", "depth"]:
|
|
update_alpha(c)
|
|
layers_pane.call_deferred("set_layers", self)
|
|
|
|
func get_visible_layers(list : Array, layers_array : Array = layers) -> void:
|
|
for i in range(layers_array.size()-1, -1, -1):
|
|
var l = layers_array[i]
|
|
if l.hidden:
|
|
continue
|
|
get_visible_layers(list, l.layers)
|
|
list.push_back(l)
|
|
|
|
func update_layers_renderer(visible_layers : Array) -> void:
|
|
for viewport in [ albedo, metallic, roughness, emission, depth ]:
|
|
while viewport.get_child_count() > 0:
|
|
viewport.remove_child(viewport.get_child(0))
|
|
for l in visible_layers:
|
|
var texture_rect : TextureRect
|
|
texture_rect = TextureRect.new()
|
|
texture_rect.texture = l.albedo
|
|
texture_rect.modulate = Color(1.0, 1.0, 1.0, l.albedo_alpha)
|
|
texture_rect.rect_size = albedo.size
|
|
l.albedo_color_rects = [ texture_rect ]
|
|
albedo.add_child(texture_rect)
|
|
texture_rect = TextureRect.new()
|
|
texture_rect.texture = l.mr
|
|
texture_rect.modulate = Color(1.0, 1.0, 1.0, l.metallic_alpha)
|
|
texture_rect.rect_size = mr.size
|
|
texture_rect.material = preload("res://material_maker/panels/paint/shaders/metallic_layer.tres")
|
|
l.metallic_color_rects = [ texture_rect ]
|
|
metallic.add_child(texture_rect)
|
|
texture_rect = TextureRect.new()
|
|
texture_rect.texture = l.mr
|
|
texture_rect.modulate = Color(1.0, 1.0, 1.0, l.roughness_alpha)
|
|
texture_rect.rect_size = mr.size
|
|
texture_rect.material = preload("res://material_maker/panels/paint/shaders/roughness_layer.tres")
|
|
l.roughness_color_rects = [ texture_rect ]
|
|
roughness.add_child(texture_rect)
|
|
# var color_rect : ColorRect = ColorRect.new()
|
|
# color_rect.rect_size = mr.size
|
|
# color_rect.material = preload("res://material_maker/panels/paint/shaders/mr_layer.tres").duplicate()
|
|
# color_rect.material.set_shader_param("mr", l.mr"))
|
|
# mr.add_child(color_rect)
|
|
texture_rect = TextureRect.new()
|
|
texture_rect.texture = l.albedo
|
|
texture_rect.modulate = Color(0.0, 0.0, 0.0, l.albedo_alpha)
|
|
texture_rect.rect_size = emission.size
|
|
l.albedo_color_rects.push_back(texture_rect)
|
|
emission.add_child(texture_rect)
|
|
texture_rect = TextureRect.new()
|
|
texture_rect.texture = l.emission
|
|
texture_rect.modulate = Color(1.0, 1.0, 1.0, l.emission_alpha)
|
|
texture_rect.rect_size = emission.size
|
|
l.emission_color_rects.push_back(texture_rect)
|
|
emission.add_child(texture_rect)
|
|
texture_rect = TextureRect.new()
|
|
texture_rect.texture = l.depth
|
|
texture_rect.modulate = Color(1.0, 1.0, 1.0, l.depth_alpha)
|
|
texture_rect.rect_size = depth.size
|
|
l.depth_color_rects.push_back(texture_rect)
|
|
depth.add_child(texture_rect)
|
|
_on_Painter_painted()
|
|
|
|
func load(data : Dictionary, file_name : String):
|
|
var dir_name = file_name.left(file_name.rfind("."))
|
|
layers.clear()
|
|
load_layers(data.layers, layers, dir_name)
|
|
_on_layers_changed()
|
|
|
|
func load_layers(data_layers : Array, layers_array : Array, path : String, first_index : int = 0) -> int:
|
|
for l in data_layers:
|
|
var layer : Layer = Layer.new()
|
|
layer.name = l.name
|
|
if l.has("index"):
|
|
layer.index = l.index
|
|
else:
|
|
layer.index = first_index
|
|
first_index += 1
|
|
layer.hidden = l.hidden
|
|
for c in CHANNELS:
|
|
if l.has(c):
|
|
var texture = ImageTexture.new()
|
|
texture.load(path+"/"+l[c])
|
|
layer.set(c, texture)
|
|
for c in [ "albedo", "metallic", "roughness", "emission", "depth" ]:
|
|
layer.set(c+"_alpha", l[c+"_alpha"] if l.has(c+"_alpha") else 1.0)
|
|
if l.has("layers"):
|
|
first_index = load_layers(l.layers, layer.layers, path, first_index)
|
|
layers_array.push_back(layer)
|
|
return first_index
|
|
|
|
func save(file_name : String) -> Dictionary:
|
|
var dir_name = file_name.left(file_name.rfind("."))
|
|
var dir = Directory.new()
|
|
dir.make_dir(dir_name)
|
|
var data = { texture_size=texture_size }
|
|
#tree.save_layers(data, tree.get_root(), 0, dir_name, [ "albedo", "mr", "emission", "depth" ])
|
|
data.layers = save_layers(layers, dir_name)
|
|
return data
|
|
|
|
func save_layers(layers_array : Array, path : String) -> Array:
|
|
var layers_data = []
|
|
for l in layers_array:
|
|
var layer_data = { name=l.name, index=l.index, hidden=l.hidden }
|
|
for c in CHANNELS:
|
|
if l.get(c) != null:
|
|
var file_name : String = "%s_%d.png" % [ c, l.index ]
|
|
var file_path : String = path.plus_file(file_name)
|
|
var image : Image = l.get(c).get_data()
|
|
image.lock()
|
|
image.save_png(file_path)
|
|
image.unlock()
|
|
layer_data[c] = file_name
|
|
for c in [ "albedo", "metallic", "roughness", "emission", "depth" ]:
|
|
layer_data[c+"_alpha"] = l.get(c+"_alpha")
|
|
if !l.layers.empty():
|
|
layer_data.layers = save_layers(l.layers, path)
|
|
layers_data.push_back(layer_data)
|
|
return layers_data
|
|
|
|
func _on_Painter_painted():
|
|
for viewport in [ albedo, metallic, roughness, emission, depth ]:
|
|
viewport.render_target_update_mode = Viewport.UPDATE_ONCE
|
|
viewport.update_worlds()
|
|
yield(get_tree(), "idle_frame")
|
|
yield(get_tree(), "idle_frame")
|
|
mr.render_target_update_mode = Viewport.UPDATE_ONCE
|
|
mr.update_worlds()
|
|
nm_viewport.render_target_update_mode = Viewport.UPDATE_ONCE
|
|
nm_viewport.update_worlds()
|
|
|
|
# debug
|
|
|
|
func debug_get_texture_names():
|
|
return [ "Albedo", "Metallic", "Roughness", "Metallic/Roughness", "Emission", "Normal map", "Depth" ]
|
|
|
|
func debug_get_texture(ID):
|
|
if ID == 0:
|
|
return get_albedo_texture()
|
|
if ID == 1:
|
|
return $Metallic.get_texture()
|
|
if ID == 2:
|
|
return $Roughness.get_texture()
|
|
elif ID == 3:
|
|
return get_mr_texture()
|
|
elif ID == 4:
|
|
return get_emission_texture()
|
|
elif ID == 5:
|
|
return get_normal_map()
|
|
elif ID == 6:
|
|
return get_depth_texture()
|