Use debug draw addon
parent
9359f84345
commit
cb2cb5283a
|
@ -0,0 +1,11 @@
|
|||
DebugDraw utility for Godot Engine
|
||||
--------------------------------
|
||||
|
||||
Copyright (c) 2020 Marc Gilleron
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
|
||||
## @brief Single-file autoload for debug drawing and printing.
|
||||
## Draw and print on screen from anywhere in a single line of code.
|
||||
## Find it quickly by naming it "DDD".
|
||||
|
||||
# TODO Thread-safety
|
||||
# TODO 2D functions
|
||||
|
||||
extends Node
|
||||
|
||||
## @brief How many frames HUD text lines remain shown after being invoked.
|
||||
const TEXT_LINGER_FRAMES = 5
|
||||
## @brief How many frames lines remain shown after being drawn.
|
||||
const LINES_LINGER_FRAMES = 1
|
||||
## @brief Color of the text drawn as HUD
|
||||
const TEXT_COLOR = Color(1,1,1)
|
||||
## @brief Background color of the text drawn as HUD
|
||||
const TEXT_BG_COLOR = Color(0.3, 0.3, 0.3, 0.8)
|
||||
|
||||
# 2D
|
||||
|
||||
var _canvas_item : CanvasItem = null
|
||||
var _texts := {}
|
||||
var _font : Font = null
|
||||
|
||||
# 3D
|
||||
|
||||
var _boxes := []
|
||||
var _box_pool := []
|
||||
var _box_mesh : Mesh = null
|
||||
var _lines := []
|
||||
var _line_material_pool := []
|
||||
|
||||
|
||||
func _ready():
|
||||
# Get default font
|
||||
# Meh
|
||||
var c := Control.new()
|
||||
add_child(c)
|
||||
_font = c.get_font("font")
|
||||
c.queue_free()
|
||||
|
||||
|
||||
## @brief Draws the unshaded outline of a 3D box.
|
||||
## @param position: world-space position of the center of the box
|
||||
## @param size: size of the box in world units
|
||||
## @param color
|
||||
func draw_box(position: Vector3, size: Vector3, color: Color = Color(1,1,1)):
|
||||
var mi := _get_box()
|
||||
var mat := _get_line_material()
|
||||
mat.albedo_color = color
|
||||
mi.material_override = mat
|
||||
mi.translation = position
|
||||
mi.scale = size
|
||||
_boxes.append({
|
||||
"node": mi,
|
||||
"frame": Engine.get_frames_drawn() + LINES_LINGER_FRAMES
|
||||
})
|
||||
|
||||
|
||||
## @brief Draws an unshaded 3D line.
|
||||
## @param a: begin position in world units
|
||||
## @param b: end position in world units
|
||||
## @param color
|
||||
func draw_line_3d(a: Vector3, b: Vector3, color: Color):
|
||||
var g = ImmediateGeometry.new()
|
||||
g.material_override = _get_line_material()
|
||||
g.begin(Mesh.PRIMITIVE_LINES)
|
||||
g.set_color(color)
|
||||
g.add_vertex(a)
|
||||
g.add_vertex(b)
|
||||
g.end()
|
||||
add_child(g)
|
||||
_lines.append({
|
||||
"node": g,
|
||||
"frame": Engine.get_frames_drawn() + LINES_LINGER_FRAMES,
|
||||
})
|
||||
|
||||
|
||||
## @brief Draws an unshaded 3D line defined as a ray.
|
||||
## @param origin: begin position in world units
|
||||
## @param direction
|
||||
## @param length: length of the line in world units
|
||||
## @param color
|
||||
func draw_ray_3d(origin: Vector3, direction: Vector3, length: float, color : Color):
|
||||
draw_line_3d(origin, origin + direction * length, color)
|
||||
|
||||
|
||||
## @brief Adds a text monitoring line to the HUD, from the provided value.
|
||||
## It will be shown as such: - {key}: {text}
|
||||
## Multiple calls with the same `key` will override previous text.
|
||||
## @param key: identifier of the line
|
||||
## @param text: text to show next to the key
|
||||
func set_text(key: String, value):
|
||||
_texts[key] = {
|
||||
"text": value if typeof(value) == TYPE_STRING else str(value),
|
||||
"frame": Engine.get_frames_drawn() + TEXT_LINGER_FRAMES
|
||||
}
|
||||
|
||||
|
||||
func _get_box() -> MeshInstance:
|
||||
var mi : MeshInstance
|
||||
if len(_box_pool) == 0:
|
||||
mi = MeshInstance.new()
|
||||
if _box_mesh == null:
|
||||
_box_mesh = _create_wirecube_mesh(Color(1, 1, 1))
|
||||
mi.mesh = _box_mesh
|
||||
add_child(mi)
|
||||
else:
|
||||
mi = _box_pool[-1]
|
||||
_box_pool.pop_back()
|
||||
return mi
|
||||
|
||||
|
||||
func _recycle_box(mi: MeshInstance):
|
||||
mi.hide()
|
||||
_box_pool.append(mi)
|
||||
|
||||
|
||||
func _get_line_material() -> SpatialMaterial:
|
||||
var mat : SpatialMaterial
|
||||
if len(_line_material_pool) == 0:
|
||||
mat = SpatialMaterial.new()
|
||||
mat.flags_unshaded = true
|
||||
mat.vertex_color_use_as_albedo = true
|
||||
else:
|
||||
mat = _line_material_pool[-1]
|
||||
_line_material_pool.pop_back()
|
||||
return mat
|
||||
|
||||
|
||||
func _recycle_line_material(mat: SpatialMaterial):
|
||||
_line_material_pool.append(mat)
|
||||
|
||||
|
||||
func _process_3d_lines_delayed_free(items: Array):
|
||||
var i := 0
|
||||
while i < len(items):
|
||||
var d = items[i]
|
||||
if d.frame <= Engine.get_frames_drawn():
|
||||
_recycle_line_material(d.node.material_override)
|
||||
d.node.queue_free()
|
||||
items[i] = items[i - 1]
|
||||
items.pop_back()
|
||||
else:
|
||||
i += 1
|
||||
|
||||
|
||||
func _process(delta: float):
|
||||
_process_3d_lines_delayed_free(_lines)
|
||||
_process_3d_lines_delayed_free(_boxes)
|
||||
|
||||
# Progressively delete boxes
|
||||
if len(_box_pool) > 0:
|
||||
var last = _box_pool[-1]
|
||||
_box_pool.pop_back()
|
||||
last.queue_free()
|
||||
|
||||
# Remove text lines after some time
|
||||
for key in _texts.keys():
|
||||
var t = _texts[key]
|
||||
if t.frame <= Engine.get_frames_drawn():
|
||||
_texts.erase(key)
|
||||
|
||||
# Update canvas
|
||||
if _canvas_item == null:
|
||||
_canvas_item = Node2D.new()
|
||||
_canvas_item.position = Vector2(8, 8)
|
||||
_canvas_item.connect("draw", self, "_on_CanvasItem_draw")
|
||||
add_child(_canvas_item)
|
||||
_canvas_item.update()
|
||||
|
||||
|
||||
func _on_CanvasItem_draw():
|
||||
var ci := _canvas_item
|
||||
|
||||
var ascent := Vector2(0, _font.get_ascent())
|
||||
var pos := Vector2()
|
||||
var xpad := 2
|
||||
var ypad := 1
|
||||
var font_offset := ascent + Vector2(xpad, ypad)
|
||||
var line_height := _font.get_height() + 2 * ypad
|
||||
|
||||
for key in _texts.keys():
|
||||
var t = _texts[key]
|
||||
var text := str(key, ": ", t.text, "\n")
|
||||
var ss := _font.get_string_size(text)
|
||||
ci.draw_rect(Rect2(pos, Vector2(ss.x + xpad * 2, line_height)), TEXT_BG_COLOR)
|
||||
ci.draw_string(_font, pos + font_offset, text, TEXT_COLOR)
|
||||
pos.y += line_height
|
||||
|
||||
|
||||
static func _create_wirecube_mesh(color := Color(1,1,1)) -> ArrayMesh:
|
||||
var positions := PoolVector3Array([
|
||||
Vector3(0, 0, 0),
|
||||
Vector3(1, 0, 0),
|
||||
Vector3(1, 0, 1),
|
||||
Vector3(0, 0, 1),
|
||||
Vector3(0, 1, 0),
|
||||
Vector3(1, 1, 0),
|
||||
Vector3(1, 1, 1),
|
||||
Vector3(0, 1, 1)
|
||||
])
|
||||
var colors := PoolColorArray([
|
||||
color, color, color, color,
|
||||
color, color, color, color,
|
||||
])
|
||||
var indices := PoolIntArray([
|
||||
0, 1,
|
||||
1, 2,
|
||||
2, 3,
|
||||
3, 0,
|
||||
|
||||
4, 5,
|
||||
5, 6,
|
||||
6, 7,
|
||||
7, 4,
|
||||
|
||||
0, 4,
|
||||
1, 5,
|
||||
2, 6,
|
||||
3, 7
|
||||
])
|
||||
var arrays := []
|
||||
arrays.resize(Mesh.ARRAY_MAX)
|
||||
arrays[Mesh.ARRAY_VERTEX] = positions
|
||||
arrays[Mesh.ARRAY_COLOR] = colors
|
||||
arrays[Mesh.ARRAY_INDEX] = indices
|
||||
var mesh := ArrayMesh.new()
|
||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_LINES, arrays)
|
||||
return mesh
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
# Single-file autoload for debug drawing and printing.
|
||||
# Draw and print on screen from anywhere in a single line of code.
|
||||
# Find it quickly by naming it "DDD".
|
||||
|
||||
extends Node
|
||||
|
||||
|
||||
const TEXT_LINGER_FRAMES = 5
|
||||
const LINES_LINGER_FRAMES = 1
|
||||
const BOXES_LINGER_FRAMES = 1
|
||||
|
||||
var _lines = []
|
||||
|
||||
var _canvas_item = null
|
||||
var _texts = {}
|
||||
|
||||
var _boxes = []
|
||||
var _box_pool = []
|
||||
var _box_mesh = null
|
||||
|
||||
var _line_material_pool = []
|
||||
|
||||
var _font = null
|
||||
|
||||
|
||||
func _ready():
|
||||
# Meh
|
||||
var c = Control.new()
|
||||
add_child(c)
|
||||
_font = c.get_font("font")
|
||||
c.queue_free()
|
||||
print("Got font ", _font)
|
||||
|
||||
|
||||
func draw_box(position: Vector3, size: Vector3, color: Color = Color(1,1,1)):
|
||||
if _box_mesh == null:
|
||||
_box_mesh = _create_wirecube_mesh(Color(1,1,1))
|
||||
var mi = _get_box()
|
||||
mi.mesh = _box_mesh
|
||||
var mat = _get_line_material()
|
||||
mat.albedo_color = color
|
||||
mi.material_override = mat
|
||||
mi.translation = position
|
||||
mi.scale = size
|
||||
_boxes.append({
|
||||
"node": mi,
|
||||
"frame": Engine.get_frames_drawn() + LINES_LINGER_FRAMES
|
||||
})
|
||||
|
||||
|
||||
func draw_line(a, b, color):
|
||||
var g = ImmediateGeometry.new()
|
||||
g.material_override = _get_line_material()
|
||||
g.begin(Mesh.PRIMITIVE_LINES)
|
||||
g.set_color(color)
|
||||
g.add_vertex(a)
|
||||
g.add_vertex(b)
|
||||
g.end()
|
||||
add_child(g)
|
||||
_lines.append({
|
||||
"node": g,
|
||||
"frame": Engine.get_frames_drawn() + LINES_LINGER_FRAMES,
|
||||
})
|
||||
|
||||
|
||||
func set_text(key, text):
|
||||
_texts[key] = {
|
||||
"text": text,
|
||||
"frame": Engine.get_frames_drawn() + TEXT_LINGER_FRAMES
|
||||
}
|
||||
|
||||
|
||||
func _get_box():
|
||||
var mi
|
||||
if len(_box_pool) == 0:
|
||||
mi = MeshInstance.new()
|
||||
mi.mesh = _box_mesh
|
||||
add_child(mi)
|
||||
else:
|
||||
mi = _box_pool[-1]
|
||||
_box_pool.pop_back()
|
||||
return mi
|
||||
|
||||
|
||||
func _recycle_box(mi):
|
||||
mi.hide()
|
||||
_box_pool.append(mi)
|
||||
|
||||
|
||||
func _get_line_material():
|
||||
var mat
|
||||
if len(_line_material_pool) == 0:
|
||||
mat = SpatialMaterial.new()
|
||||
mat.flags_unshaded = true
|
||||
mat.vertex_color_use_as_albedo = true
|
||||
else:
|
||||
mat = _line_material_pool[-1]
|
||||
_line_material_pool.pop_back()
|
||||
return mat
|
||||
|
||||
|
||||
func _recycle_line_material(mat):
|
||||
_line_material_pool.append(mat)
|
||||
|
||||
|
||||
func _process_delayed_free(items):
|
||||
var i = 0
|
||||
while i < len(items):
|
||||
var d = items[i]
|
||||
if d.frame <= Engine.get_frames_drawn():
|
||||
_recycle_line_material(d.node.material_override)
|
||||
d.node.queue_free()
|
||||
items[i] = items[i - 1]
|
||||
items.pop_back()
|
||||
else:
|
||||
i += 1
|
||||
|
||||
|
||||
func _process(delta):
|
||||
_process_delayed_free(_lines)
|
||||
_process_delayed_free(_boxes)
|
||||
|
||||
# Progressively delete boxes
|
||||
if len(_box_pool) > 0:
|
||||
var last = _box_pool[-1]
|
||||
_box_pool.pop_back()
|
||||
last.queue_free()
|
||||
|
||||
# Remove text lines after some time
|
||||
for key in _texts.keys():
|
||||
var t = _texts[key]
|
||||
if t.frame <= Engine.get_frames_drawn():
|
||||
_texts.erase(key)
|
||||
|
||||
# Update canvas
|
||||
if _canvas_item == null:
|
||||
_canvas_item = Node2D.new()
|
||||
_canvas_item.position = Vector2(8, 8)
|
||||
_canvas_item.connect("draw", self, "_on_CanvasItem_draw")
|
||||
add_child(_canvas_item)
|
||||
_canvas_item.update()
|
||||
|
||||
|
||||
func _on_CanvasItem_draw():
|
||||
var ci = _canvas_item
|
||||
var fg_color = Color(1,1,1)
|
||||
var bg_color = Color(0.3, 0.3, 0.3, 0.8)
|
||||
|
||||
var ascent = Vector2(0, _font.get_ascent())
|
||||
var pos = Vector2()
|
||||
var xpad = 2
|
||||
var ypad = 1
|
||||
var font_offset = ascent + Vector2(xpad, ypad)
|
||||
var line_height = _font.get_height() + 2 * ypad
|
||||
|
||||
for key in _texts.keys():
|
||||
var t = _texts[key]
|
||||
var text = str(key, ": ", t.text, "\n")
|
||||
var ss = _font.get_string_size(text)
|
||||
ci.draw_rect(Rect2(pos, Vector2(ss.x + xpad * 2, line_height)), bg_color)
|
||||
ci.draw_string(_font, pos + font_offset, text, fg_color)
|
||||
pos.y += line_height
|
||||
|
||||
|
||||
static func _create_wirecube_mesh(color = Color(1,1,1)):
|
||||
var positions = PoolVector3Array([
|
||||
Vector3(0, 0, 0),
|
||||
Vector3(1, 0, 0),
|
||||
Vector3(1, 0, 1),
|
||||
Vector3(0, 0, 1),
|
||||
Vector3(0, 1, 0),
|
||||
Vector3(1, 1, 0),
|
||||
Vector3(1, 1, 1),
|
||||
Vector3(0, 1, 1)
|
||||
])
|
||||
var colors = PoolColorArray([
|
||||
color, color, color, color,
|
||||
color, color, color, color,
|
||||
])
|
||||
var indices = PoolIntArray([
|
||||
0, 1,
|
||||
1, 2,
|
||||
2, 3,
|
||||
3, 0,
|
||||
|
||||
4, 5,
|
||||
5, 6,
|
||||
6, 7,
|
||||
7, 4,
|
||||
|
||||
0, 4,
|
||||
1, 5,
|
||||
2, 6,
|
||||
3, 7
|
||||
])
|
||||
var arrays = []
|
||||
arrays.resize(Mesh.ARRAY_MAX)
|
||||
arrays[Mesh.ARRAY_VERTEX] = positions
|
||||
arrays[Mesh.ARRAY_COLOR] = colors
|
||||
arrays[Mesh.ARRAY_INDEX] = indices
|
||||
var mesh = ArrayMesh.new()
|
||||
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_LINES, arrays)
|
||||
return mesh
|
||||
|
|
@ -21,7 +21,7 @@ config/icon="res://icon.png"
|
|||
|
||||
[autoload]
|
||||
|
||||
DDD="*res://common/ddd.gd"
|
||||
DDD="*res://addons/zylann.debug_draw/debug_draw.gd"
|
||||
|
||||
[physics]
|
||||
|
||||
|
|
Loading…
Reference in New Issue