diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h index fa5b0f061bda..3fbfe5bdc0e9 100644 --- a/core/math/geometry_2d.h +++ b/core/math/geometry_2d.h @@ -37,6 +37,7 @@ #include "core/math/vector2i.h" #include "core/math/vector3.h" #include "core/math/vector3i.h" +#include "core/templates/iterable.h" #include "core/templates/vector.h" class Geometry2D { @@ -461,41 +462,77 @@ class Geometry2D { return H; } - static Vector bresenham_line(const Point2i &p_from, const Point2i &p_to) { - Vector points; - - Vector2i delta = (p_to - p_from).abs() * 2; - Vector2i step = (p_to - p_from).sign(); - Vector2i current = p_from; - - if (delta.x > delta.y) { - int err = delta.x / 2; + class BresenhamIterator { + bool is_end; + Vector2i to; - for (; current.x != p_to.x; current.x += step.x) { - points.push_back(current); + Vector2i pos; + int err; + Vector2i delta; + Vector2i step; + public: + _FORCE_INLINE_ void operator++() { + if (pos == to) { + is_end = true; + return; + } + if (delta.x > delta.y) { err -= delta.y; if (err < 0) { - current.y += step.y; + pos.y += step.y; err += delta.x; } - } - } else { - int err = delta.y / 2; - - for (; current.y != p_to.y; current.y += step.y) { - points.push_back(current); - + pos.x += step.x; + } else { err -= delta.x; if (err < 0) { - current.x += step.x; + pos.x += step.x; err += delta.y; } + pos.y += step.y; } } - points.push_back(current); + _FORCE_INLINE_ Vector2i operator*() { + return pos; + } + + _FORCE_INLINE_ bool operator!=(const BresenhamIterator &p_it) const { + return (is_end && p_it.is_end) ? false : (is_end != p_it.is_end || pos != p_it.pos); + } + + public: + BresenhamIterator(const Vector2i &p_from, const Vector2i &p_to) { + is_end = false; + pos = p_from; + to = p_to; + + Vector2i offset = p_to - p_from; + delta = offset.abs() * 2; + step = offset.sign(); + if (delta.x > delta.y) { + err = delta.x / 2; + } else { + err = delta.y / 2; + } + } + + BresenhamIterator() { + is_end = true; + } + }; + + static Iterable bresenham_iter(Vector2i p_from, Vector2i p_to) { + return Iterable(BresenhamIterator(p_from, p_to), BresenhamIterator()); + } + + static Vector bresenham_line(const Point2i &p_from, const Point2i &p_to) { + Vector points; + for (Vector2i point : bresenham_iter(p_from, p_to)) { + points.push_back(point); + } return points; } diff --git a/editor/import/editor_atlas_packer.cpp b/editor/import/editor_atlas_packer.cpp index 94de4d1d2379..78086d1dde48 100644 --- a/editor/import/editor_atlas_packer.cpp +++ b/editor/import/editor_atlas_packer.cpp @@ -79,8 +79,8 @@ void EditorAtlasPacker::chart_pack(Vector &charts, int &r_width, int &r_h for (int k = 0; k < 3; k++) { int l = k == 0 ? 2 : k - 1; - Vector points = Geometry2D::bresenham_line(v[k], v[l]); - for (Point2i point : points) { + Iterable bresenham = Geometry2D::bresenham_iter(v[k], v[l]); + for (const Point2i &point : bresenham) { src_bitmap->set_bitv(point, true); } } diff --git a/editor/scene/2d/tiles/tile_data_editors.cpp b/editor/scene/2d/tiles/tile_data_editors.cpp index ec9f49357bf2..00766858e0b9 100644 --- a/editor/scene/2d/tiles/tile_data_editors.cpp +++ b/editor/scene/2d/tiles/tile_data_editors.cpp @@ -1114,9 +1114,9 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti Ref mm = p_event; if (mm.is_valid()) { if (drag_type == DRAG_TYPE_PAINT) { - Vector line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true)); - for (int i = 0; i < line.size(); i++) { - Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]); + Iterable bresenham = Geometry2D::bresenham_iter(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true)); + for (const Vector2i &c : bresenham) { + Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(c); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { TileMapCell cell; cell.source_id = 0; @@ -2202,9 +2202,9 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t Ref mm = p_event; if (mm.is_valid()) { if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) { - Vector line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true)); - for (int i = 0; i < line.size(); i++) { - Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]); + Iterable bresenham = Geometry2D::bresenham_iter(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true)); + for (const Vector2i &c : bresenham) { + Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(c); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { int terrain_set = drag_painted_value; TileMapCell cell; @@ -2236,9 +2236,9 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) { int terrain_set = Dictionary(drag_painted_value)["terrain_set"]; int terrain = Dictionary(drag_painted_value)["terrain"]; - Vector line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true)); - for (int i = 0; i < line.size(); i++) { - Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]); + Iterable bresenham = Geometry2D::bresenham_iter(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true)); + for (const Vector2i &c : bresenham) { + Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(c); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { TileMapCell cell; cell.source_id = 0; diff --git a/editor/scene/2d/tiles/tile_set_atlas_source_editor.cpp b/editor/scene/2d/tiles/tile_set_atlas_source_editor.cpp index eaf88eee05ad..c51d2ae0e13e 100644 --- a/editor/scene/2d/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/scene/2d/tiles/tile_set_atlas_source_editor.cpp @@ -1118,12 +1118,11 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords); - for (int i = 0; i < line.size(); i++) { - if (tile_set_atlas_source->get_tile_at_coords(line[i]) == TileSetSource::INVALID_ATLAS_COORDS) { - tile_set_atlas_source->create_tile(line[i]); - drag_modified_tiles.insert(line[i]); + Iterable bresenham = Geometry2D::bresenham_iter(last_base_tiles_coords, new_base_tiles_coords); + for (const Vector2i &c : bresenham) { + if (tile_set_atlas_source->get_tile_at_coords(c) == TileSetSource::INVALID_ATLAS_COORDS) { + tile_set_atlas_source->create_tile(c); + drag_modified_tiles.insert(c); } } @@ -1133,10 +1132,9 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords); - for (int i = 0; i < line.size(); i++) { - Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(line[i]); + Iterable bresenham = Geometry2D::bresenham_iter(last_base_tiles_coords, new_base_tiles_coords); + for (const Vector2i &c : bresenham) { + Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(c); if (base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) { drag_modified_tiles.insert(base_tile_coords); } diff --git a/editor/scene/curve_editor_plugin.cpp b/editor/scene/curve_editor_plugin.cpp index 1628491b0802..c2a2e28bb1b5 100644 --- a/editor/scene/curve_editor_plugin.cpp +++ b/editor/scene/curve_editor_plugin.cpp @@ -1087,8 +1087,8 @@ Ref CurvePreviewGenerator::generate(const Ref &p_from, cons v = (curve->sample_baked(t) - curve->get_min_value()) / curve->get_value_range(); y = CLAMP(im.get_height() - v * im.get_height(), 0, im.get_height() - 1); - Vector points = Geometry2D::bresenham_line(Point2i(x - 1, prev_y), Point2i(x, y)); - for (Point2i point : points) { + Iterable bresenham = Geometry2D::bresenham_iter(Point2i(x - 1, prev_y), Point2i(x, y)); + for (const Point2i &point : bresenham) { im.set_pixelv(point, line_color); } prev_y = y;