111 lines
2.9 KiB
GDScript
111 lines
2.9 KiB
GDScript
@tool
|
|
class_name TerrainControlLayers
|
|
extends Resource
|
|
|
|
## Resource containing artist-controlled terrain layers for procedural generation.
|
|
## Includes biome maps, height profiles, masks, and slope limits.
|
|
|
|
signal layers_changed
|
|
|
|
@export var resolution: Vector2i = Vector2i(512, 512):
|
|
set(value):
|
|
resolution = value
|
|
emit_changed()
|
|
layers_changed.emit()
|
|
|
|
@export_group("Biome Control")
|
|
@export var biome_map: Texture2D:
|
|
set(value):
|
|
biome_map = value
|
|
emit_changed()
|
|
layers_changed.emit()
|
|
|
|
@export var height_profile: Curve:
|
|
set(value):
|
|
if height_profile and height_profile.changed.is_connected(_on_curve_changed):
|
|
height_profile.changed.disconnect(_on_curve_changed)
|
|
height_profile = value
|
|
if height_profile:
|
|
height_profile.changed.connect(_on_curve_changed)
|
|
emit_changed()
|
|
layers_changed.emit()
|
|
|
|
@export_group("Slope Control")
|
|
@export var slope_limit_map: Texture2D:
|
|
set(value):
|
|
slope_limit_map = value
|
|
emit_changed()
|
|
layers_changed.emit()
|
|
|
|
@export_range(0.0, 90.0) var default_slope_limit: float = 45.0:
|
|
set(value):
|
|
default_slope_limit = value
|
|
emit_changed()
|
|
layers_changed.emit()
|
|
|
|
@export_group("Mask Layers")
|
|
@export var mask_layers: Array[Texture2D] = []:
|
|
set(value):
|
|
mask_layers = value
|
|
emit_changed()
|
|
layers_changed.emit()
|
|
|
|
@export var mask_names: Array[String] = []:
|
|
set(value):
|
|
mask_names = value
|
|
emit_changed()
|
|
layers_changed.emit()
|
|
|
|
|
|
func _on_curve_changed() -> void:
|
|
emit_changed()
|
|
layers_changed.emit()
|
|
|
|
|
|
func get_biome_value(uv: Vector2) -> Color:
|
|
if not biome_map:
|
|
return Color.WHITE
|
|
var img := biome_map.get_image()
|
|
if not img:
|
|
return Color.WHITE
|
|
var px := clampi(int(uv.x * img.get_width()), 0, img.get_width() - 1)
|
|
var py := clampi(int(uv.y * img.get_height()), 0, img.get_height() - 1)
|
|
return img.get_pixel(px, py)
|
|
|
|
|
|
func get_slope_limit(uv: Vector2) -> float:
|
|
if not slope_limit_map:
|
|
return default_slope_limit
|
|
var img := slope_limit_map.get_image()
|
|
if not img:
|
|
return default_slope_limit
|
|
var px := clampi(int(uv.x * img.get_width()), 0, img.get_width() - 1)
|
|
var py := clampi(int(uv.y * img.get_height()), 0, img.get_height() - 1)
|
|
return img.get_pixel(px, py).r * 90.0
|
|
|
|
|
|
func get_height_profile_value(normalized_height: float) -> float:
|
|
if not height_profile:
|
|
return normalized_height
|
|
return height_profile.sample(clampf(normalized_height, 0.0, 1.0))
|
|
|
|
|
|
func get_mask_value(mask_index: int, uv: Vector2) -> float:
|
|
if mask_index < 0 or mask_index >= mask_layers.size():
|
|
return 0.0
|
|
var tex := mask_layers[mask_index]
|
|
if not tex:
|
|
return 0.0
|
|
var img := tex.get_image()
|
|
if not img:
|
|
return 0.0
|
|
var px := clampi(int(uv.x * img.get_width()), 0, img.get_width() - 1)
|
|
var py := clampi(int(uv.y * img.get_height()), 0, img.get_height() - 1)
|
|
return img.get_pixel(px, py).r
|
|
|
|
|
|
func get_mask_name(mask_index: int) -> String:
|
|
if mask_index < 0 or mask_index >= mask_names.size():
|
|
return "mask_%d" % mask_index
|
|
return mask_names[mask_index]
|