@tool
extends Node3D
@onready var mesh_instance: MeshInstance3D = $MeshInstance3D
@onready var camera: Camera3D = $Camera
@onready var label: Label = $CanvasLayer/StatsLabel
var orbit_angle := 0.0
var orbit_pitch := 0.3
var orbit_radius := 8.0
var orbit_speed := 0.0
var center := Vector3.ZERO
var current_voxel_size := 0.1
var dragging := false
var last_mouse := Vector2.ZERO
func _ready() -> void:
if Engine.is_editor_hint():
# Generate in editor too so it shows in viewport
_generate_fandisk(current_voxel_size)
else:
_generate_fandisk(current_voxel_size)
func _generate_fandisk(voxel_size: float) -> void:
current_voxel_size = voxel_size
label.text = "Generating fandisk at voxel_size=%.3f..." % voxel_size
var gen = DCTerrainGeneratorMeshSDF.new()
gen.mesh_path = "res://fandisk.glb"
print("Fandisk loaded: ", gen.get_triangle_count(), " source triangles")
var mesh = DCTerrainUtils.mesh_from_generator_auto(gen, voxel_size)
mesh_instance.mesh = mesh
if mesh and mesh.get_surface_count() > 0:
var aabb = mesh.get_aabb()
center = aabb.get_center()
orbit_radius = aabb.size.length() * 1.2
print("AABB center: ", center, " size: ", aabb.size)
_update_label()
func _process(delta: float) -> void:
if Engine.is_editor_hint():
return
orbit_angle += orbit_speed * delta
_update_camera()
func _update_camera() -> void:
var pitch_clamped = clamp(orbit_pitch, -1.5, 1.5)
camera.position = center + Vector3(
cos(orbit_angle) * cos(pitch_clamped) * orbit_radius,
sin(pitch_clamped) * orbit_radius,
sin(orbit_angle) * cos(pitch_clamped) * orbit_radius
)
camera.look_at(center)
func _update_label() -> void:
label.text = "Fandisk DC Test | Voxel: %.3f\n" % current_voxel_size
label.text += "LMB drag: orbit | Scroll: zoom | MMB drag: pan\n"
label.text += "1/2/3: resolution | Space: auto-rotate | F12: screenshot"
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseButton:
match event.button_index:
MOUSE_BUTTON_LEFT:
dragging = event.pressed
last_mouse = event.position
MOUSE_BUTTON_RIGHT:
dragging = event.pressed
last_mouse = event.position
MOUSE_BUTTON_WHEEL_UP:
orbit_radius = max(0.5, orbit_radius * 0.9)
_update_camera()
MOUSE_BUTTON_WHEEL_DOWN:
orbit_radius *= 1.1
_update_camera()
MOUSE_BUTTON_MIDDLE:
dragging = event.pressed
last_mouse = event.position
elif event is InputEventMouseMotion and dragging:
var delta = event.position - last_mouse
last_mouse = event.position
if Input.is_mouse_button_pressed(MOUSE_BUTTON_MIDDLE):
# Pan
var right = camera.global_transform.basis.x
var up = camera.global_transform.basis.y
var pan_speed = orbit_radius * 0.002
center -= right * delta.x * pan_speed
center += up * delta.y * pan_speed
_update_camera()
else:
# Orbit
orbit_angle -= delta.x * 0.005
orbit_pitch += delta.y * 0.005
_update_camera()
elif event is InputEventKey and event.pressed:
match event.keycode:
KEY_1:
_generate_fandisk(0.2)
KEY_2:
_generate_fandisk(0.1)
KEY_3:
_generate_fandisk(0.05)
KEY_4:
_generate_fandisk(0.025)
KEY_SPACE:
orbit_speed = 0.0 if orbit_speed > 0.0 else 0.5
KEY_R:
# Reset view
orbit_angle = 0.0
orbit_pitch = 0.3
if mesh_instance.mesh and mesh_instance.mesh.get_surface_count() > 0:
var aabb = mesh_instance.mesh.get_aabb()
center = aabb.get_center()
orbit_radius = aabb.size.length() * 1.2
_update_camera()
KEY_W:
# Toggle wireframe
var vp = get_viewport()
if vp.debug_draw == Viewport.DEBUG_DRAW_WIREFRAME:
vp.debug_draw = Viewport.DEBUG_DRAW_DISABLED
else:
vp.debug_draw = Viewport.DEBUG_DRAW_WIREFRAME
KEY_F12:
_take_screenshot()
func _take_screenshot() -> void:
var img = get_viewport().get_texture().get_image()
var timestamp = Time.get_datetime_string_from_system().replace(":", "-")
var path = "user://fandisk_%s.png" % timestamp
img.save_png(path)
print("Screenshot saved: ", path)