| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2019-02-12 17:18:13 +01:00
										 |  |  | /*  bit_map.cpp                                                          */ | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							| 
									
										
										
										
											2017-08-27 14:16:55 +02:00
										 |  |  | /*                      https://godotengine.org                          */ | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2022-01-13 09:45:09 +01:00
										 |  |  | /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */ | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* 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.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 17:18:13 +01:00
										 |  |  | #include "bit_map.h"
 | 
					
						
							| 
									
										
										
										
											2018-08-14 14:30:15 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-11 18:13:45 +02:00
										 |  |  | #include "core/io/image_loader.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void BitMap::create(const Size2 &p_size) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(p_size.width < 1); | 
					
						
							|  |  |  | 	ERR_FAIL_COND(p_size.height < 1); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	width = p_size.width; | 
					
						
							|  |  |  | 	height = p_size.height; | 
					
						
							| 
									
										
										
										
											2021-05-08 01:19:18 +02:00
										 |  |  | 	bitmask.resize((((width * height) - 1) / 8) + 1); | 
					
						
							| 
									
										
										
										
											2021-04-29 12:34:11 +02:00
										 |  |  | 	memset(bitmask.ptrw(), 0, bitmask.size()); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 11:30:55 -05:00
										 |  |  | void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshold) { | 
					
						
							| 
									
										
										
										
											2017-05-17 07:36:47 -03:00
										 |  |  | 	ERR_FAIL_COND(p_image.is_null() || p_image->empty()); | 
					
						
							|  |  |  | 	Ref<Image> img = p_image->duplicate(); | 
					
						
							|  |  |  | 	img->convert(Image::FORMAT_LA8); | 
					
						
							|  |  |  | 	ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-17 07:36:47 -03:00
										 |  |  | 	create(Size2(img->get_width(), img->get_height())); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-17 07:36:47 -03:00
										 |  |  | 	PoolVector<uint8_t>::Read r = img->get_data().read(); | 
					
						
							| 
									
										
										
										
											2017-11-25 00:07:54 -03:00
										 |  |  | 	uint8_t *w = bitmask.ptrw(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	for (int i = 0; i < width * height; i++) { | 
					
						
							|  |  |  | 		int bbyte = i / 8; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		int bbit = i % 8; | 
					
						
							| 
									
										
										
										
											2018-02-21 11:30:55 -05:00
										 |  |  | 		if (r[i * 2 + 1] / 255.0 > p_threshold) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			w[bbyte] |= (1 << bbit); | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void BitMap::set_bit_rect(const Rect2 &p_rect, bool p_value) { | 
					
						
							|  |  |  | 	Rect2i current = Rect2i(0, 0, width, height).clip(p_rect); | 
					
						
							| 
									
										
										
										
											2017-11-25 00:07:54 -03:00
										 |  |  | 	uint8_t *data = bitmask.ptrw(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-04 00:25:13 +02:00
										 |  |  | 	for (int i = current.position.x; i < current.position.x + current.size.x; i++) { | 
					
						
							|  |  |  | 		for (int j = current.position.y; j < current.position.y + current.size.y; j++) { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 			int ofs = width * j + i; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			int bbyte = ofs / 8; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 			int bbit = ofs % 8; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			uint8_t b = data[bbyte]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			if (p_value) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				b |= (1 << bbit); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2018-01-09 16:31:30 +00:00
										 |  |  | 				b &= ~(1 << bbit); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			data[bbyte] = b; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int BitMap::get_true_bit_count() const { | 
					
						
							|  |  |  | 	int ds = bitmask.size(); | 
					
						
							|  |  |  | 	const uint8_t *d = bitmask.ptr(); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	int c = 0; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-04 19:11:39 +03:00
										 |  |  | 	//fast, almost branchless version
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	for (int i = 0; i < ds; i++) { | 
					
						
							|  |  |  | 		c += (d[i] & (1 << 7)) >> 7; | 
					
						
							|  |  |  | 		c += (d[i] & (1 << 6)) >> 6; | 
					
						
							|  |  |  | 		c += (d[i] & (1 << 5)) >> 5; | 
					
						
							|  |  |  | 		c += (d[i] & (1 << 4)) >> 4; | 
					
						
							|  |  |  | 		c += (d[i] & (1 << 3)) >> 3; | 
					
						
							|  |  |  | 		c += (d[i] & (1 << 2)) >> 2; | 
					
						
							| 
									
										
										
										
											2019-04-04 19:11:39 +03:00
										 |  |  | 		c += (d[i] & (1 << 1)) >> 1; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		c += d[i] & 1; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return c; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void BitMap::set_bit(const Point2 &p_pos, bool p_value) { | 
					
						
							| 
									
										
										
										
											2018-01-06 17:38:39 -03:00
										 |  |  | 	int x = p_pos.x; | 
					
						
							|  |  |  | 	int y = p_pos.y; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ERR_FAIL_INDEX(x, width); | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX(y, height); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int ofs = width * y + x; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	int bbyte = ofs / 8; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	int bbit = ofs % 8; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	uint8_t b = bitmask[bbyte]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (p_value) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		b |= (1 << bbit); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2018-01-09 16:31:30 +00:00
										 |  |  | 		b &= ~(1 << bbit); | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 	bitmask.write[bbyte] = b; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | bool BitMap::get_bit(const Point2 &p_pos) const { | 
					
						
							|  |  |  | 	int x = Math::fast_ftoi(p_pos.x); | 
					
						
							|  |  |  | 	int y = Math::fast_ftoi(p_pos.y); | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX_V(x, width, false); | 
					
						
							|  |  |  | 	ERR_FAIL_INDEX_V(y, height, false); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int ofs = width * y + x; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	int bbyte = ofs / 8; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	int bbit = ofs % 8; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	return (bitmask[bbyte] & (1 << bbit)) != 0; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Size2 BitMap::get_size() const { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	return Size2(width, height); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void BitMap::_set_data(const Dictionary &p_d) { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	ERR_FAIL_COND(!p_d.has("size")); | 
					
						
							|  |  |  | 	ERR_FAIL_COND(!p_d.has("data")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	create(p_d["size"]); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	bitmask = p_d["data"]; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | Dictionary BitMap::_get_data() const { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	Dictionary d; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	d["size"] = get_size(); | 
					
						
							|  |  |  | 	d["data"] = bitmask; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	return d; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 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; | 
					
						
							|  |  |  | 	Vector<Vector2> _points; | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		int sv = 0; | 
					
						
							|  |  |  | 		{ //square value
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/*
 | 
					
						
							| 
									
										
										
										
											2018-08-14 14:30:15 +02:00
										 |  |  | 			checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent | 
					
						
							|  |  |  | 			+---+---+ | 
					
						
							|  |  |  | 			| 1 | 2 | | 
					
						
							|  |  |  | 			+---+---+ | 
					
						
							|  |  |  | 			| 4 | 8 | <- current pixel (curx,cury) | 
					
						
							|  |  |  | 			+---+---+ | 
					
						
							|  |  |  | 			*/ | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 			Point2i tl = Point2i(curx - 1, cury - 1); | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 			sv += (rect.has_point(tl) && get_bit(tl)) ? 1 : 0; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 			Point2i tr = Point2i(curx, cury - 1); | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 			sv += (rect.has_point(tr) && get_bit(tr)) ? 2 : 0; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 			Point2i bl = Point2i(curx - 1, cury); | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 			sv += (rect.has_point(bl) && get_bit(bl)) ? 4 : 0; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 			Point2i br = Point2i(curx, cury); | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 			sv += (rect.has_point(br) && get_bit(br)) ? 8 : 0; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 			ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector<Vector2>()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch (sv) { | 
					
						
							|  |  |  | 			case 1: | 
					
						
							|  |  |  | 			case 5: | 
					
						
							|  |  |  | 			case 13: | 
					
						
							|  |  |  | 				/* going UP with these cases:
 | 
					
						
							| 
									
										
										
										
											2018-08-14 14:30:15 +02:00
										 |  |  | 				1          5           13 | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				| 1 |   |  | 1 |   |  | 1 |   | | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				|   |   |  | 4 |   |  | 4 | 8 | | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				*/ | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 				stepx = 0; | 
					
						
							|  |  |  | 				stepy = -1; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			case 8: | 
					
						
							|  |  |  | 			case 10: | 
					
						
							|  |  |  | 			case 11: | 
					
						
							|  |  |  | 				/* going DOWN with these cases:
 | 
					
						
							| 
									
										
										
										
											2018-08-14 14:30:15 +02:00
										 |  |  | 				8          10         11 | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				|   |   |  |   | 2 |  | 1 | 2 | | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				|   | 8 |  |   | 8 |  |   | 8 | | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				*/ | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 				stepx = 0; | 
					
						
							|  |  |  | 				stepy = 1; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			case 4: | 
					
						
							|  |  |  | 			case 12: | 
					
						
							|  |  |  | 			case 14: | 
					
						
							|  |  |  | 				/* going LEFT with these cases:
 | 
					
						
							| 
									
										
										
										
											2018-08-14 14:30:15 +02:00
										 |  |  | 				4          12         14 | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				|   |   |  |   |   |  |   | 2 | | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				| 4 |   |  | 4 | 8 |  | 4 | 8 | | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				*/ | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 				stepx = -1; | 
					
						
							|  |  |  | 				stepy = 0; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			case 2: | 
					
						
							|  |  |  | 			case 3: | 
					
						
							|  |  |  | 			case 7: | 
					
						
							|  |  |  | 				/* going RIGHT with these cases:
 | 
					
						
							| 
									
										
										
										
											2018-08-14 14:30:15 +02:00
										 |  |  | 				2          3          7 | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				|   | 2 |  | 1 | 2 |  | 1 | 2 | | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				|   |   |  |   |   |  | 4 |   | | 
					
						
							|  |  |  | 				+---+---+  +---+---+  +---+---+ | 
					
						
							|  |  |  | 				*/ | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 				stepx = 1; | 
					
						
							|  |  |  | 				stepy = 0; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case 9: | 
					
						
							|  |  |  | 				/*
 | 
					
						
							| 
									
										
										
										
											2018-08-14 14:30:15 +02:00
										 |  |  | 				+---+---+ | 
					
						
							|  |  |  | 				| 1 |   | | 
					
						
							|  |  |  | 				+---+---+ | 
					
						
							|  |  |  | 				|   | 8 | | 
					
						
							|  |  |  | 				+---+---+ | 
					
						
							|  |  |  | 				this should normally go UP, but if we already been here, we go down | 
					
						
							|  |  |  | 				*/ | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 				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: | 
					
						
							|  |  |  | 				/*
 | 
					
						
							| 
									
										
										
										
											2018-08-14 14:30:15 +02:00
										 |  |  | 				6 | 
					
						
							|  |  |  | 				+---+---+ | 
					
						
							|  |  |  | 				|   | 2 | | 
					
						
							|  |  |  | 				+---+---+ | 
					
						
							|  |  |  | 				| 4 |   | | 
					
						
							|  |  |  | 				+---+---+ | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 				this normally go RIGHT, but if its coming from RIGHT, it should go LEFT | 
					
						
							| 
									
										
										
										
											2018-08-14 14:30:15 +02:00
										 |  |  | 				*/ | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 				if (case6s.has(Point2i(curx, cury))) { | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 					//found, so we go left, and delete from case6s;
 | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 					stepx = -1; | 
					
						
							|  |  |  | 					stepy = 0; | 
					
						
							|  |  |  | 					case6s.erase(Point2i(curx, cury)); | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 					//not found, we go right, and add to case6s;
 | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 					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) { | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 			_points.write[_points.size() - 1].x = (float)(curx - rect.position.x); | 
					
						
							|  |  |  | 			_points.write[_points.size() - 1].y = (float)(cury + rect.position.y); | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			_points.push_back(Vector2((float)(curx - rect.position.x), (float)(cury + rect.position.y))); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		count++; | 
					
						
							|  |  |  | 		prevx = stepx; | 
					
						
							|  |  |  | 		prevy = stepy; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-21 20:57:39 +01:00
										 |  |  | 		ERR_FAIL_COND_V((int)count > width * height, _points); | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 	} 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) { | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	if (v.size() < 3) { | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 		return v; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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++) { | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 			left.write[i] = v[i]; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		right.resize(v.size() - index); | 
					
						
							|  |  |  | 		for (int i = 0; i < right.size(); i++) { | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 			right.write[i] = v[index + i]; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		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++) { | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 			r1.write[middle + i] = r2[i]; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		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) { | 
					
						
							| 
									
										
										
										
											2018-07-25 03:11:03 +02:00
										 |  |  | 		result.write[0].y = last.y; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 		result.resize(result.size() - 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | struct FillBitsStackEntry { | 
					
						
							|  |  |  | 	Point2i pos; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	int j; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) { | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 	// Using a custom stack to work iteratively to avoid stack overflow on big bitmaps
 | 
					
						
							|  |  |  | 	PoolVector<FillBitsStackEntry> stack; | 
					
						
							|  |  |  | 	// Tracking size since we won't be shrinking the stack vector
 | 
					
						
							|  |  |  | 	int stack_size = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Point2i pos = p_pos; | 
					
						
							| 
									
										
										
										
											2018-12-17 12:42:24 +01:00
										 |  |  | 	int next_i = 0; | 
					
						
							|  |  |  | 	int next_j = 0; | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	bool reenter = true; | 
					
						
							|  |  |  | 	bool popped = false; | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		if (reenter) { | 
					
						
							|  |  |  | 			next_i = pos.x - 1; | 
					
						
							|  |  |  | 			next_j = pos.y - 1; | 
					
						
							|  |  |  | 			reenter = false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (int i = next_i; i <= pos.x + 1; i++) { | 
					
						
							|  |  |  | 			for (int j = next_j; j <= pos.y + 1; j++) { | 
					
						
							|  |  |  | 				if (popped) { | 
					
						
							|  |  |  | 					// The next loop over j must start normally
 | 
					
						
							|  |  |  | 					next_j = pos.y; | 
					
						
							|  |  |  | 					popped = false; | 
					
						
							|  |  |  | 					// Skip because an iteration was already executed with current counter values
 | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 				if (i < rect.position.x || i >= rect.position.x + rect.size.x) { | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 					continue; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if (j < rect.position.y || j >= rect.position.y + rect.size.y) { | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 					continue; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 				if (p_map->get_bit(Vector2(i, j))) { | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 					continue; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 				} else if (p_src->get_bit(Vector2(i, j))) { | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 					p_map->set_bit(Vector2(i, j), true); | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 					FillBitsStackEntry se = { pos, i, j }; | 
					
						
							|  |  |  | 					stack.resize(MAX(stack_size + 1, stack.size())); | 
					
						
							|  |  |  | 					stack.set(stack_size, se); | 
					
						
							|  |  |  | 					stack_size++; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 					pos = Point2i(i, j); | 
					
						
							|  |  |  | 					reenter = true; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (reenter) { | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 		if (!reenter) { | 
					
						
							|  |  |  | 			if (stack_size) { | 
					
						
							|  |  |  | 				FillBitsStackEntry se = stack.get(stack_size - 1); | 
					
						
							|  |  |  | 				stack_size--; | 
					
						
							|  |  |  | 				pos = se.pos; | 
					
						
							|  |  |  | 				next_i = se.i; | 
					
						
							|  |  |  | 				next_j = se.j; | 
					
						
							|  |  |  | 				popped = true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while (reenter || popped); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-24 09:35:07 +02:00
										 |  |  | 	print_verbose("BitMap: Max stack size: " + itos(stack.size())); | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-10 01:37:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 14:20:36 +02:00
										 |  |  | Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const { | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 	Rect2i r = Rect2i(0, 0, width, height).clip(p_rect); | 
					
						
							| 
									
										
										
										
											2018-08-24 09:35:07 +02:00
										 |  |  | 	print_verbose("BitMap: Rect: " + r); | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Point2i from; | 
					
						
							|  |  |  | 	Ref<BitMap> fill; | 
					
						
							|  |  |  | 	fill.instance(); | 
					
						
							|  |  |  | 	fill->create(get_size()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-04 14:20:36 +02:00
										 |  |  | 	Vector<Vector<Vector2>> polygons; | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 	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))) { | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 				fill_bits(this, fill, Point2i(j, i), r); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 				Vector<Vector2> polygon = _march_square(r, Point2i(j, i)); | 
					
						
							| 
									
										
										
										
											2018-08-24 09:35:07 +02:00
										 |  |  | 				print_verbose("BitMap: Pre reduce: " + itos(polygon.size())); | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 				polygon = reduce(polygon, r, p_epsilon); | 
					
						
							| 
									
										
										
										
											2018-08-24 09:35:07 +02:00
										 |  |  | 				print_verbose("BitMap: Post reduce: " + itos(polygon.size())); | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (polygon.size() < 3) { | 
					
						
							|  |  |  | 					print_verbose("Invalid polygon, skipped"); | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 				polygons.push_back(polygon); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return polygons; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 	if (p_pixels == 0) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-14 11:40:55 +02:00
										 |  |  | 	bool bit_value = p_pixels > 0; | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 	p_pixels = Math::abs(p_pixels); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 	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++) { | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			if (bit_value == get_bit(Point2(j, i))) { | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			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++) { | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 					bool outside = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if ((x < p_rect.position.x) || (x >= p_rect.position.x + p_rect.size.x) || (y < p_rect.position.y) || (y >= p_rect.position.y + p_rect.size.y)) { | 
					
						
							|  |  |  | 						// outside of rectangle counts as bit not set
 | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 						if (!bit_value) { | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 							outside = true; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 						} else { | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 							continue; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					float d = Point2(j, i).distance_to(Point2(x, y)) - CMP_EPSILON; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 					if (d > p_pixels) { | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 						continue; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 					if (outside || (bit_value == copy->get_bit(Point2(x, y)))) { | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 						found = true; | 
					
						
							|  |  |  | 						break; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 				if (found) { | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (found) { | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | 				set_bit(Point2(j, i), bit_value); | 
					
						
							| 
									
										
										
										
											2018-02-21 09:38:21 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-06 18:45:24 +02:00
										 |  |  | void BitMap::shrink_mask(int p_pixels, const Rect2 &p_rect) { | 
					
						
							|  |  |  | 	grow_mask(-p_pixels, p_rect); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 21:11:54 +02:00
										 |  |  | Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const { | 
					
						
							| 
									
										
										
										
											2021-05-04 14:20:36 +02:00
										 |  |  | 	Vector<Vector<Vector2>> result = clip_opaque_to_polygons(p_rect, p_epsilon); | 
					
						
							| 
									
										
										
										
											2018-08-08 21:11:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Convert result to bindable types
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Array result_array; | 
					
						
							|  |  |  | 	result_array.resize(result.size()); | 
					
						
							|  |  |  | 	for (int i = 0; i < result.size(); i++) { | 
					
						
							|  |  |  | 		const Vector<Vector2> &polygon = result[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		PoolVector2Array polygon_array; | 
					
						
							|  |  |  | 		polygon_array.resize(polygon.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			PoolVector2Array::Write w = polygon_array.write(); | 
					
						
							|  |  |  | 			for (int j = 0; j < polygon.size(); j++) { | 
					
						
							|  |  |  | 				w[j] = polygon[j]; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		result_array[i] = polygon_array; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return result_array; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-20 13:51:51 +02:00
										 |  |  | void BitMap::resize(const Size2 &p_new_size) { | 
					
						
							| 
									
										
										
										
											2019-04-19 15:54:33 -03:00
										 |  |  | 	Ref<BitMap> new_bitmap; | 
					
						
							|  |  |  | 	new_bitmap.instance(); | 
					
						
							|  |  |  | 	new_bitmap->create(p_new_size); | 
					
						
							| 
									
										
										
										
											2019-05-20 13:51:51 +02:00
										 |  |  | 	int lw = MIN(width, p_new_size.width); | 
					
						
							|  |  |  | 	int lh = MIN(height, p_new_size.height); | 
					
						
							|  |  |  | 	for (int x = 0; x < lw; x++) { | 
					
						
							|  |  |  | 		for (int y = 0; y < lh; y++) { | 
					
						
							|  |  |  | 			new_bitmap->set_bit(Vector2(x, y), get_bit(Vector2(x, y))); | 
					
						
							| 
									
										
										
										
											2019-04-19 15:54:33 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	width = new_bitmap->width; | 
					
						
							|  |  |  | 	height = new_bitmap->height; | 
					
						
							|  |  |  | 	bitmask = new_bitmap->bitmask; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Ref<Image> BitMap::convert_to_image() const { | 
					
						
							|  |  |  | 	Ref<Image> image; | 
					
						
							|  |  |  | 	image.instance(); | 
					
						
							| 
									
										
										
										
											2019-05-20 13:51:51 +02:00
										 |  |  | 	image->create(width, height, false, Image::FORMAT_L8); | 
					
						
							| 
									
										
										
										
											2019-04-19 15:54:33 -03:00
										 |  |  | 	image->lock(); | 
					
						
							| 
									
										
										
										
											2019-05-20 13:51:51 +02:00
										 |  |  | 	for (int i = 0; i < width; i++) { | 
					
						
							|  |  |  | 		for (int j = 0; j < height; j++) { | 
					
						
							|  |  |  | 			image->set_pixel(i, j, get_bit(Point2(i, j)) ? Color(1, 1, 1) : Color(0, 0, 0)); | 
					
						
							| 
									
										
										
										
											2019-04-19 15:54:33 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	image->unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return image; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-20 13:51:51 +02:00
										 |  |  | void BitMap::blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap) { | 
					
						
							| 
									
										
										
										
											2019-04-19 15:54:33 -03:00
										 |  |  | 	int x = p_pos.x; | 
					
						
							|  |  |  | 	int y = p_pos.y; | 
					
						
							|  |  |  | 	int w = p_bitmap->get_size().width; | 
					
						
							|  |  |  | 	int h = p_bitmap->get_size().height; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-20 13:51:51 +02:00
										 |  |  | 	for (int i = 0; i < w; i++) { | 
					
						
							|  |  |  | 		for (int j = 0; j < h; j++) { | 
					
						
							|  |  |  | 			int px = x + i; | 
					
						
							|  |  |  | 			int py = y + j; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			if (px < 0 || px >= width) { | 
					
						
							| 
									
										
										
										
											2019-04-19 15:54:33 -03:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			if (py < 0 || py >= height) { | 
					
						
							| 
									
										
										
										
											2019-04-19 15:54:33 -03:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2021-05-05 12:44:11 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-05-20 13:51:51 +02:00
										 |  |  | 			if (p_bitmap->get_bit(Vector2(i, j))) { | 
					
						
							|  |  |  | 				set_bit(Vector2(x, y), true); | 
					
						
							| 
									
										
										
										
											2019-04-19 15:54:33 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | void BitMap::_bind_methods() { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create); | 
					
						
							| 
									
										
										
										
											2018-02-21 11:30:55 -05:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image", "threshold"), &BitMap::create_from_image_alpha, DEFVAL(0.1)); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_bit", "position", "bit"), &BitMap::set_bit); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_bit", "position"), &BitMap::get_bit); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-27 11:10:09 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_bit_rect", "rect", "bit"), &BitMap::set_bit_rect); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("get_true_bit_count"), &BitMap::get_true_bit_count); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("get_size"), &BitMap::get_size); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("_set_data"), &BitMap::_set_data); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("_get_data"), &BitMap::_get_data); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-08 21:11:54 +02:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("grow_mask", "pixels", "rect"), &BitMap::grow_mask); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("opaque_to_polygons", "rect", "epsilon"), &BitMap::_opaque_to_polygons_bind, DEFVAL(2.0)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-12 00:35:12 +02:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BitMap::BitMap() { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	width = 0; | 
					
						
							|  |  |  | 	height = 0; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //////////////////////////////////////
 |