Skip to content

Commit

Permalink
first attempt to draw 2d
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriySalnikov committed Sep 3, 2023
1 parent 49ab1a5 commit 7633bd5
Show file tree
Hide file tree
Showing 13 changed files with 680 additions and 26 deletions.
6 changes: 6 additions & 0 deletions examples_dd3d/DebugDrawDemoScene.gd
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ func _process(delta: float) -> void:
$LagTest.visible = false
return

DebugDraw2D.draw_set_transform_2d(Vector2(100,1), deg_to_rad(45), Vector2(0.5, 1))
var trans = DebugDraw2D.draw_set_transform_2d(Vector2(100,1), deg_to_rad(45), Vector2(0.5, 1))
if true:
var trans2 = DebugDraw2D.draw_set_transform_2d(Vector2(1,1), deg_to_rad(180))
trans = null

$HitTest.visible = true
$LagTest.visible = true

Expand Down
7 changes: 5 additions & 2 deletions examples_dd3d/DebugDrawDemoScene.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,13 @@ func _ready() -> void:

func _process(_delta):
pass
#queue_redraw()
queue_redraw()

func _draw():
pass
if Input.is_key_pressed(KEY_1):
draw_set_transform(Vector2(100,0), deg_to_rad(45))
draw_line(Vector2(0,10), Vector2(100, 10), Color.AQUA)
#draw_texture_rect_region(load(\"res://icon.svg\"), Rect2(Vector2(), Vector2(128,128)), Rect2(Vector2(), Vector2(128,128)))

func _on_CheckBox_toggled(button_pressed: bool) -> void:
Expand Down Expand Up @@ -254,7 +257,7 @@ stretch = true
[node name="Viewport" type="SubViewport" parent="Panel/ViewportContainer"]
handle_input_locally = false
size = Vector2i(2, 2)
size = Vector2i(300, 300)
render_target_update_mode = 0
[node name="CameraLayer2_5" type="Camera3D" parent="Panel/ViewportContainer/Viewport"]
Expand Down
112 changes: 108 additions & 4 deletions src/2d/debug_draw_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ GODOT_WARNING_RESTORE()
#include <limits.h>

#define NEED_LEAVE (!debug_enabled)
std::atomic<uint64_t> DDTransform2DGuard::create_counter = 0;

DDTransform2DGuard::DDTransform2DGuard() {
guard_id = create_counter++;
thread_id = OS::get_singleton()->get_thread_caller_id();

DebugDraw2D::get_singleton()->register_transform_guard(guard_id, thread_id, Transform2D());
}

DDTransform2DGuard::DDTransform2DGuard(const Transform2D &xform) {
guard_id = create_counter++;
thread_id = OS::get_singleton()->get_thread_caller_id();

DebugDraw2D::get_singleton()->register_transform_guard(guard_id, thread_id, xform);
}

DDTransform2DGuard::~DDTransform2DGuard() {
DebugDraw2D::get_singleton()->unregister_transform_guard(guard_id, thread_id);
}

DebugDraw2D *DebugDraw2D::singleton = nullptr;

