983 lines
36 KiB
GDScript
983 lines
36 KiB
GDScript
@tool
|
|
extends Control
|
|
class_name CloudsEditorController
|
|
|
|
@export_category("Driver Tools")
|
|
@export var CloudsStatusLabel : Label
|
|
@export var CloudsActiveToggle : CheckButton
|
|
@export var CloudsDriverRefresh : Button
|
|
@export var CloudsDriverAccordianButton : AccordionButton
|
|
@export_category("Mask Tools")
|
|
@export var UseMaskToggle : CheckButton
|
|
@export var MaskStatusLabel : Label
|
|
@export var MaskFilePath : LineEdit
|
|
@export var MaskResolution : SpinBox
|
|
@export var MaskWidth : SpinBox
|
|
@export_category("Draw Tools")
|
|
@export var DrawWeightEnable : TextureButton
|
|
@export var DrawColorEnable : TextureButton
|
|
@export var DrawColorPicker : ColorPicker
|
|
|
|
@export var DrawTools : Control
|
|
@export var DrawSharpness : HSlider
|
|
@export var DrawStrength : HSlider
|
|
|
|
@export var compute_shader : RDShaderFile
|
|
@export var DrawingColor : Color
|
|
@export var InvertedDrawingColor : Color
|
|
|
|
@export_range(100,50000,50) var DefaultBrushSize : float = 1000.0
|
|
@export_range(100,50000,50) var DefaultCloudsHeight : float = 2000.0
|
|
|
|
var driver : SunshineCloudsDriverGD
|
|
|
|
var currentRoot : Node
|
|
|
|
var currentDrawingMask : RID = RID()
|
|
|
|
enum DRAWINGMODE {none, weight, color, setValue}
|
|
|
|
var drawScale : float
|
|
var currentCloudsHeight : float
|
|
var currentDrawMode : DRAWINGMODE = DRAWINGMODE.none
|
|
var drawingCurrently : bool = false
|
|
var drawInverted : bool = false
|
|
var drawBrushToolMaterial : BaseMaterial3D = preload("res://addons/SunshineClouds2/Dock/Materials/DrawBrushToolsMaterial.tres")
|
|
var drawBrushToolPrefab : PackedScene = preload("res://addons/SunshineClouds2/Dock/CloudsDrawBrush.tscn")
|
|
var drawBrushTool : MeshInstance3D
|
|
|
|
#region Compute Variables
|
|
var computeEnabled : bool = false
|
|
var rd : RenderingDevice
|
|
var shader : RID = RID()
|
|
var pipeline : RID = RID()
|
|
|
|
var uniform_set : RID
|
|
var push_constants : PackedByteArray
|
|
|
|
var last_image_data : PackedByteArray = []
|
|
#endregion
|
|
|
|
var pause_updates : bool = false
|
|
|
|
|
|
func _enter_tree() -> void:
|
|
drawScale = DefaultBrushSize
|
|
|
|
func _notification(what):
|
|
if what == NOTIFICATION_PREDELETE and is_instance_valid(self):
|
|
RenderingServer.call_on_render_thread(ClearCompute)
|
|
|
|
func _process(delta: float) -> void:
|
|
|
|
if (currentDrawMode != DRAWINGMODE.none):
|
|
|
|
var selection = EditorInterface.get_selection()
|
|
if (selection.get_selected_nodes().size() == 0):
|
|
if (driver != null):
|
|
selection.add_node(driver)
|
|
|
|
if (currentDrawMode == DRAWINGMODE.color):
|
|
drawBrushToolMaterial.albedo_color = DrawColorPicker.color
|
|
|
|
if (drawingCurrently):
|
|
|
|
RenderingServer.call_on_render_thread(ExecuteCompute.bindv([delta, false, Color.WHITE]))
|
|
|
|
func InitialSceneLoad() -> void:
|
|
var sceneRoot = await FindSceneNode()
|
|
SceneChanged(sceneRoot)
|
|
print("initial scene load")
|
|
|
|
await get_tree().create_timer(0.5).timeout
|
|
var version_info = Engine.get_version_info()
|
|
|
|
var file = FileAccess.open("res://addons/SunshineClouds2/CloudsInc.txt", FileAccess.READ_WRITE)
|
|
var content = file.get_as_text()
|
|
var major_index = content.find("GODOT_VERSION_MAJOR") + 20
|
|
var minor_index = content.find("GODOT_VERSION_MINOR") + 20
|
|
|
|
if content[major_index] != str(version_info.major) || content[minor_index] != str(version_info.minor):
|
|
print("Version conflict, updating and reimporting...")
|
|
content[major_index] = str(version_info.major)
|
|
content[minor_index] = str(version_info.minor)
|
|
file.store_string(content)
|
|
file.close()
|
|
|
|
EditorInterface.get_resource_filesystem().reimport_files(["res://addons/SunshineClouds2/SunshineCloudsCompute.glsl", "res://addons/SunshineClouds2/SunshineCloudsPostCompute.glsl", "res://addons/SunshineClouds2/SunshineCloudsPreCompute.glsl"])
|
|
await get_tree().create_timer(0.1).timeout
|
|
if driver != null && driver.clouds_resource != null:
|
|
driver.clouds_resource.refresh_compute()
|
|
|
|
print("Version change may cause some errors during first load, these should not impact functionality, if there is impacted functionality please report it to the creator of the plugin.")
|
|
print("Version updated, launching normally.")
|
|
else:
|
|
print("Version correct, launching normally.")
|
|
file.close()
|
|
|
|
|
|
func RefreshSceneNode() -> void:
|
|
var sceneRoot = await FindSceneNode()
|
|
|
|
SceneChanged(sceneRoot)
|
|
|
|
func FindSceneNode() -> Node:
|
|
var editorInterface = EditorPlugin.new().get_editor_interface()
|
|
var sceneRoot = editorInterface.get_edited_scene_root()
|
|
var iterationcount: int = 300 #30 seconds of checking.
|
|
while sceneRoot == null && iterationcount > 0:
|
|
await get_tree().create_timer(0.1).timeout
|
|
iterationcount -= 1
|
|
sceneRoot = editorInterface.get_edited_scene_root()
|
|
|
|
return sceneRoot
|
|
|
|
func SceneChanged(scene_root : Node):
|
|
|
|
pause_updates = true
|
|
DrawWeightEnable.button_pressed = false
|
|
DrawColorEnable.button_pressed = false
|
|
last_image_data = []
|
|
DisableDrawMode()
|
|
|
|
currentRoot = scene_root
|
|
driver = RetrieveCloudsDriver(scene_root)
|
|
if (driver != null && driver.clouds_resource != null):
|
|
driver.clouds_resource.maskDrawnRid = RID()
|
|
|
|
MaskWidth.value = driver.clouds_resource.mask_width_km
|
|
UseMaskToggle.button_pressed = driver.clouds_resource.extra_large_used_as_mask
|
|
|
|
if ResourceLoader.exists(MaskFilePath.text):
|
|
var image = ResourceLoader.load(MaskFilePath.text) as Image
|
|
if image:
|
|
print("retrieved mask scale")
|
|
MaskResolution.value = image.get_width()
|
|
pause_updates = false
|
|
UpdateStatusDisplay()
|
|
|
|
func RetrieveCloudsDriver(scene_root : Node) -> SunshineCloudsDriverGD:
|
|
if (scene_root != null):
|
|
for child in scene_root.get_children():
|
|
if child is SunshineCloudsDriverGD:
|
|
return child
|
|
|
|
var newDriver = RetrieveCloudsDriver(child)
|
|
if (newDriver):
|
|
return newDriver
|
|
|
|
return null
|
|
|
|
func UpdateStatusDisplay():
|
|
|
|
if (driver != null):
|
|
CloudsActiveToggle.disabled = false
|
|
CloudsActiveToggle.button_pressed = driver.update_continuously
|
|
CloudsDriverRefresh.visible = false
|
|
CloudsStatusLabel.text = "Clouds present"
|
|
|
|
if ResourceLoader.exists(MaskFilePath.text):
|
|
MaskStatusLabel.text = "Mask Detected: " + MaskFilePath.text
|
|
DrawTools.visible = true
|
|
else:
|
|
MaskStatusLabel.text = "Mask Not Found."
|
|
DrawTools.visible = false
|
|
|
|
else:
|
|
CloudsActiveToggle.disabled = true
|
|
CloudsActiveToggle.button_pressed = false
|
|
CloudsDriverRefresh.visible = true
|
|
DrawTools.visible = false
|
|
CloudsDriverAccordianButton.Open()
|
|
CloudsStatusLabel.text = "Clouds not present"
|
|
|
|
|
|
if driver != null && driver.clouds_resource != null:
|
|
UseMaskToggle.disabled = false
|
|
else:
|
|
UseMaskToggle.disabled = true
|
|
UseMaskToggle.button_pressed = false
|
|
|
|
|
|
func UpdateMaskSettings():
|
|
if (pause_updates):
|
|
return
|
|
print("Update mask settings")
|
|
if (driver != null && driver.clouds_resource != null):
|
|
driver.clouds_resource.mask_width_km = MaskWidth.value
|
|
driver.clouds_resource.extra_large_used_as_mask = UseMaskToggle.button_pressed
|
|
if (!UseMaskToggle.button_pressed):
|
|
driver.clouds_resource.extra_large_noise_patterns = ResourceLoader.load("res://addons/SunshineClouds2/NoiseTextures/ExtraLargeScaleNoise.tres")
|
|
elif ResourceLoader.exists(MaskFilePath.text):
|
|
driver.clouds_resource.extra_large_noise_patterns = ResourceLoader.load(MaskFilePath.text)
|
|
|
|
InitializeMaskTexture()
|
|
|
|
func InitializeMaskTexture():
|
|
#if (driver == null):
|
|
#return
|
|
|
|
if not rd:
|
|
rd = RenderingServer.get_rendering_device()
|
|
if not rd:
|
|
return
|
|
#currentDrawingMask = driver.clouds_resource.mask_rid
|
|
#var useDriverData : bool = driver != null && driver.clouds_resource != null
|
|
#
|
|
print("initializing mask")
|
|
if ResourceLoader.exists(MaskFilePath.text):
|
|
print("loading mask")
|
|
var image = ResourceLoader.load(MaskFilePath.text) as CompressedTexture2D
|
|
if (!image || image.get_width() != MaskResolution.value):
|
|
print(MaskFilePath.text)
|
|
print("mask incorrect size found size:", image.get_width(), " desired:", MaskResolution.value)
|
|
image = Image.create(MaskResolution.value, MaskResolution.value, false, Image.FORMAT_RGBAF)
|
|
image.clear_mipmaps()
|
|
image.save_exr(MaskFilePath.text)
|
|
|
|
var editorFileSystem := EditorInterface.get_resource_filesystem()
|
|
editorFileSystem.scan()
|
|
else:
|
|
var image = Image.create(MaskResolution.value, MaskResolution.value, false, Image.FORMAT_RGBAF)
|
|
image.clear_mipmaps()
|
|
image.save_exr(MaskFilePath.text)
|
|
|
|
var editorFileSystem := EditorInterface.get_resource_filesystem()
|
|
editorFileSystem.scan()
|
|
|
|
|
|
|
|
#driver.clouds_resource.mask_rid = currentDrawingMask
|
|
#driver.clouds_resource.extra_large_noise_patterns = ResourceLoader.load(MaskFilePath.text)
|
|
#driver.clouds_resource.last_size = Vector2i.ZERO
|
|
|
|
RenderingServer.call_on_render_thread(InitializeCompute)
|
|
call_deferred("UpdateStatusDisplay")
|
|
|
|
#region Draw mode
|
|
|
|
#region Compute
|
|
|
|
func InitializeCompute():
|
|
computeEnabled = false
|
|
#if driver == null:
|
|
#return
|
|
|
|
#currentDrawingMask = driver.clouds_resource.mask_rid
|
|
#if !currentDrawingMask.is_valid():
|
|
#return
|
|
|
|
if not rd:
|
|
rd = RenderingServer.get_rendering_device()
|
|
if not rd:
|
|
computeEnabled = false
|
|
printerr("No rendering device on load.")
|
|
return
|
|
ClearCompute()
|
|
if not compute_shader:
|
|
compute_shader = ResourceLoader.load("res://addons/SunshineClouds2/Dock/MaskDrawingCompute.glsl")
|
|
|
|
if not compute_shader:
|
|
computeEnabled = false
|
|
printerr("No Shader found for drawing tool.")
|
|
ClearCompute()
|
|
return
|
|
|
|
var shader_spirv = compute_shader.get_spirv()
|
|
shader = rd.shader_create_from_spirv(shader_spirv)
|
|
if shader.is_valid():
|
|
pipeline = rd.compute_pipeline_create(shader)
|
|
else:
|
|
computeEnabled = false
|
|
printerr("Shader failed to compile.")
|
|
ClearCompute()
|
|
return
|
|
|
|
var uniforms_array : Array[RDUniform] = []
|
|
|
|
var newFormat : RDTextureFormat = RDTextureFormat.new()
|
|
newFormat.format = RenderingDevice.DATA_FORMAT_R32G32B32A32_SFLOAT
|
|
newFormat.height = MaskResolution.value
|
|
newFormat.width = MaskResolution.value
|
|
newFormat.usage_bits = RenderingDevice.TEXTURE_USAGE_STORAGE_BIT | RenderingDevice.TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice.TEXTURE_USAGE_CAN_COPY_FROM_BIT
|
|
|
|
var image : Image
|
|
if ResourceLoader.exists(MaskFilePath.text):
|
|
image = (ResourceLoader.load(MaskFilePath.text) as CompressedTexture2D).get_image()
|
|
|
|
if image == null:
|
|
image = Image.create(MaskResolution.value, MaskResolution.value, false, Image.FORMAT_RGBAF)
|
|
|
|
currentDrawingMask = rd.texture_create(newFormat, RDTextureView.new(), [image.get_data()])
|
|
|
|
if (driver != null && driver.clouds_resource != null):
|
|
driver.clouds_resource.update_mask(currentDrawingMask)
|
|
|
|
var mask_uniform = RDUniform.new()
|
|
mask_uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_IMAGE
|
|
mask_uniform.binding = 0
|
|
mask_uniform.add_id(currentDrawingMask)
|
|
uniforms_array.append(mask_uniform)
|
|
|
|
uniform_set = rd.uniform_set_create(uniforms_array, shader, 0)
|
|
computeEnabled = true
|
|
|
|
func ClearCompute():
|
|
if rd:
|
|
if shader.is_valid():
|
|
rd.free_rid(shader)
|
|
shader = RID()
|
|
|
|
if currentDrawingMask.is_valid():
|
|
rd.free_rid(currentDrawingMask)
|
|
currentDrawingMask = RID()
|
|
|
|
func ExecuteCompute(delta : float, setvalue : bool, setvalueColor : Color):
|
|
if (!computeEnabled):
|
|
return
|
|
|
|
var resolution : float = MaskResolution.value
|
|
var drawPosition : Vector2 = Vector2.ZERO
|
|
var drawRadius = 0.0
|
|
|
|
if (!setvalue):
|
|
drawPosition = Vector2(drawBrushTool.global_position.x, drawBrushTool.global_position.z)
|
|
drawPosition = (drawPosition / (MaskWidth.value * 1000.0)) * resolution
|
|
drawPosition += Vector2(resolution * 0.5, resolution * 0.5)
|
|
|
|
drawRadius = (drawBrushTool.scale.x / (MaskWidth.value * 1000.0)) * resolution
|
|
|
|
var groups = ceil(resolution / 32) + 1
|
|
var drawSharpness = DrawSharpness.value
|
|
var drawStrength = DrawStrength.value * delta
|
|
if (drawInverted):
|
|
drawStrength = -drawStrength
|
|
|
|
var editingtype : float = 0.0
|
|
if setvalue:
|
|
editingtype = 2.0
|
|
elif currentDrawMode == DRAWINGMODE.color:
|
|
editingtype = 1.0
|
|
|
|
var ms = StreamPeerBuffer.new()
|
|
ms.put_float(drawPosition.x)
|
|
ms.put_float(drawPosition.y)
|
|
ms.put_float(drawRadius)
|
|
ms.put_float(drawSharpness)
|
|
|
|
ms.put_float(drawStrength)
|
|
ms.put_float(editingtype)
|
|
ms.put_float(resolution)
|
|
ms.put_float(0.0)
|
|
|
|
if (setvalue):
|
|
ms.put_float(setvalueColor.r)
|
|
ms.put_float(setvalueColor.g)
|
|
ms.put_float(setvalueColor.b)
|
|
ms.put_float(setvalueColor.a)
|
|
else:
|
|
ms.put_float(DrawColorPicker.color.r)
|
|
ms.put_float(DrawColorPicker.color.g)
|
|
ms.put_float(DrawColorPicker.color.b)
|
|
ms.put_float(0.0)
|
|
|
|
push_constants = ms.get_data_array()
|
|
|
|
var compute_list = rd.compute_list_begin()
|
|
rd.compute_list_bind_compute_pipeline(compute_list, pipeline)
|
|
rd.compute_list_bind_uniform_set(compute_list, uniform_set, 0)
|
|
rd.compute_list_set_push_constant(compute_list, push_constants, push_constants.size())
|
|
rd.compute_list_dispatch(compute_list, groups, groups, 1)
|
|
rd.compute_list_end()
|
|
|
|
|
|
await RenderingServer.frame_post_draw
|
|
|
|
rd.texture_get_data_async(currentDrawingMask, 0, CompleteRetreval)
|
|
|
|
func CompleteRetreval(data):
|
|
last_image_data = data
|
|
#for byte in data:
|
|
#print(byte)
|
|
#print("RetrevalComplete ", data)
|
|
#var image = Image.create_from_data(MaskResolution.value, MaskResolution.value, false, Image.FORMAT_RGBAF, data)
|
|
##rd.texture_update(RenderingServer.texture_get_rd_texture(currentMask.get_rid()),0, data)
|
|
#image.save_png(MaskFilePath.text)
|
|
|
|
#var editorFileSystem := EditorInterface.get_resource_filesystem()
|
|
#editorFileSystem.scan()
|
|
|
|
#endregion
|
|
|
|
func IterateCursorLocation(viewport_camera: Camera3D, event:InputEventMouse):
|
|
if (is_instance_valid(driver) && driver.clouds_resource != null):
|
|
currentCloudsHeight = (driver.clouds_resource.cloud_floor + driver.clouds_resource.cloud_ceiling) / 2.0
|
|
else:
|
|
currentCloudsHeight = DefaultCloudsHeight
|
|
var ray_origin = viewport_camera.project_ray_origin(event.position)
|
|
var ray_dir = viewport_camera.project_ray_normal(event.position)
|
|
|
|
var result : float = RetrieveTravelDistance(ray_origin, ray_dir)
|
|
if (result == -1.0):
|
|
drawBrushTool.visible = false
|
|
else:
|
|
drawBrushTool.visible = true
|
|
drawBrushTool.global_position = ray_origin + ray_dir * result
|
|
drawBrushTool.global_position.y = driver.clouds_resource.cloud_floor
|
|
|
|
func BeginCursorDraw():
|
|
drawingCurrently = true
|
|
|
|
func EndCursorDraw():
|
|
drawingCurrently = false
|
|
|
|
func ScaleDrawingCircleUp():
|
|
drawScale = min(drawScale + (drawScale * 0.1), 100000.0)
|
|
SetDrawScale()
|
|
|
|
func ScaleDrawingCircleDown():
|
|
drawScale = max(drawScale - (drawScale * 0.1), 100.0)
|
|
SetDrawScale()
|
|
|
|
func DrawModeCancel():
|
|
DrawWeightEnable.button_pressed = false
|
|
DrawColorEnable.button_pressed = false
|
|
DisableDrawMode()
|
|
|
|
|
|
func SetDrawScale():
|
|
if driver != null && driver.clouds_resource != null:
|
|
drawBrushTool.scale = Vector3(drawScale, driver.clouds_resource.cloud_ceiling - driver.clouds_resource.cloud_floor, drawScale)
|
|
else:
|
|
drawBrushTool.scale = Vector3(drawScale, 1000.0, drawScale)
|
|
|
|
#region Draw Mode Toggles
|
|
|
|
func FloodFill():
|
|
var resultColor : Color = DrawColorPicker.color
|
|
resultColor.a = DrawStrength.value / DrawStrength.max_value
|
|
RenderingServer.call_on_render_thread(ExecuteCompute.bindv([0.0, true, resultColor]))
|
|
await get_tree().create_timer(0.2).timeout
|
|
call_deferred("DisableDrawMode")
|
|
|
|
func DrawWeightToggled():
|
|
DrawColorEnable.button_pressed = false
|
|
|
|
if DrawWeightEnable.button_pressed && EnableDrawMode():
|
|
currentDrawMode = DRAWINGMODE.weight
|
|
else:
|
|
DrawWeightEnable.button_pressed = false
|
|
|
|
func DrawColorToggled():
|
|
DrawWeightEnable.button_pressed = false
|
|
|
|
if DrawColorEnable.button_pressed && EnableDrawMode():
|
|
currentDrawMode = DRAWINGMODE.color
|
|
else:
|
|
DrawColorEnable.button_pressed = false
|
|
|
|
func EnableDrawMode() -> bool:
|
|
if (!computeEnabled):
|
|
InitializeMaskTexture()
|
|
|
|
if (!is_instance_valid(currentRoot)):
|
|
return false
|
|
drawBrushToolMaterial.albedo_color = DrawingColor
|
|
if (!is_instance_valid(drawBrushTool)):
|
|
drawBrushTool = drawBrushToolPrefab.instantiate() as MeshInstance3D
|
|
currentRoot.add_child(drawBrushTool)
|
|
SetDrawScale()
|
|
|
|
return true
|
|
|
|
func DisableDrawMode():
|
|
DrawColorEnable.button_pressed = false
|
|
DrawWeightEnable.button_pressed = false
|
|
currentDrawMode = DRAWINGMODE.none
|
|
drawInverted = false
|
|
if (drawingCurrently):
|
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
|
drawingCurrently = false
|
|
|
|
if (is_instance_valid(drawBrushTool)):
|
|
drawBrushTool.queue_free()
|
|
drawBrushTool = null
|
|
|
|
if (last_image_data.size() > 0):
|
|
print("Saved image to disc")
|
|
var image = Image.create_from_data(MaskResolution.value, MaskResolution.value, false, Image.FORMAT_RGBAF, last_image_data)
|
|
|
|
image.save_exr(MaskFilePath.text)
|
|
var editorFileSystem := EditorInterface.get_resource_filesystem()
|
|
editorFileSystem.scan()
|
|
|
|
last_image_data = []
|
|
|
|
if (driver != null && driver.clouds_resource != null):
|
|
driver.clouds_resource.extra_large_noise_patterns = ResourceLoader.load(MaskFilePath.text)
|
|
|
|
#endregion
|
|
|
|
func SetDrawInvert(mode : bool):
|
|
if (currentDrawMode == DRAWINGMODE.weight && drawInverted != mode):
|
|
drawInverted = mode
|
|
drawBrushToolMaterial.albedo_color = InvertedDrawingColor if drawInverted else DrawingColor
|
|
|
|
|
|
#region draw tools helpers
|
|
|
|
func RetrieveTravelDistance(pos : Vector3, dir :Vector3) -> float:
|
|
var t : float = (currentCloudsHeight - pos.y) / dir.y
|
|
if (dir.y == 0 || t < 0.0):
|
|
return -1.0
|
|
|
|
|
|
return t * dir.length()
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#Updates
|
|
func SetCloudsUpdating():
|
|
if (driver != null):
|
|
driver.update_continuously = CloudsActiveToggle.button_pressed
|
|
|
|
UpdateStatusDisplay()
|
|
|
|
|
|
#
|
|
#
|
|
#
|
|
#
|
|
#@tool
|
|
#extends MeshInstance3D
|
|
#class_name WanderingTerrainDrawnStamp
|
|
#
|
|
#
|
|
#@export var visibleColorMat : ShaderMaterial = preload("res://addons/WanderingTerrain/Materials/StampMaterials/EraseChunkVisibleColorMat.tres")
|
|
#@export var highlightedColorMat : ShaderMaterial = preload("res://addons/WanderingTerrain/Materials/StampMaterials/EraseChunkHighlightedColorMat.tres")
|
|
#@export var thisStampIndex : Vector2
|
|
#@export var currentHeightmapImageTexture: Texture2D
|
|
#@export var currentColormapImageTexture: Texture2D
|
|
#@export var currentSplatmapImageTexture: Texture2D
|
|
#@export var currentMaterial : ShaderMaterial
|
|
#
|
|
#var newHeightmapImage : Image
|
|
#var newColormapImage : Image
|
|
#var newSplatmapImage : Image
|
|
#var newHeightmapdrawingDirty : bool = false
|
|
#var newColormapdrawingDirty : bool = false
|
|
#var newSplatmapdrawingDirty : bool = false
|
|
#var pixelChanged : bool = false
|
|
#
|
|
#enum DrawingUpdateMode {sculpting, colorpainting, splatpainting}
|
|
#
|
|
#var thisRect : Rect2
|
|
#
|
|
#
|
|
#func InitializeDrawnStamp(resolution : int, indexPosition : Vector2, position : Vector3, currentUpdateType : DrawingUpdateMode):
|
|
#add_to_group("WanderingTerrainSculptingStamps", true);
|
|
#thisStampIndex = indexPosition
|
|
#global_position = position
|
|
#currentMaterial = material_override.duplicate()
|
|
#material_override = currentMaterial
|
|
#
|
|
#UpdateDrawnStamp(resolution, currentUpdateType)
|
|
#
|
|
#func SetVisible():
|
|
#currentMaterial.next_pass = visibleColorMat
|
|
#
|
|
#func SetHidden():
|
|
#currentMaterial.next_pass = null
|
|
#
|
|
#func Highlight():
|
|
#currentMaterial.next_pass = highlightedColorMat
|
|
#
|
|
#func Unhightlight():
|
|
#currentMaterial.next_pass = visibleColorMat
|
|
#
|
|
#func CheckHasAnyUpdate() -> bool:
|
|
#
|
|
#if (pixelChanged || currentHeightmapImageTexture != null || currentColormapImageTexture != null || currentSplatmapImageTexture != null):
|
|
#return true
|
|
#
|
|
#return false
|
|
#
|
|
#func UpdateDrawnStamp(resolution : int, currentUpdateType : DrawingUpdateMode):
|
|
#
|
|
#match currentUpdateType:
|
|
#DrawingUpdateMode.sculpting:
|
|
#
|
|
#if (newHeightmapImage == null || newHeightmapImage.get_width() != resolution):
|
|
#if (currentHeightmapImageTexture != null && currentHeightmapImageTexture.get_width() == resolution):
|
|
#newHeightmapImage = currentHeightmapImageTexture.get_image()
|
|
#else:
|
|
#currentHeightmapImageTexture = null
|
|
#newHeightmapdrawingDirty = true
|
|
#newHeightmapImage = Image.create(resolution, resolution, false, Image.FORMAT_RGF)
|
|
#for x in resolution:
|
|
#for y in resolution:
|
|
#newHeightmapImage.set_pixel(x,y, Color(0.0,0.0,0.0,0.0))
|
|
#
|
|
#
|
|
#var imageTexture = ImageTexture.create_from_image(newHeightmapImage)
|
|
#currentMaterial.set_shader_parameter("HeightMap", imageTexture)
|
|
#
|
|
#DrawingUpdateMode.colorpainting:
|
|
#
|
|
#if (newColormapImage == null || newColormapImage.get_width() != resolution):
|
|
#if (currentColormapImageTexture != null && currentColormapImageTexture.get_width() == resolution):
|
|
#newColormapImage = currentColormapImageTexture.get_image()
|
|
#else:
|
|
#currentColormapImageTexture = null
|
|
#newColormapdrawingDirty = true
|
|
#newColormapImage = Image.create(resolution, resolution, false, Image.FORMAT_RGBAF)
|
|
#for x in resolution:
|
|
#for y in resolution:
|
|
#newColormapImage.set_pixel(x,y, Color(0.0,0.0,0.0,0.0))
|
|
#
|
|
#var imageTexture = ImageTexture.create_from_image(newColormapImage)
|
|
#currentMaterial.set_shader_parameter("ColorMap", imageTexture)
|
|
#currentMaterial.set_shader_parameter("HasColorMap", true);
|
|
#
|
|
#DrawingUpdateMode.splatpainting:
|
|
#
|
|
#if (newSplatmapImage == null || newSplatmapImage.get_width() != resolution):
|
|
#if (currentSplatmapImageTexture != null && currentSplatmapImageTexture.get_width() == resolution):
|
|
#newSplatmapImage = currentSplatmapImageTexture.get_image()
|
|
#else:
|
|
#currentSplatmapImageTexture = null
|
|
#newSplatmapdrawingDirty = true
|
|
#newSplatmapImage = Image.create(resolution, resolution, false, Image.FORMAT_RGBAF)
|
|
#for x in resolution:
|
|
#for y in resolution:
|
|
#newSplatmapImage.set_pixel(x,y, Color(0.0,0.0,0.0,0.0))
|
|
#
|
|
#var imageTexture = ImageTexture.create_from_image(newSplatmapImage)
|
|
#currentMaterial.set_shader_parameter("SplatMap", imageTexture)
|
|
#currentMaterial.set_shader_parameter("HasSplatMap", true);
|
|
#
|
|
#
|
|
#thisRect = Rect2(Vector2(global_position.x - resolution / 2, global_position.z - resolution / 2),Vector2(resolution, resolution))
|
|
#
|
|
#func IsInsideRect(targetPosition : Vector2, stampRadius : float) -> bool:
|
|
#if thisRect.has_point(targetPosition) || thisRect.has_point(targetPosition + (Vector2(global_position.x, global_position.z) - targetPosition).normalized() * stampRadius):
|
|
#return true
|
|
#return false
|
|
#
|
|
#
|
|
#
|
|
#func PackStamp(terrainController : WanderingTerrainController):
|
|
#if (newHeightmapdrawingDirty && newHeightmapImage != null):
|
|
#newHeightmapdrawingDirty = false
|
|
#var resultingResource = await terrainController.Editor_SaveImageToOutputFolder(newHeightmapImage, name + "_height_savedstamp", "exr")
|
|
#if (resultingResource != null):
|
|
#currentHeightmapImageTexture = resultingResource
|
|
#currentMaterial.set_shader_parameter("HeightMap", currentHeightmapImageTexture)
|
|
#
|
|
#if (newColormapdrawingDirty && newColormapImage != null):
|
|
#newColormapdrawingDirty = false
|
|
#var resultingResource = await terrainController.Editor_SaveImageToOutputFolder(newColormapImage, name + "_color_savedstamp", "exr")
|
|
#if (resultingResource != null):
|
|
#currentColormapImageTexture = resultingResource
|
|
#currentMaterial.set_shader_parameter("ColorMap", currentColormapImageTexture)
|
|
#
|
|
#if (newSplatmapdrawingDirty && newSplatmapImage != null):
|
|
#newSplatmapdrawingDirty = false
|
|
#var resultingResource = await terrainController.Editor_SaveImageToOutputFolder(newSplatmapImage, name + "_splatmap_savedstamp", "exr")
|
|
#if (resultingResource != null):
|
|
#currentSplatmapImageTexture = resultingResource
|
|
#currentMaterial.set_shader_parameter("SplatMap", currentSplatmapImageTexture)
|
|
#
|
|
#func ColorPainting_DrawOnImage(targetPosition : Vector3, stampRadius : float, stampImage : Image, power : float, color : Color, layer : DrawingUpdateMode):
|
|
#var localPosition : Vector3 = targetPosition - global_position
|
|
#var localPositionPixelSpace := Vector2(localPosition.x + 256, localPosition.z + 256)
|
|
#var stampScale : float = stampImage.get_width() / stampRadius
|
|
#var stampActualResolution : float = (stampImage.get_width() / stampScale) + 1
|
|
#
|
|
#var stampPos : Vector2 = Vector2(localPositionPixelSpace.x, localPositionPixelSpace.y)
|
|
#var stampTopCornerPos : Vector2 = Vector2(localPositionPixelSpace.x - stampActualResolution / 2, localPositionPixelSpace.y - stampActualResolution / 2 )
|
|
#var currentPos : Vector2
|
|
#var thisColor: Color
|
|
#var stampAlpha: float
|
|
#var hasNoAlpha = stampImage.detect_alpha() == Image.ALPHA_NONE
|
|
#
|
|
#var currentImage : Image
|
|
#if (layer == DrawingUpdateMode.colorpainting):
|
|
#newColormapdrawingDirty = true
|
|
#currentImage = newColormapImage
|
|
#else:
|
|
#newSplatmapdrawingDirty = true
|
|
#currentImage = newSplatmapImage
|
|
#
|
|
#for x in stampActualResolution:
|
|
#if (stampTopCornerPos.x + x >= currentImage.get_width() || x * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#for y in stampActualResolution:
|
|
#if (stampTopCornerPos.y + y >= currentImage.get_height() || y * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#currentPos.x = stampTopCornerPos.x + x
|
|
#currentPos.y = stampTopCornerPos.y + y
|
|
#if (currentPos.x < 0 || currentPos.y < 0):
|
|
#continue
|
|
#
|
|
#thisColor = currentImage.get_pixelv(currentPos)
|
|
#if (hasNoAlpha):
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).r
|
|
#else:
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).a
|
|
#
|
|
#if (thisColor.a == 0):
|
|
#thisColor.r = color.r
|
|
#thisColor.g = color.g
|
|
#thisColor.b = color.b
|
|
#
|
|
#thisColor.r = lerpf(thisColor.r, color.r, stampAlpha * power * 0.2)
|
|
#thisColor.g = lerpf(thisColor.g, color.g, stampAlpha * power * 0.2)
|
|
#thisColor.b = lerpf(thisColor.b, color.b, stampAlpha * power * 0.2)
|
|
#
|
|
### Handles opacity, which always goes up.
|
|
#thisColor.a = clampf(thisColor.a + (stampAlpha * abs(power) * 0.2), 0.0, 1.0)
|
|
#currentImage.set_pixel(currentPos.x, currentPos.y, thisColor)
|
|
#pixelChanged = true
|
|
#
|
|
#var imageTexture = ImageTexture.create_from_image(currentImage)
|
|
#
|
|
#if (layer == DrawingUpdateMode.colorpainting):
|
|
#currentMaterial.set_shader_parameter("ColorMap", imageTexture)
|
|
#newColormapImage = currentImage
|
|
#else:
|
|
#currentMaterial.set_shader_parameter("SplatMap", imageTexture)
|
|
#newSplatmapImage = currentImage
|
|
#
|
|
#func ColorPainting_EraseOnImage(targetPosition : Vector3, stampRadius : float, stampImage : Image, power : float, layer : DrawingUpdateMode):
|
|
#var localPosition : Vector3 = targetPosition - global_position
|
|
#var localPositionPixelSpace := Vector2(localPosition.x + 256, localPosition.z + 256)
|
|
#var stampScale : float = stampImage.get_width() / stampRadius
|
|
#var stampActualResolution : float = (stampImage.get_width() / stampScale) + 1
|
|
#
|
|
#var stampPos : Vector2 = Vector2(localPositionPixelSpace.x, localPositionPixelSpace.y)
|
|
#var stampTopCornerPos : Vector2 = Vector2(localPositionPixelSpace.x - stampActualResolution / 2, localPositionPixelSpace.y - stampActualResolution / 2 )
|
|
#var currentPos : Vector2
|
|
#var thisColor: Color
|
|
#var stampAlpha: float
|
|
#var hasNoAlpha = stampImage.detect_alpha() == Image.ALPHA_NONE
|
|
#
|
|
#var currentImage : Image
|
|
#if (layer == DrawingUpdateMode.colorpainting):
|
|
#newColormapdrawingDirty = true
|
|
#currentImage = newColormapImage
|
|
#else:
|
|
#newSplatmapdrawingDirty = true
|
|
#currentImage = newSplatmapImage
|
|
#
|
|
#for x in stampActualResolution:
|
|
#if (stampTopCornerPos.x + x >= currentImage.get_width() || x * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#for y in stampActualResolution:
|
|
#if (stampTopCornerPos.y + y >= currentImage.get_height() || y * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#currentPos.x = stampTopCornerPos.x + x
|
|
#currentPos.y = stampTopCornerPos.y + y
|
|
#if (currentPos.x < 0 || currentPos.y < 0):
|
|
#continue
|
|
#
|
|
#thisColor = currentImage.get_pixelv(currentPos)
|
|
#if (hasNoAlpha):
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).r
|
|
#else:
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).a
|
|
#
|
|
#thisColor.a = clampf(thisColor.a - stampAlpha * power * 0.2, 0.0, 1.0)
|
|
#
|
|
#currentImage.set_pixel(currentPos.x, currentPos.y, thisColor)
|
|
#
|
|
#var imageTexture = ImageTexture.create_from_image(currentImage)
|
|
#
|
|
#if (layer == DrawingUpdateMode.colorpainting):
|
|
#currentMaterial.set_shader_parameter("ColorMap", imageTexture)
|
|
#newColormapImage = currentImage
|
|
#else:
|
|
#currentMaterial.set_shader_parameter("SplatMap", imageTexture)
|
|
#newSplatmapImage = currentImage
|
|
#
|
|
#func Sculpt_EraseOnImage(targetPosition : Vector3, stampRadius : float, stampImage : Image, power : float):
|
|
#newHeightmapdrawingDirty = true
|
|
#
|
|
#var localPosition : Vector3 = targetPosition - global_position
|
|
#
|
|
#var localPositionPixelSpace := Vector2(localPosition.x + 256, localPosition.z + 256)
|
|
#var stampScale : float = stampImage.get_width() / stampRadius
|
|
#var stampActualResolution : float = (stampImage.get_width() / stampScale) + 1
|
|
#var hasNoAlpha = stampImage.detect_alpha() == Image.ALPHA_NONE
|
|
#
|
|
#
|
|
#var stampPos : Vector2 = Vector2(localPositionPixelSpace.x, localPositionPixelSpace.y)
|
|
#var stampTopCornerPos : Vector2 = Vector2(localPositionPixelSpace.x - stampActualResolution / 2, localPositionPixelSpace.y - stampActualResolution / 2 )
|
|
#var currentPos : Vector2
|
|
#var thisColor: Color
|
|
#var stampAlpha: float
|
|
#
|
|
#for x in stampActualResolution:
|
|
#if (stampTopCornerPos.x + x >= newHeightmapImage.get_width() || x * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#for y in stampActualResolution:
|
|
#if (stampTopCornerPos.y + y >= newHeightmapImage.get_height() || y * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#currentPos.x = stampTopCornerPos.x + x
|
|
#currentPos.y = stampTopCornerPos.y + y
|
|
#if (currentPos.x < 0 || currentPos.y < 0):
|
|
#continue
|
|
#
|
|
#thisColor = newHeightmapImage.get_pixelv(currentPos)
|
|
#if (hasNoAlpha):
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).r
|
|
#else:
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).a
|
|
##thisColor.r += (0.5 - thisColor.r) * stampAlpha * power * 0.2
|
|
#thisColor.g = clampf(thisColor.g - stampAlpha * power * 0.2, 0.0, 1.0)
|
|
#newHeightmapImage.set_pixel(currentPos.x, currentPos.y, thisColor)
|
|
#
|
|
#var imageTexture = ImageTexture.create_from_image(newHeightmapImage)
|
|
#
|
|
#currentMaterial.set_shader_parameter("HeightMap", imageTexture)
|
|
#
|
|
#func Sculpt_SmoothOnImage(targetPosition : Vector3, stampRadius : float, stampImage : Image, power : float, worldScale : float):
|
|
#newHeightmapdrawingDirty = true
|
|
#
|
|
#var localPosition : Vector3 = targetPosition - global_position
|
|
#
|
|
#var localPositionPixelSpace := Vector2(localPosition.x + 256, localPosition.z + 256)
|
|
#var stampScale : float = stampImage.get_width() / stampRadius
|
|
#var stampActualResolution : float = (stampImage.get_width() / stampScale) + 1
|
|
#
|
|
#var stampPos : Vector2 = Vector2(localPositionPixelSpace.x, localPositionPixelSpace.y)
|
|
#var stampTopCornerPos : Vector2 = Vector2(localPositionPixelSpace.x - stampActualResolution / 2, localPositionPixelSpace.y - stampActualResolution / 2 )
|
|
#var currentPos : Vector2
|
|
#var thisColor: Color
|
|
#var stampAlpha: float
|
|
#var heightValue : float = clamp((targetPosition.y) / worldScale, 0.0, 1.0)
|
|
#var hasNoAlpha = stampImage.detect_alpha() == Image.ALPHA_NONE
|
|
#
|
|
#for x in stampActualResolution:
|
|
#if (stampTopCornerPos.x + x >= newHeightmapImage.get_width() || x * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#for y in stampActualResolution:
|
|
#if (stampTopCornerPos.y + y >= newHeightmapImage.get_height() || y * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#currentPos.x = stampTopCornerPos.x + x
|
|
#currentPos.y = stampTopCornerPos.y + y
|
|
#if (currentPos.x < 0 || currentPos.y < 0):
|
|
#continue
|
|
#
|
|
#thisColor = newHeightmapImage.get_pixelv(currentPos)
|
|
#if (hasNoAlpha):
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).r
|
|
#else:
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).a
|
|
#thisColor.r = clampf(thisColor.r + ((heightValue - thisColor.r) * stampAlpha * power * 0.2), 0.0, 1.0)
|
|
#thisColor.g = clampf(thisColor.g + ((0.0 - thisColor.g) * stampAlpha * power * 0.05), 0.0, 1.0)
|
|
#
|
|
#newHeightmapImage.set_pixel(currentPos.x, currentPos.y, thisColor)
|
|
#pixelChanged = true
|
|
#
|
|
#var imageTexture = ImageTexture.create_from_image(newHeightmapImage)
|
|
#
|
|
#currentMaterial.set_shader_parameter("HeightMap", imageTexture)
|
|
#
|
|
#
|
|
#func Sculpt_DrawOnImage(targetPosition : Vector3, stampRadius : float, stampImage : Image, power : float, worldScale : float):
|
|
#newHeightmapdrawingDirty = true
|
|
#
|
|
#var localPosition : Vector3 = targetPosition - global_position
|
|
#
|
|
#var localPositionPixelSpace := Vector2(localPosition.x + 256, localPosition.z + 256)
|
|
#var stampScale : float = stampImage.get_width() / stampRadius
|
|
#var stampActualResolution : float = (stampImage.get_width() / stampScale) + 1
|
|
#
|
|
#var stampPos : Vector2 = Vector2(localPositionPixelSpace.x, localPositionPixelSpace.y)
|
|
#var stampTopCornerPos : Vector2 = Vector2(localPositionPixelSpace.x - stampActualResolution / 2, localPositionPixelSpace.y - stampActualResolution / 2 )
|
|
#var currentPos : Vector2
|
|
#var thisColor: Color
|
|
#var stampAlpha: float
|
|
#var heightValue = clamp(targetPosition.y / worldScale, 0.0, 1.0)
|
|
#var hasNoAlpha = stampImage.detect_alpha() == Image.ALPHA_NONE
|
|
#
|
|
#for x in stampActualResolution:
|
|
#if (stampTopCornerPos.x + x >= newHeightmapImage.get_width() || x * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#for y in stampActualResolution:
|
|
#if (stampTopCornerPos.y + y >= newHeightmapImage.get_height() || y * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#currentPos.x = stampTopCornerPos.x + x
|
|
#currentPos.y = stampTopCornerPos.y + y
|
|
#if (currentPos.x < 0 || currentPos.y < 0):
|
|
#continue
|
|
#
|
|
#thisColor = newHeightmapImage.get_pixelv(currentPos)
|
|
#if (hasNoAlpha):
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).r
|
|
#else:
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).a
|
|
### Handles actual value.
|
|
#if (thisColor.g == 0):
|
|
#thisColor.r = heightValue
|
|
#thisColor.r = clampf(thisColor.r + (stampAlpha * power * 0.05), 0.0, 1.0)
|
|
### Handles opacity, which always goes up.
|
|
#thisColor.g = clampf(thisColor.g + (stampAlpha * abs(power) * 0.05), 0.0, 1.0)
|
|
#newHeightmapImage.set_pixel(currentPos.x, currentPos.y, thisColor)
|
|
#pixelChanged = true
|
|
#
|
|
#var imageTexture = ImageTexture.create_from_image(newHeightmapImage)
|
|
#
|
|
#currentMaterial.set_shader_parameter("HeightMap", imageTexture)
|
|
#
|
|
#func Sculpt_SetHeightOnImage(targetPosition : Vector3, stampRadius : float, stampImage : Image, heightValue : float, power : float, worldScale : float):
|
|
#newHeightmapdrawingDirty = true
|
|
#
|
|
#var localPosition : Vector3 = targetPosition - global_position
|
|
#
|
|
#var localPositionPixelSpace := Vector2(localPosition.x + 256, localPosition.z + 256)
|
|
#var stampScale : float = stampImage.get_width() / stampRadius
|
|
#var stampActualResolution : float = (stampImage.get_width() / stampScale) + 1
|
|
#
|
|
#var stampPos : Vector2 = Vector2(localPositionPixelSpace.x, localPositionPixelSpace.y)
|
|
#var stampTopCornerPos : Vector2 = Vector2(localPositionPixelSpace.x - stampActualResolution / 2, localPositionPixelSpace.y - stampActualResolution / 2 )
|
|
#var currentPos : Vector2
|
|
#var thisColor: Color
|
|
#var stampAlpha: float
|
|
#var currentHeight = clamp(targetPosition.y / worldScale, 0.0, 1.0)
|
|
#heightValue = clamp(heightValue / worldScale, 0.0, 1.0)
|
|
#var hasNoAlpha = stampImage.detect_alpha() == Image.ALPHA_NONE
|
|
#
|
|
#for x in stampActualResolution:
|
|
#if (stampTopCornerPos.x + x >= newHeightmapImage.get_width() || x * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#for y in stampActualResolution:
|
|
#if (stampTopCornerPos.y + y >= newHeightmapImage.get_height() || y * stampScale >= stampImage.get_width()):
|
|
#break
|
|
#currentPos.x = stampTopCornerPos.x + x
|
|
#currentPos.y = stampTopCornerPos.y + y
|
|
#if (currentPos.x < 0 || currentPos.y < 0):
|
|
#continue
|
|
#
|
|
#thisColor = newHeightmapImage.get_pixelv(currentPos)
|
|
#if (hasNoAlpha):
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).r
|
|
#else:
|
|
#stampAlpha = stampImage.get_pixel(x * stampScale,y * stampScale).a
|
|
#
|
|
#if (thisColor.g == 0):
|
|
#thisColor.r = currentHeight
|
|
#
|
|
#thisColor.r = clampf(thisColor.r + ((heightValue - thisColor.r) * stampAlpha * power), 0.0, 1.0)
|
|
### Handles opacity, which always goes up.
|
|
#thisColor.g = clampf(thisColor.g + (stampAlpha * abs(power) * 0.2), 0.0, 1.0)
|
|
#newHeightmapImage.set_pixel(currentPos.x, currentPos.y, thisColor)
|
|
#pixelChanged = true
|
|
#
|
|
#var imageTexture = ImageTexture.create_from_image(newHeightmapImage)
|
|
#
|
|
#currentMaterial.set_shader_parameter("HeightMap", imageTexture)
|