OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / maps / editor_grid.gd

109 lines · gd ref:
extends MeshInstance3D
class_name EditorGrid
## THE ACTIVE GRID, drawn on the surface you are aiming at (#31: TrenchBroom's
## GridRenderer — "we have a grid size with nothing drawing it").
##
## A patch of RADIUS cells around the aimed point, on the plane of the aimed surface's
## dominant axis, aligned to the WORLD lattice (multiples of the grid step), so the lines
## are exactly where a snapped edit lands. Every MAJOR_EVERY-th line is brighter; lines
## fade toward the patch edge so it reads as a local guide, not a floor.
##
## Rebuilt only when the aimed CELL, the surface axis/side or the step changes — aiming
## around inside one cell costs a comparison per frame.

const RADIUS := 16
const MAJOR_EVERY := 8
const LIFT := 0.003            # off the surface along its normal, so lines never z-fight
const MINOR := Color(1.0, 1.0, 1.0, 0.22)
const MAJOR := Color(1.0, 0.75, 0.3, 0.45)

var _key := ""
var _verts := PackedVector3Array()   # the drawn lines, CPU side (gates; the dummy renderer keeps none)


func _init() -> void:
	name = "EditorGrid"
	mesh = ImmediateMesh.new()
	cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
	var mat := StandardMaterial3D.new()
	mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
	mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
	mat.vertex_color_use_as_albedo = true
	mat.no_depth_test = false
	material_override = mat
	top_level = true


## Show the grid around `point` on the plane facing `normal`, at grid `step` metres.
## Returns true when the mesh was rebuilt (for gates).
func show_at(point: Vector3, normal: Vector3, step: float) -> bool:
	visible = true
	if step <= 1.0e-5:
		return false
	var axis := 0
	var an := normal.abs()
	if an.y >= an.x and an.y >= an.z:
		axis = 1
	elif an.z >= an.x:
		axis = 2
	var side := 1.0 if normal[axis] >= 0.0 else -1.0
	var a := (axis + 1) % 3
	var b := (axis + 2) % 3
	var ca := floori(point[a] / step)
	var cb := floori(point[b] / step)
	var key := "%d|%d|%d|%d|%s|%.4f" % [axis, int(side), ca, cb, String.num(point[axis], 3), step]
	if key == _key:
		return false
	_key = key
	_build(axis, side, a, b, ca, cb, point[axis] + side * LIFT, step)
	return true


func hide_grid() -> void:
	visible = false
	_key = ""


func _build(axis: int, _side: float, a: int, b: int, ca: int, cb: int, plane: float, step: float) -> void:
	var im := mesh as ImmediateMesh
	im.clear_surfaces()
	_verts.clear()
	im.surface_begin(Mesh.PRIMITIVE_LINES)
	var lo_a := float(ca - RADIUS) * step
	var hi_a := float(ca + RADIUS + 1) * step
	var lo_b := float(cb - RADIUS) * step
	var hi_b := float(cb + RADIUS + 1) * step
	for i in range(-RADIUS, RADIUS + 2):
		# Lines of constant a (running along b), then of constant b (running along a).
		for dir in 2:
			var cell := (ca if dir == 0 else cb) + i
			var t := float(cell) * step
			var col := MAJOR if posmod(cell, MAJOR_EVERY) == 0 else MINOR
			col.a *= clampf(1.0 - absf(float(i)) / float(RADIUS + 1), 0.0, 1.0)
			var p0 := Vector3.ZERO
			var p1 := Vector3.ZERO
			p0[axis] = plane
			p1[axis] = plane
			if dir == 0:
				p0[a] = t; p1[a] = t
				p0[b] = lo_b; p1[b] = hi_b
			else:
				p0[b] = t; p1[b] = t
				p0[a] = lo_a; p1[a] = hi_a
			im.surface_set_color(col)
			im.surface_add_vertex(p0)
			im.surface_set_color(col)
			im.surface_add_vertex(p1)
			_verts.append(p0)
			_verts.append(p1)
	im.surface_end()


## For gates: the drawn lines as vertex pairs, and their count.
func verts() -> PackedVector3Array:
	return _verts


func line_count() -> int:
	return _verts.size() / 2