Expand All @@ -49,9 +68,40 @@ void DebugDraw2D::_bind_methods() {
#pragma region Draw Functions
ClassDB::bind_method(D_METHOD(NAMEOF(clear_2d_objects)), &DebugDraw2D::clear_2d_objects);

const int DEFAULT_FONT_SIZE = 16;
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_line), "from", "to", "color", "width", "antialiased"), &DebugDraw2D::draw_line, -1.0, false);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_dashed_line), "from", "to", "color", "width", "dash", "aligned"), &DebugDraw2D::draw_dashed_line, -1.0, 2.0, true);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_polyline), "points", "color", "width", "antialiased"), &DebugDraw2D::draw_polyline, -1.0, false);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_polyline_colors), "points", "colors", "width", "antialiased"), &DebugDraw2D::draw_polyline_colors, -1.0, false);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_arc), "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &DebugDraw2D::draw_arc, -1.0, false);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_multiline), "points", "color", "width"), &DebugDraw2D::draw_multiline, -1.0);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_multiline_colors), "points", "colors", "width"), &DebugDraw2D::draw_multiline_colors, -1.0);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_rect), "rect", "color", "filled", "width"), &DebugDraw2D::draw_rect, true, -1.0);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_circle), "position", "radius", "color"), &DebugDraw2D::draw_circle);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_texture), "texture", "position", "modulate"), &DebugDraw2D::draw_texture, Color(1, 1, 1, 1));
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_texture_rect), "texture", "rect", "tile", "modulate", "transpose"), &DebugDraw2D::draw_texture_rect, Color(1, 1, 1, 1), false);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_texture_rect_region), "texture", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &DebugDraw2D::draw_texture_rect_region, Color(1, 1, 1, 1), false, true);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_msdf_texture_rect_region), "texture", "rect", "src_rect", "modulate", "outline", "pixel_range", "scale"), &DebugDraw2D::draw_msdf_texture_rect_region, Color(1, 1, 1, 1), 0.0, 4.0, 1.0);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_lcd_texture_rect_region), "texture", "rect", "src_rect", "modulate"), &DebugDraw2D::draw_lcd_texture_rect_region, Color(1, 1, 1, 1));
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_style_box), "style_box", "rect"), &DebugDraw2D::draw_style_box);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_primitive), "points", "colors", "uvs", "texture"), &DebugDraw2D::draw_primitive, Ref<Texture2D>());
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_polygon), "points", "colors", "uvs", "texture"), &DebugDraw2D::draw_polygon, PackedVector2Array(), Ref<Texture2D>());
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_colored_polygon), "points", "color", "uvs", "texture"), &DebugDraw2D::draw_colored_polygon, PackedVector2Array(), Ref<Texture2D>());
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_string), "font", "pos", "text", "alignment", "width", "font_size", "modulate", "justification_flags", "direction", "orientation"), &DebugDraw2D::draw_string, HORIZONTAL_ALIGNMENT_LEFT, -1, DEFAULT_FONT_SIZE, Color(1.0, 1.0, 1.0), TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::DIRECTION_AUTO, TextServer::ORIENTATION_HORIZONTAL);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_multiline_string), "font", "pos", "text", "alignment", "width", "font_size", "max_lines", "modulate", "brk_flags", "justification_flags", "direction", "orientation"), &DebugDraw2D::draw_multiline_string, HORIZONTAL_ALIGNMENT_LEFT, -1, DEFAULT_FONT_SIZE, -1, Color(1.0, 1.0, 1.0), TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::DIRECTION_AUTO, TextServer::ORIENTATION_HORIZONTAL);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_string_outline), "font", "pos", "text", "alignment", "width", "font_size", "size", "modulate", "justification_flags", "direction", "orientation"), &DebugDraw2D::draw_string_outline, HORIZONTAL_ALIGNMENT_LEFT, -1, DEFAULT_FONT_SIZE, 1, Color(1.0, 1.0, 1.0), TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::DIRECTION_AUTO, TextServer::ORIENTATION_HORIZONTAL);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_multiline_string_outline), "font", "pos", "text", "alignment", "width", "font_size", "max_lines", "size", "modulate", "brk_flags", "justification_flags", "direction", "orientation"), &DebugDraw2D::draw_multiline_string_outline, HORIZONTAL_ALIGNMENT_LEFT, -1, DEFAULT_FONT_SIZE, -1, 1, Color(1.0, 1.0, 1.0), TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND, TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND, TextServer::DIRECTION_AUTO, TextServer::ORIENTATION_HORIZONTAL);
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_char), "font", "pos", "char", "font_size", "modulate"), &DebugDraw2D::draw_char, DEFAULT_FONT_SIZE, Color(1.0, 1.0, 1.0));
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_char_outline), "font", "pos", "char", "font_size", "size", "modulate"), &DebugDraw2D::draw_char_outline, DEFAULT_FONT_SIZE, -1, Color(1.0, 1.0, 1.0));
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_mesh), "mesh", "texture", "transform", "modulate"), &DebugDraw2D::draw_mesh, Transform2D(), Color(1, 1, 1, 1));
// ClassDB::bind_method(D_METHOD(NAMEOF(draw_multimesh), "multimesh", "texture"), &DebugDraw2D::draw_multimesh);

ClassDB::bind_method(D_METHOD(NAMEOF(draw_set_transform_2d), "position", "rotation", "scale"), &DebugDraw2D::draw_set_transform_2d, 0.0, Vector2(1.0, 1.0));
ClassDB::bind_method(D_METHOD(NAMEOF(draw_set_transform_matrix_2d), "xform"), &DebugDraw2D::draw_set_transform_matrix_2d);

