209 lines
7.8 KiB
GDScript
209 lines
7.8 KiB
GDScript
extends ViewportContainer
|
|
|
|
const CAMERA_DISTANCE_MIN = 1.0
|
|
const CAMERA_DISTANCE_MAX = 10.0
|
|
|
|
export var ui_path : String = "UI/Preview3DUI"
|
|
|
|
onready var objects = $MaterialPreview/Preview3d/Objects
|
|
onready var current_object = objects.get_child(0)
|
|
|
|
onready var environments = $MaterialPreview/Preview3d/Environments
|
|
onready var current_environment = environments.get_child(0)
|
|
|
|
onready var camera_stand = $MaterialPreview/Preview3d/CameraPivot
|
|
onready var camera = $MaterialPreview/Preview3d/CameraPivot/Camera
|
|
|
|
var ui
|
|
|
|
signal need_update(me)
|
|
|
|
const MENU = [
|
|
{ menu="Model", submenu="model_list", description="Select" },
|
|
{ menu="Model", command="configure_model", description="Configure" },
|
|
{ menu="Model", command="rotate_model", description="Rotate", toggle=true },
|
|
{ menu="Model/Generate map", submenu="generate_mesh_normal_map", description="Mesh normal" },
|
|
{ menu="Model/Generate map", submenu="generate_inverse_uv_map", description="Inverse UV" },
|
|
{ menu="Environment", submenu="environment_list", description="Select" }
|
|
]
|
|
|
|
var _mouse_start_position := Vector2.ZERO
|
|
|
|
|
|
func _ready() -> void:
|
|
ui = get_node(ui_path)
|
|
get_node("/root/MainWindow").create_menus(MENU, self, ui)
|
|
$MaterialPreview/Preview3d/ObjectRotate.play("rotate")
|
|
_on_Environment_item_selected(0)
|
|
|
|
func create_menu_model_list(menu : PopupMenu) -> void:
|
|
menu.clear()
|
|
for i in objects.get_child_count():
|
|
var o = objects.get_child(i)
|
|
menu.add_item(o.name, i)
|
|
if !menu.is_connected("id_pressed", self, "_on_Model_item_selected"):
|
|
menu.connect("id_pressed", self, "_on_Model_item_selected")
|
|
|
|
func create_menu_environment_list(menu : PopupMenu) -> void:
|
|
menu.clear()
|
|
for i in environments.get_child_count():
|
|
var e = environments.get_child(i)
|
|
menu.add_item(e.name, i)
|
|
if !menu.is_connected("id_pressed", self, "_on_Environment_item_selected"):
|
|
menu.connect("id_pressed", self, "_on_Environment_item_selected")
|
|
|
|
func _on_Model_item_selected(id) -> void:
|
|
if id == objects.get_child_count()-1:
|
|
var dialog = FileDialog.new()
|
|
add_child(dialog)
|
|
dialog.rect_min_size = Vector2(500, 500)
|
|
dialog.access = FileDialog.ACCESS_FILESYSTEM
|
|
dialog.mode = FileDialog.MODE_OPEN_FILE
|
|
dialog.add_filter("*.obj;OBJ model File")
|
|
if get_node("/root/MainWindow").config_cache.has_section_key("path", "mesh"):
|
|
dialog.current_dir = get_node("/root/MainWindow").config_cache.get_value("path", "mesh")
|
|
dialog.connect("file_selected", self, "do_load_custom_mesh")
|
|
dialog.connect("popup_hide", dialog, "queue_free")
|
|
dialog.popup_centered()
|
|
else:
|
|
select_object(id)
|
|
|
|
func do_load_custom_mesh(file_path) -> void:
|
|
get_node("/root/MainWindow").config_cache.set_value("path", "mesh", file_path.get_base_dir())
|
|
var id = objects.get_child_count()-1
|
|
var mesh = $ObjLoader.load_obj_file(file_path)
|
|
if mesh != null:
|
|
var object : MeshInstance = objects.get_child(id)
|
|
object.mesh = mesh
|
|
object.set_surface_material(0, SpatialMaterial.new())
|
|
select_object(id)
|
|
|
|
func select_object(id) -> void:
|
|
current_object.visible = false
|
|
current_object = objects.get_child(id)
|
|
current_object.visible = true
|
|
emit_signal("need_update", [ self ])
|
|
|
|
func _on_Environment_item_selected(id) -> void:
|
|
current_environment.visible = false
|
|
current_environment = environments.get_child(id)
|
|
$MaterialPreview/Preview3d/CameraPivot/Camera.set_environment(current_environment.environment)
|
|
current_environment.visible = true
|
|
|
|
func configure_model() -> void:
|
|
var popup = preload("res://material_maker/panels/preview_3d/mesh_config_popup.tscn").instance()
|
|
add_child(popup)
|
|
popup.configure_mesh(current_object)
|
|
|
|
func rotate_model(button_pressed = null) -> bool:
|
|
var object_rotate = $MaterialPreview/Preview3d/ObjectRotate
|
|
if button_pressed is bool:
|
|
if button_pressed:
|
|
object_rotate.play("rotate")
|
|
else:
|
|
object_rotate.stop(false)
|
|
return object_rotate.is_playing()
|
|
|
|
func get_materials() -> Array:
|
|
if current_object != null and current_object.get_surface_material(0) != null:
|
|
return [ current_object.get_surface_material(0) ]
|
|
return []
|
|
|
|
func on_gui_input(event) -> void:
|
|
if event is InputEventMouseButton:
|
|
$MaterialPreview/Preview3d/ObjectRotate.stop(false)
|
|
match event.button_index:
|
|
BUTTON_WHEEL_UP:
|
|
camera.translation.z = clamp(
|
|
camera.translation.z / (1.01 if event.shift else 1.1),
|
|
CAMERA_DISTANCE_MIN,
|
|
CAMERA_DISTANCE_MAX
|
|
)
|
|
BUTTON_WHEEL_DOWN:
|
|
camera.translation.z = clamp(
|
|
camera.translation.z * (1.01 if event.shift else 1.1),
|
|
CAMERA_DISTANCE_MIN,
|
|
CAMERA_DISTANCE_MAX
|
|
)
|
|
BUTTON_LEFT, BUTTON_RIGHT:
|
|
var mask := Input.get_mouse_button_mask()
|
|
var lpressed := mask & BUTTON_MASK_LEFT
|
|
var rpressed := mask & BUTTON_MASK_RIGHT
|
|
if event.pressed and ((lpressed and not rpressed) or (not lpressed and rpressed)): # xor
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
_mouse_start_position = event.global_position
|
|
elif not lpressed and not rpressed:
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN) # allow and hide cursor warp
|
|
Input.warp_mouse_position(_mouse_start_position)
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
elif event is InputEventMouseMotion:
|
|
var motion = 0.01*event.relative
|
|
if abs(motion.y) > abs(motion.x):
|
|
motion.x = 0
|
|
else:
|
|
motion.y = 0
|
|
var camera_basis = camera.global_transform.basis
|
|
if event.shift:
|
|
if event.button_mask & BUTTON_MASK_LEFT:
|
|
objects.rotate(camera_basis.x.normalized(), motion.y)
|
|
objects.rotate(camera_basis.y.normalized(), motion.x)
|
|
elif event.button_mask & BUTTON_MASK_RIGHT:
|
|
objects.rotate(camera_basis.z.normalized(), motion.x)
|
|
else:
|
|
if event.button_mask & BUTTON_MASK_LEFT:
|
|
camera_stand.rotate(camera_basis.x.normalized(), -motion.y)
|
|
camera_stand.rotate(camera_basis.y.normalized(), -motion.x)
|
|
elif event.button_mask & BUTTON_MASK_RIGHT:
|
|
camera_stand.rotate(camera_basis.z.normalized(), -motion.x)
|
|
|
|
|
|
func generate_map(generate_function : String, size : int) -> void:
|
|
var dialog = FileDialog.new()
|
|
add_child(dialog)
|
|
dialog.rect_min_size = Vector2(500, 500)
|
|
dialog.access = FileDialog.ACCESS_FILESYSTEM
|
|
dialog.mode = FileDialog.MODE_SAVE_FILE
|
|
dialog.add_filter("*.png;PNG image File")
|
|
dialog.add_filter("*.exr;EXR image File")
|
|
if get_node("/root/MainWindow").config_cache.has_section_key("path", "maps"):
|
|
dialog.current_dir = get_node("/MainWindow").config_cache.get_value("path", "maps")
|
|
dialog.connect("file_selected", self, generate_function, [ size ])
|
|
dialog.connect("popup_hide", dialog, "queue_free")
|
|
dialog.popup_centered()
|
|
|
|
func do_generate_map(file_name : String, map : String, size : int) -> void:
|
|
var mesh_normal_mapper = load("res://material_maker/panels/preview_3d/map_renderer.tscn").instance()
|
|
add_child(mesh_normal_mapper)
|
|
var id = objects.get_child_count()-1
|
|
var object : MeshInstance = objects.get_child(id)
|
|
var result = mesh_normal_mapper.gen(object.mesh, map, file_name, size)
|
|
while result is GDScriptFunctionState:
|
|
result = yield(result, "completed")
|
|
mesh_normal_mapper.queue_free()
|
|
OS.clipboard = "{\"name\":\"image\",\"parameters\":{\"image\":\"%s\"},\"type\":\"image\"}" % file_name
|
|
|
|
func create_menu_map(menu : PopupMenu, function : String) -> void:
|
|
menu.clear()
|
|
for i in range(5):
|
|
menu.add_item(str(256 << i)+"x"+str(256 << i), i)
|
|
if !menu.is_connected("id_pressed", self, function):
|
|
menu.connect("id_pressed", self, function)
|
|
|
|
func create_menu_generate_mesh_normal_map(menu) -> void:
|
|
create_menu_map(menu, "generate_mesh_normal_map")
|
|
|
|
func generate_mesh_normal_map(i : int) -> void:
|
|
generate_map("do_generate_mesh_normal_map", 256 << i)
|
|
|
|
func do_generate_mesh_normal_map(file_name : String, size : int) -> void:
|
|
do_generate_map(file_name, "mesh_normal", size)
|
|
|
|
func create_menu_generate_inverse_uv_map(menu) -> void:
|
|
create_menu_map(menu, "generate_inverse_uv_map")
|
|
|
|
func generate_inverse_uv_map(i : int) -> void:
|
|
generate_map("do_generate_inverse_uv_map", 256 << i)
|
|
|
|
func do_generate_inverse_uv_map(file_name : String, size : int) -> void:
|
|
do_generate_map(file_name, "inv_uv", size)
|