summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
authorJuan Linietsky <juan@godotengine.org>2018-02-21 09:38:21 -0300
committerJuan Linietsky <juan@godotengine.org>2018-02-21 09:39:09 -0300
commit9e3a1e5401f9f807085547de0ecc3f527610daa4 (patch)
treeac58cd4f27e9dfe8ed550dfce9bfc442f29cd05a /scene
parent1c77fdcc8516cf2f0c5083d4840a684b9ad90958 (diff)
Add base support for 2D meshes in Godot, including Sprite -> Mesh2D conversion.
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/canvas_item.cpp20
-rw-r--r--scene/2d/canvas_item.h4
-rw-r--r--scene/2d/mesh_instance_2d.cpp76
-rw-r--r--scene/2d/mesh_instance_2d.h33
-rw-r--r--scene/register_scene_types.cpp2
-rw-r--r--scene/resources/bit_mask.cpp348
-rw-r--r--scene/resources/bit_mask.h8
7 files changed, 486 insertions, 5 deletions
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index 87bcdae527..8d7fce8cc4 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -684,7 +684,7 @@ void CanvasItem::draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos
ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw(canvas_item, p_pos, p_modulate);
+ p_texture->draw(canvas_item, p_pos, p_modulate, false, p_normal_map);
}
void CanvasItem::draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) {
@@ -779,6 +779,22 @@ void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Colo
VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, p_antialiased);
}
+void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map, RID p_skeleton) {
+
+ ERR_FAIL_COND(p_mesh.is_null());
+ RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+
+ VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), texture_rid, normal_map_rid, p_skeleton);
+}
+void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map) {
+
+ ERR_FAIL_COND(p_multimesh.is_null());
+ RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ VisualServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid, normal_map_rid);
+}
+
void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w) {
if (!drawing) {
@@ -1016,6 +1032,8 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "antialiased"), &CanvasItem::draw_colored_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1)), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "skeleton"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>()), DEFVAL(RID()));
+ ClassDB::bind_method(D_METHOD("draw_multimesh", "mesh", "texture", "normal_map"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>()));
ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform);
ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix);
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index 68384b9f1e..d0bf584b38 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -34,6 +34,7 @@
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "scene/resources/material.h"
+#include "scene/resources/multimesh.h"
#include "scene/resources/shader.h"
#include "scene/resources/texture.h"
@@ -282,6 +283,9 @@ public:
void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false);
void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false);
+ void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map, RID p_skeleton);
+ void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map);
+
void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1));
diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp
new file mode 100644
index 0000000000..184942663f
--- /dev/null
+++ b/scene/2d/mesh_instance_2d.cpp
@@ -0,0 +1,76 @@
+#include "mesh_instance_2d.h"
+
+void MeshInstance2D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_DRAW) {
+ if (mesh.is_valid()) {
+ draw_mesh(mesh, texture, normal_map, RID());
+ }
+ }
+}
+
+void MeshInstance2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshInstance2D::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance2D::get_mesh);
+
+ ClassDB::bind_method(D_METHOD("set_texture", "texture"), &MeshInstance2D::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &MeshInstance2D::get_texture);
+
+ ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &MeshInstance2D::set_normal_map);
+ ClassDB::bind_method(D_METHOD("get_normal_map"), &MeshInstance2D::get_normal_map);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
+}
+
+void MeshInstance2D::set_mesh(const Ref<Mesh> &p_mesh) {
+
+ mesh = p_mesh;
+ update();
+}
+
+Ref<Mesh> MeshInstance2D::get_mesh() const {
+
+ return mesh;
+}
+
+void MeshInstance2D::set_texture(const Ref<Texture> &p_texture) {
+
+ if (p_texture == texture)
+ return;
+ texture = p_texture;
+ update();
+ emit_signal("texture_changed");
+ _change_notify("texture");
+}
+
+void MeshInstance2D::set_normal_map(const Ref<Texture> &p_texture) {
+
+ normal_map = p_texture;
+ update();
+}
+
+Ref<Texture> MeshInstance2D::get_normal_map() const {
+
+ return normal_map;
+}
+
+Ref<Texture> MeshInstance2D::get_texture() const {
+
+ return texture;
+}
+
+Rect2 MeshInstance2D::_edit_get_rect() const {
+
+ if (mesh.is_valid()) {
+ AABB aabb = mesh->get_aabb();
+ return Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
+ }
+
+ return Node2D::_edit_get_rect();
+}
+
+MeshInstance2D::MeshInstance2D() {
+}
diff --git a/scene/2d/mesh_instance_2d.h b/scene/2d/mesh_instance_2d.h
new file mode 100644
index 0000000000..d1d1ade0ae
--- /dev/null
+++ b/scene/2d/mesh_instance_2d.h
@@ -0,0 +1,33 @@
+#ifndef MESH_INSTANCE_2D_H
+#define MESH_INSTANCE_2D_H
+
+#include "scene/2d/node_2d.h"
+
+class MeshInstance2D : public Node2D {
+ GDCLASS(MeshInstance2D, Node2D)
+
+ Ref<Mesh> mesh;
+
+ Ref<Texture> texture;
+ Ref<Texture> normal_map;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_mesh(const Ref<Mesh> &p_mesh);
+ Ref<Mesh> get_mesh() const;
+
+ void set_texture(const Ref<Texture> &p_texture);
+ Ref<Texture> get_texture() const;
+
+ void set_normal_map(const Ref<Texture> &p_texture);
+ Ref<Texture> get_normal_map() const;
+
+ virtual Rect2 _edit_get_rect() const;
+
+ MeshInstance2D();
+};
+
+#endif // MESH_INSTANCE_2D_H
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index bb0cf168af..19d8f09ebe 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -46,6 +46,7 @@
#include "scene/2d/light_2d.h"
#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/line_2d.h"
+#include "scene/2d/mesh_instance_2d.h"
#include "scene/2d/navigation2d.h"
#include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h"
@@ -434,6 +435,7 @@ void register_scene_types() {
ClassDB::register_class<AnimatedSprite>();
ClassDB::register_class<Position2D>();
ClassDB::register_class<Line2D>();
+ ClassDB::register_class<MeshInstance2D>();
ClassDB::register_virtual_class<CollisionObject2D>();
ClassDB::register_virtual_class<PhysicsBody2D>();
ClassDB::register_class<StaticBody2D>();
diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp
index ea313b5a20..6932a98c17 100644
--- a/scene/resources/bit_mask.cpp
+++ b/scene/resources/bit_mask.cpp
@@ -42,7 +42,7 @@ void BitMap::create(const Size2 &p_size) {
zeromem(bitmask.ptrw(), bitmask.size());
}
-void BitMap::create_from_image_alpha(const Ref<Image> &p_image) {
+void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_treshold) {
ERR_FAIL_COND(p_image.is_null() || p_image->empty());
Ref<Image> img = p_image->duplicate();
@@ -58,8 +58,9 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image) {
int bbyte = i / 8;
int bbit = i % 8;
- if (r[i * 2])
+ if (r[i * 2 + 1] / 255.0 > p_treshold) {
w[bbyte] |= (1 << bbit);
+ }
}
}
@@ -168,10 +169,351 @@ Dictionary BitMap::_get_data() const {
return d;
}
+Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) const {
+
+ int stepx = 0;
+ int stepy = 0;
+ int prevx = 0;
+ int prevy = 0;
+ int startx = start.x;
+ int starty = start.y;
+ int curx = startx;
+ int cury = starty;
+ unsigned int count = 0;
+ Set<Point2i> case9s;
+ Set<Point2i> case6s;
+ int i;
+ Vector<Vector2> _points;
+ do {
+ int sv = 0;
+ { //square value
+
+ /*
+ checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent
+ +---+---+
+ | 1 | 2 |
+ +---+---+
+ | 4 | 8 | <- current pixel (curx,cury)
+ +---+---+
+ */
+ //NOTE: due to the way we pick points from texture, rect needs to be smaller, otherwise it goes outside 1 pixel
+ Rect2i fixed_rect = Rect2i(rect.position, rect.size - Size2i(2, 2));
+ Point2i tl = Point2i(curx - 1, cury - 1);
+ sv += (fixed_rect.has_point(tl) && get_bit(tl)) ? 1 : 0;
+ Point2i tr = Point2i(curx, cury - 1);
+ sv += (fixed_rect.has_point(tr) && get_bit(tr)) ? 2 : 0;
+ Point2i bl = Point2i(curx - 1, cury);
+ sv += (fixed_rect.has_point(bl) && get_bit(bl)) ? 4 : 0;
+ Point2i br = Point2i(curx, cury);
+ sv += (fixed_rect.has_point(br) && get_bit(br)) ? 8 : 0;
+ ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector<Vector2>());
+ }
+
+ switch (sv) {
+
+ case 1:
+ case 5:
+ case 13:
+ /* going UP with these cases:
+ 1 5 13
+ +---+---+ +---+---+ +---+---+
+ | 1 | | | 1 | | | 1 | |
+ +---+---+ +---+---+ +---+---+
+ | | | | 4 | | | 4 | 8 |
+ +---+---+ +---+---+ +---+---+
+ */
+ stepx = 0;
+ stepy = -1;
+ break;
+
+ case 8:
+ case 10:
+ case 11:
+ /* going DOWN with these cases:
+ 8 10 11
+ +---+---+ +---+---+ +---+---+
+ | | | | | 2 | | 1 | 2 |
+ +---+---+ +---+---+ +---+---+
+ | | 8 | | | 8 | | | 8 |
+ +---+---+ +---+---+ +---+---+
+ */
+ stepx = 0;
+ stepy = 1;
+ break;
+
+ case 4:
+ case 12:
+ case 14:
+ /* going LEFT with these cases:
+ 4 12 14
+ +---+---+ +---+---+ +---+---+
+ | | | | | | | | 2 |
+ +---+---+ +---+---+ +---+---+
+ | 4 | | | 4 | 8 | | 4 | 8 |
+ +---+---+ +---+---+ +---+---+
+ */
+ stepx = -1;
+ stepy = 0;
+ break;
+
+ case 2:
+ case 3:
+ case 7:
+ /* going RIGHT with these cases:
+ 2 3 7
+ +---+---+ +---+---+ +---+---+
+ | | 2 | | 1 | 2 | | 1 | 2 |
+ +---+---+ +---+---+ +---+---+
+ | | | | | | | 4 | |
+ +---+---+ +---+---+ +---+---+
+ */
+ stepx = 1;
+ stepy = 0;
+ break;
+ case 9:
+ /*
+ +---+---+
+ | 1 | |
+ +---+---+
+ | | 8 |
+ +---+---+
+ this should normally go UP, but if we already been here, we go down
+ */
+ if (case9s.has(Point2i(curx, cury))) {
+ //found, so we go down, and delete from case9s;
+ stepx = 0;
+ stepy = 1;
+ case9s.erase(Point2i(curx, cury));
+ } else {
+ //not found, we go up, and add to case9s;
+ stepx = 0;
+ stepy = -1;
+ case9s.insert(Point2i(curx, cury));
+ }
+ break;
+ case 6:
+ /*
+ 6
+ +---+---+
+ | | 2 |
+ +---+---+
+ | 4 | |
+ +---+---+
+ this normally go RIGHT, but if its coming from UP, it should go LEFT
+ */
+ if (case6s.has(Point2i(curx, cury))) {
+ //found, so we go down, and delete from case6s;
+ stepx = -1;
+ stepy = 0;
+ case6s.erase(Point2i(curx, cury));
+ } else {
+ //not found, we go up, and add to case6s;
+ stepx = 1;
+ stepy = 0;
+ case6s.insert(Point2i(curx, cury));
+ }
+ break;
+ default:
+ ERR_PRINT("this shouldn't happen.");
+ }
+ //little optimization
+ // if previous direction is same as current direction,
+ // then we should modify the last vec to current
+ curx += stepx;
+ cury += stepy;
+ if (stepx == prevx && stepy == prevy) {
+ _points[_points.size() - 1].x = (float)(curx - rect.position.x);
+ _points[_points.size() - 1].y = (float)(cury + rect.position.y);
+ } else {
+ _points.push_back(Vector2((float)(curx - rect.position.x), (float)(cury + rect.position.y)));
+ }
+
+ count++;
+ prevx = stepx;
+ prevy = stepy;
+
+ ERR_FAIL_COND_V(count > width * height, _points);
+ } while (curx != startx || cury != starty);
+ return _points;
+}
+
+static float perpendicular_distance(const Vector2 &i, const Vector2 &start, const Vector2 &end) {
+ float res;
+ float slope;
+ float intercept;
+
+ if (start.x == end.x) {
+ res = Math::absf(i.x - end.x);
+ } else if (start.y == end.y) {
+ res = Math::absf(i.y - end.y);
+ } else {
+ slope = (end.y - start.y) / (end.x - start.x);
+ intercept = start.y - (slope * start.x);
+ res = Math::absf(slope * i.x - i.y + intercept) / Math::sqrt(Math::pow(slope, 2.0f) + 1.0);
+ }
+ return res;
+}
+
+static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) {
+ if (v.size() < 3)
+ return v;
+
+ int index = -1;
+ float dist = 0;
+ //not looping first and last point
+ for (size_t i = 1, size = v.size(); i < size - 1; ++i) {
+ float cdist = perpendicular_distance(v[i], v[0], v[v.size() - 1]);
+ if (cdist > dist) {
+ dist = cdist;
+ index = static_cast<int>(i);
+ }
+ }
+ if (dist > optimization) {
+
+ Vector<Vector2> left, right;
+ left.resize(index);
+ for (int i = 0; i < index; i++) {
+ left[i] = v[i];
+ }
+ right.resize(v.size() - index);
+ for (int i = 0; i < right.size(); i++) {
+ right[i] = v[index + i];
+ }
+ Vector<Vector2> r1 = rdp(left, optimization);
+ Vector<Vector2> r2 = rdp(right, optimization);
+
+ int middle = r1.size();
+ r1.resize(r1.size() + r2.size());
+ for (int i = 0; i < r2.size(); i++) {
+ r1[middle + i] = r2[i];
+ }
+ return r1;
+ } else {
+ Vector<Vector2> ret;
+ ret.push_back(v[0]);
+ ret.push_back(v[v.size() - 1]);
+ return ret;
+ }
+}
+
+static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect, float epsilon) {
+ int size = points.size();
+ // if there are less than 3 points, then we have nothing
+ ERR_FAIL_COND_V(size < 3, Vector<Vector2>());
+ // if there are less than 9 points (but more than 3), then we don't need to reduce it
+ if (size < 9) {
+ return points;
+ }
+
+ float maxEp = MIN(rect.size.width, rect.size.height);
+ float ep = CLAMP(epsilon, 0.0, maxEp / 2);
+ Vector<Vector2> result = rdp(points, ep);
+
+ Vector2 last = result[result.size() - 1];
+
+ if (last.y > result[0].y && last.distance_to(result[0]) < ep * 0.5f) {
+ result[0].y = last.y;
+ result.resize(result.size() - 1);
+ }
+ return result;
+}
+
+static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) {
+
+ for (int i = p_pos.x - 1; i <= p_pos.x + 1; i++) {
+ for (int j = p_pos.y - 1; j <= p_pos.y + 1; j++) {
+
+ if (i < rect.position.x || i >= rect.position.x + rect.size.x)
+ continue;
+ if (j < rect.position.y || j >= rect.position.y + rect.size.y)
+ continue;
+
+ if (p_map->get_bit(Vector2(i, j)))
+ continue;
+
+ else if (p_src->get_bit(Vector2(i, j))) {
+ p_map->set_bit(Vector2(i, j), true);
+ fill_bits(p_src, p_map, Point2i(i, j), rect);
+ }
+ }
+ }
+}
+Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const {
+
+ Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
+
+ print_line("Rect: " + r);
+ Point2i from;
+ Ref<BitMap> fill;
+ fill.instance();
+ fill->create(get_size());
+
+ Vector<Vector<Vector2> > polygons;
+ for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
+ for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
+ if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) {
+
+ Vector<Vector2> polygon = _march_square(r, Point2i(j, i));
+ print_line("pre reduce: " + itos(polygon.size()));
+ polygon = reduce(polygon, r, p_epsilon);
+ print_line("post reduce: " + itos(polygon.size()));
+ polygons.push_back(polygon);
+ fill_bits(this, fill, Point2i(j, i), r);
+ }
+ }
+ }
+
+ return polygons;
+}
+
+void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
+
+ Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
+
+ Ref<BitMap> copy;
+ copy.instance();
+ copy->create(get_size());
+ copy->bitmask = bitmask;
+
+ for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
+ for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
+ if (copy->get_bit(Point2(j, i)))
+ continue;
+
+ bool found = false;
+
+ for (int y = i - p_pixels; y <= i + p_pixels; y++) {
+ for (int x = j - p_pixels; x <= j + p_pixels; x++) {
+
+ if (x < p_rect.position.x || x >= p_rect.position.x + p_rect.size.x)
+ continue;
+ if (y < p_rect.position.y || y >= p_rect.position.y + p_rect.size.y)
+ continue;
+
+ float d = Point2(j, i).distance_to(Point2(x, y)) - CMP_EPSILON;
+ if (d > p_pixels)
+ continue;
+
+ if (copy->get_bit(Point2(x, y))) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+
+ if (found) {
+ set_bit(Point2(j, i), true);
+ }
+ }
+ }
+}
+
void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create);
- ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image"), &BitMap::create_from_image_alpha);
+ ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image", "treshold"), &BitMap::create_from_image_alpha, DEFVAL(0.1));
ClassDB::bind_method(D_METHOD("set_bit", "position", "bit"), &BitMap::set_bit);
ClassDB::bind_method(D_METHOD("get_bit", "position"), &BitMap::get_bit);
diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h
index cf126ef96b..d69db00d51 100644
--- a/scene/resources/bit_mask.h
+++ b/scene/resources/bit_mask.h
@@ -44,6 +44,8 @@ class BitMap : public Resource {
int width;
int height;
+ Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const;
+
protected:
void _set_data(const Dictionary &p_d);
Dictionary _get_data() const;
@@ -52,7 +54,7 @@ protected:
public:
void create(const Size2 &p_size);
- void create_from_image_alpha(const Ref<Image> &p_image);
+ void create_from_image_alpha(const Ref<Image> &p_image, float p_treshold = 0.1);
void set_bit(const Point2 &p_pos, bool p_value);
bool get_bit(const Point2 &p_pos) const;
@@ -61,6 +63,10 @@ public:
Size2 get_size() const;
+ void grow_mask(int p_pixels, const Rect2 &p_rect);
+
+ Vector<Vector<Vector2> > clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const;
+
BitMap();
};