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