209 lines
5.6 KiB
GDScript
209 lines
5.6 KiB
GDScript
tool
|
|
extends WindowDialog
|
|
|
|
const HTerrainData = preload("../../hterrain_data.gd")
|
|
const Errors = preload("../../util/errors.gd")
|
|
const Util = preload("../../util/util.gd")
|
|
const Logger = preload("../../util/logger.gd")
|
|
|
|
const FORMAT_RH = 0
|
|
const FORMAT_R16 = 1
|
|
const FORMAT_PNG8 = 2
|
|
const FORMAT_EXRH = 3
|
|
const FORMAT_COUNT = 4
|
|
|
|
onready var _output_path_line_edit := $VB/Grid/OutputPath/HeightmapPathLineEdit as LineEdit
|
|
onready var _format_selector := $VB/Grid/FormatSelector as OptionButton
|
|
onready var _height_range_min_spinbox := $VB/Grid/HeightRange/HeightRangeMin as SpinBox
|
|
onready var _height_range_max_spinbox := $VB/Grid/HeightRange/HeightRangeMax as SpinBox
|
|
onready var _export_button := $VB/Buttons/ExportButton as Button
|
|
onready var _show_in_explorer_checkbox := $VB/ShowInExplorerCheckbox as CheckBox
|
|
|
|
var _terrain = null
|
|
var _file_dialog : EditorFileDialog = null
|
|
var _format_names := []
|
|
var _format_extensions := []
|
|
var _logger = Logger.get_for(self)
|
|
|
|
|
|
func _ready():
|
|
_format_names.resize(FORMAT_COUNT)
|
|
_format_extensions.resize(FORMAT_COUNT)
|
|
|
|
_format_names[FORMAT_RH] = "16-bit RAW float (native)"
|
|
_format_names[FORMAT_R16] = "16-bit RAW unsigned"
|
|
_format_names[FORMAT_PNG8] = "8-bit PNG"
|
|
_format_names[FORMAT_EXRH] = "16-bit float greyscale EXR (native)"
|
|
|
|
_format_extensions[FORMAT_RH] = "raw"
|
|
_format_extensions[FORMAT_R16] = "raw"
|
|
_format_extensions[FORMAT_PNG8] = "png"
|
|
_format_extensions[FORMAT_EXRH] = "exr"
|
|
|
|
if not Util.is_in_edited_scene(self):
|
|
for i in len(_format_names):
|
|
_format_selector.get_popup().add_item(_format_names[i], i)
|
|
|
|
|
|
func setup_dialogs(base_control):
|
|
assert(_file_dialog == null)
|
|
var fd := EditorFileDialog.new()
|
|
fd.mode = EditorFileDialog.MODE_SAVE_FILE
|
|
fd.resizable = true
|
|
fd.access = EditorFileDialog.ACCESS_FILESYSTEM
|
|
fd.connect("file_selected", self, "_on_FileDialog_file_selected")
|
|
base_control.add_child(fd)
|
|
_file_dialog = fd
|
|
|
|
_update_file_extension()
|
|
|
|
|
|
func set_terrain(terrain):
|
|
_terrain = terrain
|
|
|
|
|
|
func _exit_tree():
|
|
if _file_dialog != null:
|
|
_file_dialog.queue_free()
|
|
_file_dialog = null
|
|
|
|
|
|
func _on_FileDialog_file_selected(fpath):
|
|
_output_path_line_edit.text = fpath
|
|
|
|
|
|
func _auto_adjust_height_range():
|
|
assert(_terrain != null)
|
|
assert(_terrain.get_data() != null)
|
|
var aabb = _terrain.get_data().get_aabb()
|
|
_height_range_min_spinbox.value = aabb.position.y
|
|
_height_range_max_spinbox.value = aabb.position.y + aabb.size.y
|
|
|
|
|
|
func _export() -> bool:
|
|
assert(_terrain != null)
|
|
assert(_terrain.get_data() != null)
|
|
var heightmap: Image = _terrain.get_data().get_image(HTerrainData.CHANNEL_HEIGHT)
|
|
var fpath := _output_path_line_edit.text.strip_edges()
|
|
|
|
# TODO Is `selected` an ID or an index? I need an ID, it works by chance for now.
|
|
var format := _format_selector.selected
|
|
|
|
var height_min := _height_range_min_spinbox.value
|
|
var height_max := _height_range_max_spinbox.value
|
|
|
|
if height_min == height_max:
|
|
_logger.error("Cannot export, height range is zero")
|
|
return false
|
|
|
|
if height_min > height_max:
|
|
_logger.error("Cannot export, height min is greater than max")
|
|
return false
|
|
|
|
var save_error := OK
|
|
|
|
if format == FORMAT_PNG8:
|
|
var hscale = 1.0 / (height_max - height_min)
|
|
var im = Image.new()
|
|
im.create(heightmap.get_width(), heightmap.get_height(), false, Image.FORMAT_R8)
|
|
|
|
im.lock()
|
|
heightmap.lock()
|
|
|
|
for y in heightmap.get_height():
|
|
for x in heightmap.get_width():
|
|
var h = clamp((heightmap.get_pixel(x, y).r - height_min) * hscale, 0.0, 1.0)
|
|
im.set_pixel(x, y, Color(h, h, h))
|
|
|
|
im.unlock()
|
|
heightmap.unlock()
|
|
|
|
save_error = im.save_png(fpath)
|
|
|
|
elif format == FORMAT_EXRH:
|
|
save_error = heightmap.save_exr(fpath, true)
|
|
|
|
else:
|
|
var f = File.new()
|
|
var err = f.open(fpath, File.WRITE)
|
|
if err != OK:
|
|
_print_file_error(fpath, err)
|
|
return false
|
|
|
|
if format == FORMAT_RH:
|
|
# Native format
|
|
f.store_buffer(heightmap.get_data())
|
|
|
|
elif format == FORMAT_R16:
|
|
var hscale = 65535.0 / (height_max - height_min)
|
|
heightmap.lock()
|
|
for y in heightmap.get_height():
|
|
for x in heightmap.get_width():
|
|
var h = int((heightmap.get_pixel(x, y).r - height_min) * hscale)
|
|
if h < 0:
|
|
h = 0
|
|
elif h > 65535:
|
|
h = 65535
|
|
if x % 50 == 0:
|
|
_logger.debug(str(h))
|
|
f.store_16(h)
|
|
heightmap.unlock()
|
|
|
|
f.close()
|
|
|
|
if save_error == OK:
|
|
_logger.debug("Exported heightmap as \"{0}\"".format([fpath]))
|
|
return true
|
|
else:
|
|
_print_file_error(fpath, save_error)
|
|
return false
|
|
|
|
|
|
func _update_file_extension():
|
|
if _format_selector.selected == -1:
|
|
_format_selector.selected = 0
|
|
# This recursively calls the current function
|
|
return
|
|
|
|
# TODO Is `selected` an ID or an index? I need an ID, it works by chance for now.
|
|
var format = _format_selector.selected
|
|
|
|
var ext = _format_extensions[format]
|
|
_file_dialog.clear_filters()
|
|
_file_dialog.add_filter(str("*.", ext, " ; ", ext.to_upper(), " files"))
|
|
|
|
var fpath = _output_path_line_edit.text.strip_edges()
|
|
if fpath != "":
|
|
_output_path_line_edit.text = str(fpath.get_basename(), ".", ext)
|
|
|
|
|
|
func _print_file_error(fpath, err):
|
|
_logger.error("Could not save path {0}, error: {1}" \
|
|
.format([fpath, Errors.get_message(err)]))
|
|
|
|
|
|
func _on_CancelButton_pressed():
|
|
hide()
|
|
|
|
|
|
func _on_ExportButton_pressed():
|
|
if _export():
|
|
hide()
|
|
if _show_in_explorer_checkbox.pressed:
|
|
OS.shell_open(_output_path_line_edit.text.strip_edges().get_base_dir())
|
|
|
|
|
|
func _on_HeightmapPathLineEdit_text_changed(new_text):
|
|
_export_button.disabled = (new_text.strip_edges() == "")
|
|
|
|
|
|
func _on_HeightmapPathBrowseButton_pressed():
|
|
_file_dialog.popup_centered_ratio()
|
|
|
|
|
|
func _on_FormatSelector_item_selected(ID):
|
|
_update_file_extension()
|
|
|
|
|
|
func _on_HeightRangeAutoButton_pressed():
|
|
_auto_adjust_height_range()
|