ClassDB::bind_method(D_METHOD(NAMEOF(begin_text_group), "group_title", "group_priority", "group_color", "show_title", "title_size", "text_size"), &DebugDraw2D::begin_text_group, 0, Colors::empty_color, true, -1, -1);
ClassDB::bind_method(D_METHOD(NAMEOF(end_text_group)), &DebugDraw2D::end_text_group);
ClassDB::bind_method(D_METHOD(NAMEOF(set_text), "key", "value", "priority", "color_of_value", "duration"), &DebugDraw2D::set_text, Variant(), 0, Colors::empty_color, -1.0); // TODO: -1 must be explicitly double. Need fix for Variant converter
ClassDB::bind_method(D_METHOD(NAMEOF(set_text), "key", "value", "priority", "color_of_value", "duration"), &DebugDraw2D::set_text, Variant(), 0, Colors::empty_color, -1);

ClassDB::bind_method(D_METHOD(NAMEOF(create_graph), "title"), &DebugDraw2D::create_graph);
ClassDB::bind_method(D_METHOD(NAMEOF(create_fps_graph), "title"), &DebugDraw2D::create_fps_graph);
Expand Down Expand Up @@ -108,6 +158,7 @@ DebugDraw2D::~DebugDraw2D() {

root_node = nullptr;
config.unref();
clear_transform_guards();
}

