diff options
author | Gone2Daly <71726742+Gone2Daly@users.noreply.github.com> | 2023-07-22 21:05:42 +0200 |
---|---|---|
committer | Gone2Daly <71726742+Gone2Daly@users.noreply.github.com> | 2023-07-22 21:05:42 +0200 |
commit | 71b3cd829f80de4c2cd3972d8bfd5ee470a5d180 (patch) | |
tree | b4280fde6eef2ae6987648bc7bf8e00e9011bb7f /game/addons/zylann.hterrain/tools/brush/decal.gd | |
parent | ce9022d0df74d6c33db3686622be2050d873ab0b (diff) |
init_testtest3d
Diffstat (limited to 'game/addons/zylann.hterrain/tools/brush/decal.gd')
-rw-r--r-- | game/addons/zylann.hterrain/tools/brush/decal.gd | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/game/addons/zylann.hterrain/tools/brush/decal.gd b/game/addons/zylann.hterrain/tools/brush/decal.gd new file mode 100644 index 0000000..13433ed --- /dev/null +++ b/game/addons/zylann.hterrain/tools/brush/decal.gd @@ -0,0 +1,121 @@ +@tool +# Shows a cursor on top of the terrain to preview where the brush will paint + +# TODO Use an actual decal node, it wasn't available in Godot 3 + +const HT_DirectMeshInstance = preload("../../util/direct_mesh_instance.gd") +const HTerrain = preload("../../hterrain.gd") +const HTerrainData = preload("../../hterrain_data.gd") +const HT_Util = preload("../../util/util.gd") + +var _mesh_instance : HT_DirectMeshInstance +var _mesh : PlaneMesh +var _material = ShaderMaterial.new() +#var _debug_mesh = CubeMesh.new() +#var _debug_mesh_instance = null + +var _terrain : HTerrain = null + + +func _init(): + _material.shader = load("res://addons/zylann.hterrain/tools/brush/decal.gdshader") + _mesh_instance = HT_DirectMeshInstance.new() + _mesh_instance.set_material(_material) + + _mesh = PlaneMesh.new() + _mesh_instance.set_mesh(_mesh) + + #_debug_mesh_instance = DirectMeshInstance.new() + #_debug_mesh_instance.set_mesh(_debug_mesh) + + +func set_size(size: float): + _mesh.size = Vector2(size, size) + # Must line up to terrain vertex policy, so must apply an off-by-one. + # If I don't do that, the brush will appear to wobble above the ground + var ss := size - 1 + # Don't subdivide too much + while ss > 50: + ss /= 2 + _mesh.subdivide_width = ss + _mesh.subdivide_depth = ss + + +#func set_shape(shape_image): +# set_size(shape_image.get_width()) + + +func _on_terrain_transform_changed(terrain_global_trans: Transform3D): + var inv = terrain_global_trans.affine_inverse() + _material.set_shader_parameter("u_terrain_inverse_transform", inv) + + var normal_basis = terrain_global_trans.basis.inverse().transposed() + _material.set_shader_parameter("u_terrain_normal_basis", normal_basis) + + +func set_terrain(terrain: HTerrain): + if _terrain == terrain: + return + + if _terrain != null: + _terrain.transform_changed.disconnect(_on_terrain_transform_changed) + _mesh_instance.exit_world() + #_debug_mesh_instance.exit_world() + + _terrain = terrain + + if _terrain != null: + _terrain.transform_changed.connect(_on_terrain_transform_changed) + _on_terrain_transform_changed(_terrain.get_internal_transform()) + _mesh_instance.enter_world(terrain.get_world_3d()) + #_debug_mesh_instance.enter_world(terrain.get_world()) + + update_visibility() + + +func set_position(p_local_pos: Vector3): + assert(_terrain != null) + assert(typeof(p_local_pos) == TYPE_VECTOR3) + + # Set custom AABB (in local cells) because the decal is displaced by shader + var data = _terrain.get_data() + if data != null: + var r = _mesh.size / 2 + var aabb = data.get_region_aabb( \ + int(p_local_pos.x - r.x), \ + int(p_local_pos.z - r.y), \ + int(2 * r.x), \ + int(2 * r.y)) + aabb.position = Vector3(-r.x, aabb.position.y, -r.y) + _mesh.custom_aabb = aabb + #_debug_mesh.size = aabb.size + + var trans = Transform3D(Basis(), p_local_pos) + var terrain_gt = _terrain.get_internal_transform() + trans = terrain_gt * trans + _mesh_instance.set_transform(trans) + #_debug_mesh_instance.set_transform(trans) + + +# This is called very often so it should be cheap +func update_visibility(): + var heightmap = _get_heightmap(_terrain) + if heightmap == null: + # I do this for refcounting because heightmaps are large resources + _material.set_shader_parameter("u_terrain_heightmap", null) + _mesh_instance.set_visible(false) + #_debug_mesh_instance.set_visible(false) + else: + _material.set_shader_parameter("u_terrain_heightmap", heightmap) + _mesh_instance.set_visible(true) + #_debug_mesh_instance.set_visible(true) + + +func _get_heightmap(terrain): + if terrain == null: + return null + var data = terrain.get_data() + if data == null: + return null + return data.get_texture(HTerrainData.CHANNEL_HEIGHT) + |