## Converts a position input in viewport coordinates (e.g. from the mouse position input)
## into 3D coordinates (e.g. 3D world coordinates). Useful to get a 3D 'world' position.
## Returns a Vector3.INF if no 3D world coordinates can be determined.
@tool
class_name GUIDEModifier3DCoordinates
extends GUIDEModifier

## The maximum depth of the ray cast used to detect the 3D position.
@export var max_depth:float = 1000.0

## Whether the rays cast should collide with areas.
@export var collide_with_areas:bool = false

## Collision mask to use for the ray cast.
@export_flags_3d_physics var collision_mask:int


func _modify_input(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> Vector3:
	# if we collide with nothing, no need to even try
	if collision_mask == 0:
		return Vector3.INF
		
	if not input.is_finite():
		return Vector3.INF
			
	var viewport = Engine.get_main_loop().root
	var camera:Camera3D = viewport.get_camera_3d()
	if camera == null:
		return Vector3.INF
		
	
	var input_position:Vector2 = Vector2(input.x, input.y)	
		
	var from:Vector3 = camera.project_ray_origin(input_position)
	var to:Vector3 = from + camera.project_ray_normal(input_position) * max_depth
	var query:= PhysicsRayQueryParameters3D.create(from, to, collision_mask)
	query.collide_with_areas = collide_with_areas
		
	var result = viewport.world_3d.direct_space_state.intersect_ray(query)
	if result.has("position"):
		return result.position
		
	return Vector3.INF	



func _editor_name() -> String:
	return "3D coordinates"


func _editor_description() -> String:
	return "Converts a position input in viewport coordinates (e.g. from the mouse position input)\n" + \
		"into 3D coordinates (e.g. 3D world coordinates). Useful to get a 3D 'world' position."