void DebugDraw2D::process(double delta) {
Expand All @@ -120,10 +171,13 @@ void DebugDraw2D::process(double delta) {

// Update overlay
if (_canvas_need_update) {
if (!UtilityFunctions::is_instance_valid(custom_canvas) && UtilityFunctions::is_instance_valid(default_canvas))
if (!UtilityFunctions::is_instance_valid(custom_canvas) && UtilityFunctions::is_instance_valid(default_canvas)) {
default_canvas->queue_redraw();
else if (UtilityFunctions::is_instance_valid(custom_canvas))
} else if (UtilityFunctions::is_instance_valid(custom_canvas)) {
custom_canvas->queue_redraw();
} else {
clear_transform_guards();
}

// reset some values
_canvas_need_update = false;
Expand All @@ -142,6 +196,8 @@ void DebugDraw2D::_on_canvas_item_draw(Control *ci) {

grouped_text->draw(ci, _font, vp_size);
data_graphs->draw(ci, _font, vp_size, ci->get_process_delta_time());

clear_transform_guards();
#else
return;
#endif
Expand Down Expand Up @@ -198,6 +254,54 @@ Ref<DebugDrawConfig2D> DebugDraw2D::get_config() const {
return config;
}

Ref<DDTransform2DGuard> DebugDraw2D::draw_set_transform_2d(const Vector2 &position, double rotation, const Vector2 &scale) {
Transform2D xform((real_t)rotation, position);
xform.scale_basis(scale);

return draw_set_transform_matrix_2d(xform);
}

Ref<DDTransform2DGuard> DebugDraw2D::draw_set_transform_matrix_2d(const Transform2D &xform) {
auto guard = Ref<DDTransform2DGuard>(::godot::_post_initialize(new ("") DDTransform2DGuard(xform)));
return guard;
}

Transform2D DebugDraw2D::get_transform_for_current_thread() {
LOCK_GUARD(transform_stack_mutex);

uint64_t thread_id = OS::get_singleton()->get_thread_caller_id();
if (transform_stack.find(thread_id) != transform_stack.end()) {
const auto &transforms = transform_stack[thread_id];
if (transforms.size() > 0)
return transforms.back().second;
}

return default_transform_2d;
}

void DebugDraw2D::register_transform_guard(uint64_t guard_id, uint64_t thread_id, const Transform2D &xform) {
LOCK_GUARD(transform_stack_mutex);

transform_stack[thread_id].push_back(transform_pair(guard_id, xform));
}

void DebugDraw2D::unregister_transform_guard(uint64_t guard_id, uint64_t thread_id) {
LOCK_GUARD(transform_stack_mutex);

auto &transforms = transform_stack[thread_id];
auto res = std::find_if(transforms.rbegin(), transforms.rend(), [&guard_id](const transform_pair &i) { return i.first == guard_id; });

if (res != transforms.rend()) {
transforms.erase(--res.base());
}
}

void DebugDraw2D::clear_transform_guards() {
LOCK_GUARD(transform_stack_mutex);

transform_stack.clear();
}

void DebugDraw2D::set_custom_canvas(Control *_canvas) {
#ifndef DISABLE_DEBUG_RENDERING
if (!_canvas) {
Expand Down Expand Up @@ -302,4 +406,4 @@ PackedStringArray DebugDraw2D::get_graph_names() {

#pragma endregion // Draw Functions

#undef NEED_LEAVE
#undef NEED_LEAVE
74 changes: 74 additions & 0 deletions src/2d/debug_draw_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ GODOT_WARNING_DISABLE()
#include <godot_cpp/classes/sub_viewport.hpp>
GODOT_WARNING_RESTORE()

#include <atomic>
#include <map>
#include <memory>
#include <mutex>
#include <vector>

using namespace godot;

Expand All @@ -23,6 +27,22 @@ class DebugDrawGraph;
class DebugDrawStats2D;
class GroupedText;

class DDTransform2DGuard : public RefCounted {
GDCLASS(DDTransform2DGuard, RefCounted)

protected:
static void _bind_methods(){};
static std::atomic<uint64_t> create_counter;

public:
uint64_t thread_id;
uint64_t guard_id;

DDTransform2DGuard();
DDTransform2DGuard(const Transform2D &xform);
~DDTransform2DGuard();
};

class DebugDraw2D : public Object {
GDCLASS(DebugDraw2D, Object)

Expand All @@ -33,6 +53,15 @@ class DebugDraw2D : public Object {
DebugDrawManager *root_node = nullptr;

// 2d
typedef std::pair<uint64_t, Transform2D> transform_pair;
std::map<uint64_t, std::vector<transform_pair> > transform_stack;
mutable std::recursive_mutex transform_stack_mutex;

// TODO create vector of pairs<Transform, DrawInstanceBaseType>, to combine as much as possible instances by transforms
// or create a map for <uint64_t, Transform2D> to remap transform to some id's and then create a map<uint64_t, DrawInstanceBaseType> to store data
// in anyway this will need a new pooling system

// overlays
CanvasLayer *_canvas_layer = nullptr;
bool _canvas_need_update = true;
Ref<Font> _font;
Expand Down Expand Up @@ -63,6 +92,8 @@ class DebugDraw2D : public Object {
/// Custom 'CanvasItem' to draw on it. Set to 'null' to disable.
Control *custom_canvas = nullptr;

Transform2D default_transform_2d;

Ref<DebugDrawConfig2D> config;

#pragma endregion // Exposed Parameter Values
Expand All @@ -83,6 +114,14 @@ class DebugDraw2D : public Object {

Node *get_root_node();

Ref<DDTransform2DGuard> draw_set_transform_2d(const Vector2 &position, double rotation = 0.0, const Vector2 &scale = Vector2(1, 1));
Ref<DDTransform2DGuard> draw_set_transform_matrix_2d(const Transform2D &xform);

Transform2D get_transform_for_current_thread();
void register_transform_guard(uint64_t guard_id, uint64_t thread_id, const Transform2D &xform);
void unregister_transform_guard(uint64_t guard_id, uint64_t thread_id);
void clear_transform_guards();

#pragma region Exposed Parameters
void set_empty_color(const Color &_col);
Color get_empty_color() const;
Expand All @@ -106,6 +145,40 @@ class DebugDraw2D : public Object {
/// Clear all 2D objects
void clear_2d_objects();

#pragma region 2D

// TODO: add method to preconfig duration or "duration" guard which will set duration while exists. When its removed, duration will be 0
// or simply add "duration" to the end of all methods..
void draw_line(const Vector2 &from, const Vector2 &to, const Color &color, double width = -1.0, bool antialiased = false);
void draw_dashed_line(const Vector2 &from, const Vector2 &to, const Color &color, double width = -1.0, double dash = 2.0, bool aligned = true);
void draw_polyline(const PackedVector2Array &points, const Color &color, double width = -1.0, bool antialiased = false);
void draw_polyline_colors(const PackedVector2Array &points, const PackedColorArray &colors, double width = -1.0, bool antialiased = false);
void draw_arc(const Vector2 &center, double radius, double start_angle, double end_angle, int32_t point_count, const Color &color, double width = -1.0, bool antialiased = false);
void draw_multiline(const PackedVector2Array &points, const Color &color, double width = -1.0);
void draw_multiline_colors(const PackedVector2Array &points, const PackedColorArray &colors, double width = -1.0);
void draw_rect(const Rect2 &rect, const Color &color, bool filled = true, double width = -1.0);
void draw_circle(const Vector2 &position, double radius, const Color &color);
void draw_texture(const Ref<Texture2D> &texture, const Vector2 &position, const Color &modulate = Color(1, 1, 1, 1));
void draw_texture_rect(const Ref<Texture2D> &texture, const Rect2 &rect, bool tile, const Color &modulate = Color(1, 1, 1, 1), bool transpose = false);
void draw_texture_rect_region(const Ref<Texture2D> &texture, const Rect2 &rect, const Rect2 &src_rect, const Color &modulate = Color(1, 1, 1, 1), bool transpose = false, bool clip_uv = true);
void draw_msdf_texture_rect_region(const Ref<Texture2D> &texture, const Rect2 &rect, const Rect2 &src_rect, const Color &modulate = Color(1, 1, 1, 1), double outline = 0.0, double pixel_range = 4.0, double scale = 1.0);
void draw_lcd_texture_rect_region(const Ref<Texture2D> &texture, const Rect2 &rect, const Rect2 &src_rect, const Color &modulate = Color(1, 1, 1, 1));
void draw_style_box(const Ref<StyleBox> &style_box, const Rect2 &rect);
void draw_primitive(const PackedVector2Array &points, const PackedColorArray &colors, const PackedVector2Array &uvs, const Ref<Texture2D> &texture = nullptr);
void draw_polygon(const PackedVector2Array &points, const PackedColorArray &colors, const PackedVector2Array &uvs = PackedVector2Array(), const Ref<Texture2D> &texture = nullptr);
void draw_colored_polygon(const PackedVector2Array &points, const Color &color, const PackedVector2Array &uvs = PackedVector2Array(), const Ref<Texture2D> &texture = nullptr);
void draw_string(const Ref<Font> &font, const Vector2 &pos, const String &text, HorizontalAlignment alignment = (HorizontalAlignment)0, double width = -1, int32_t font_size = 16, const Color &modulate = Color(1, 1, 1, 1), BitField<TextServer::JustificationFlag> justification_flags = (BitField<TextServer::JustificationFlag>)3, TextServer::Direction direction = (TextServer::Direction)0, TextServer::Orientation orientation = (TextServer::Orientation)0) const;
void draw_multiline_string(const Ref<Font> &font, const Vector2 &pos, const String &text, HorizontalAlignment alignment = (HorizontalAlignment)0, double width = -1, int32_t font_size = 16, int32_t max_lines = -1, const Color &modulate = Color(1, 1, 1, 1), BitField<TextServer::LineBreakFlag> brk_flags = (BitField<TextServer::LineBreakFlag>)3, BitField<TextServer::JustificationFlag> justification_flags = (BitField<TextServer::JustificationFlag>)3, TextServer::Direction direction = (TextServer::Direction)0, TextServer::Orientation orientation = (TextServer::Orientation)0) const;
void draw_string_outline(const Ref<Font> &font, const Vector2 &pos, const String &text, HorizontalAlignment alignment = (HorizontalAlignment)0, double width = -1, int32_t font_size = 16, int32_t size = 1, const Color &modulate = Color(1, 1, 1, 1), BitField<TextServer::JustificationFlag> justification_flags = (BitField<TextServer::JustificationFlag>)3, TextServer::Direction direction = (TextServer::Direction)0, TextServer::Orientation orientation = (TextServer::Orientation)0) const;
void draw_multiline_string_outline(const Ref<Font> &font, const Vector2 &pos, const String &text, HorizontalAlignment alignment = (HorizontalAlignment)0, double width = -1, int32_t font_size = 16, int32_t max_lines = -1, int32_t size = 1, const Color &modulate = Color(1, 1, 1, 1), BitField<TextServer::LineBreakFlag> brk_flags = (BitField<TextServer::LineBreakFlag>)3, BitField<TextServer::JustificationFlag> justification_flags = (BitField<TextServer::JustificationFlag>)3, TextServer::Direction direction = (TextServer::Direction)0, TextServer::Orientation orientation = (TextServer::Orientation)0) const;
void draw_char(const Ref<Font> &font, const Vector2 &pos, const String &_char, int32_t font_size = 16, const Color &modulate = Color(1, 1, 1, 1)) const;
void draw_char_outline(const Ref<Font> &font, const Vector2 &pos, const String &_char, int32_t font_size = 16, int32_t size = -1, const Color &modulate = Color(1, 1, 1, 1)) const;
void draw_mesh(const Ref<Mesh> &mesh, const Ref<Texture2D> &texture, const Transform2D &transform = Transform2D(), const Color &modulate = Color(1, 1, 1, 1));
void draw_multimesh(const Ref<MultiMesh> &multimesh, const Ref<Texture2D> &texture);

#pragma endregion // 2D

#pragma region Overlay
#pragma region Text

/// Begin text group
Expand Down Expand Up @@ -158,5 +231,6 @@ class DebugDraw2D : public Object {
PackedStringArray get_graph_names();

#pragma endregion // Graphs
#pragma endregion // Overlay
#pragma endregion // Exposed Draw Functions
};
Loading

0 comments on commit 7633bd5

Please sign in to comment.