diff options
Diffstat (limited to 'core/io')
-rw-r--r-- | core/io/image.cpp | 156 | ||||
-rw-r--r-- | core/io/pck_packer.cpp | 2 | ||||
-rw-r--r-- | core/io/xml_parser.cpp | 69 | ||||
-rw-r--r-- | core/io/xml_parser.h | 8 |
4 files changed, 157 insertions, 78 deletions
diff --git a/core/io/image.cpp b/core/io/image.cpp index 65addaf964..21146dd80c 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -1341,78 +1341,126 @@ void Image::crop(int p_width, int p_height) { void Image::rotate_90(ClockDirection p_direction) { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); - ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); - ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); - - int saved_width = height; - int saved_height = width; - - if (width != height) { - int n = MAX(width, height); - resize(n, n, INTERPOLATE_NEAREST); - } + ERR_FAIL_COND_MSG(width <= 0, "The Image width specified (" + itos(width) + " pixels) must be greater than 0 pixels."); + ERR_FAIL_COND_MSG(height <= 0, "The Image height specified (" + itos(height) + " pixels) must be greater than 0 pixels."); bool used_mipmaps = has_mipmaps(); if (used_mipmaps) { clear_mipmaps(); } + // In-place 90 degrees rotation by following the permutation cycles. { - uint8_t *w = data.ptrw(); - uint8_t src[16]; - uint8_t dst[16]; + // Explanation by example (clockwise): + // + // abc da + // def -> eb + // fc + // + // In memory: + // 012345 012345 + // abcdef -> daebfc + // + // Permutation cycles: + // (0 --a--> 1 --b--> 3 --d--> 0) + // (2 --c--> 5 --f--> 4 --e--> 2) + // + // Applying cycles (backwards): + // 0->s s=a (store) + // 3->0 abcdef -> dbcdef + // 1->3 dbcdef -> dbcbef + // s->1 dbcbef -> dacbef + // + // 2->s s=c + // 4->2 dacbef -> daebef + // 5->4 daebef -> daebff + // s->5 daebff -> daebfc + + const int w = width; + const int h = height; + const int size = w * h; + + uint8_t *data_ptr = data.ptrw(); uint32_t pixel_size = get_format_pixel_size(format); - // Flip. + uint8_t single_pixel_buffer[16]; - if (p_direction == CLOCKWISE) { - for (int y = 0; y < height / 2; y++) { - for (int x = 0; x < width; x++) { - _get_pixelb(x, y, pixel_size, w, src); - _get_pixelb(x, height - y - 1, pixel_size, w, dst); +#define PREV_INDEX_IN_CYCLE(index) (p_direction == CLOCKWISE) ? ((h - 1 - (index % h)) * w + (index / h)) : ((index % h) * w + (w - 1 - (index / h))) - _put_pixelb(x, height - y - 1, pixel_size, w, src); - _put_pixelb(x, y, pixel_size, w, dst); + if (w == h) { // Square case, 4-length cycles only (plus irrelevant thus skipped 1-length cycle in the middle for odd-sized squares). + for (int y = 0; y < h / 2; y++) { + for (int x = 0; x < (w + 1) / 2; x++) { + int current = y * w + x; + memcpy(single_pixel_buffer, data_ptr + current * pixel_size, pixel_size); + for (int i = 0; i < 3; i++) { + int prev = PREV_INDEX_IN_CYCLE(current); + memcpy(data_ptr + current * pixel_size, data_ptr + prev * pixel_size, pixel_size); + current = prev; + } + memcpy(data_ptr + current * pixel_size, single_pixel_buffer, pixel_size); } } - } else { - for (int y = 0; y < height; y++) { - for (int x = 0; x < width / 2; x++) { - _get_pixelb(x, y, pixel_size, w, src); - _get_pixelb(width - x - 1, y, pixel_size, w, dst); + } else { // Rectangular case (w != h), kinda unpredictable cycles. + int permuted_pixels_count = 0; + + for (int i = 0; i < size; i++) { + int prev = PREV_INDEX_IN_CYCLE(i); + if (prev == i) { + // 1-length cycle, pixel remains at the same index. + permuted_pixels_count++; + continue; + } - _put_pixelb(width - x - 1, y, pixel_size, w, src); - _put_pixelb(x, y, pixel_size, w, dst); + // Check whether we already processed this cycle. + // We iterate over it and if we'll find an index smaller than `i` then we already + // processed this cycle because we always start at the smallest index in the cycle. + // TODO: Improve this naive approach, can be done better. + while (prev > i) { + prev = PREV_INDEX_IN_CYCLE(prev); + } + if (prev < i) { + continue; } - } - } - // Transpose. + // Save the in-cycle pixel with the smallest index (`i`). + memcpy(single_pixel_buffer, data_ptr + i * pixel_size, pixel_size); - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - if (x < y) { - _get_pixelb(x, y, pixel_size, w, src); - _get_pixelb(y, x, pixel_size, w, dst); + // Overwrite pixels one by one by the preceding pixel in the cycle. + int current = i; + prev = PREV_INDEX_IN_CYCLE(current); + while (prev != i) { + memcpy(data_ptr + current * pixel_size, data_ptr + prev * pixel_size, pixel_size); + permuted_pixels_count++; - _put_pixelb(y, x, pixel_size, w, src); - _put_pixelb(x, y, pixel_size, w, dst); + current = prev; + prev = PREV_INDEX_IN_CYCLE(current); + }; + + // Overwrite the remaining pixel in the cycle by the saved pixel with the smallest index. + memcpy(data_ptr + current * pixel_size, single_pixel_buffer, pixel_size); + permuted_pixels_count++; + + if (permuted_pixels_count == size) { + break; } } + + width = h; + height = w; } + +#undef PREV_INDEX_IN_CYCLE } - if (saved_width != saved_height) { - resize(saved_width, saved_height, INTERPOLATE_NEAREST); - } else if (used_mipmaps) { + if (used_mipmaps) { generate_mipmaps(); } } void Image::rotate_180() { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); - ERR_FAIL_COND_MSG(width <= 1, "The Image width specified (" + itos(width) + " pixels) must be greater than 1 pixels."); - ERR_FAIL_COND_MSG(height <= 1, "The Image height specified (" + itos(height) + " pixels) must be greater than 1 pixels."); + ERR_FAIL_COND_MSG(width <= 0, "The Image width specified (" + itos(width) + " pixels) must be greater than 0 pixels."); + ERR_FAIL_COND_MSG(height <= 0, "The Image height specified (" + itos(height) + " pixels) must be greater than 0 pixels."); bool used_mipmaps = has_mipmaps(); if (used_mipmaps) { @@ -1420,19 +1468,21 @@ void Image::rotate_180() { } { - uint8_t *w = data.ptrw(); - uint8_t src[16]; - uint8_t dst[16]; + uint8_t *data_ptr = data.ptrw(); uint32_t pixel_size = get_format_pixel_size(format); - for (int y = 0; y < height / 2; y++) { - for (int x = 0; x < width; x++) { - _get_pixelb(x, y, pixel_size, w, src); - _get_pixelb(width - x - 1, height - y - 1, pixel_size, w, dst); + uint8_t single_pixel_buffer[16]; - _put_pixelb(width - x - 1, height - y - 1, pixel_size, w, src); - _put_pixelb(x, y, pixel_size, w, dst); - } + uint8_t *from_begin_ptr = data_ptr; + uint8_t *from_end_ptr = data_ptr + (width * height - 1) * pixel_size; + + while (from_begin_ptr < from_end_ptr) { + memcpy(single_pixel_buffer, from_begin_ptr, pixel_size); + memcpy(from_begin_ptr, from_end_ptr, pixel_size); + memcpy(from_end_ptr, single_pixel_buffer, pixel_size); + + from_begin_ptr += pixel_size; + from_end_ptr -= pixel_size; } } diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index aa1b323db2..0118b4c6af 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -107,6 +107,8 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String & } Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encrypt) { + ERR_FAIL_COND_V_MSG(file.is_null(), ERR_INVALID_PARAMETER, "File must be opened before use."); + Ref<FileAccess> f = FileAccess::open(p_src, FileAccess::READ); if (f.is_null()) { return ERR_FILE_CANT_OPEN; diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index abae48fdd8..16b7f3a1f6 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -41,11 +41,11 @@ static inline bool _is_white_space(char c) { } //! sets the state that text was found. Returns true if set should be set -bool XMLParser::_set_text(char *start, char *end) { +bool XMLParser::_set_text(const char *start, const char *end) { // check if text is more than 2 characters, and if not, check if there is // only white space, so that this text won't be reported if (end - start < 3) { - char *p = start; + const char *p = start; for (; p != end; ++p) { if (!_is_white_space(*p)) { break; @@ -92,7 +92,7 @@ void XMLParser::_parse_closing_xml_element() { void XMLParser::_ignore_definition() { node_type = NODE_UNKNOWN; - char *F = P; + const char *F = P; // move until end marked with '>' reached while (*P && *P != '>') { next_char(); @@ -123,8 +123,8 @@ bool XMLParser::_parse_cdata() { return true; } - char *cDataBegin = P; - char *cDataEnd = nullptr; + const char *cDataBegin = P; + const char *cDataEnd = nullptr; // find end of CDATA while (*P && !cDataEnd) { @@ -152,9 +152,9 @@ void XMLParser::_parse_comment() { node_type = NODE_COMMENT; P += 1; - char *pEndOfInput = data + length; - char *pCommentBegin; - char *pCommentEnd; + const char *pEndOfInput = data + length; + const char *pCommentBegin; + const char *pCommentEnd; if (P + 1 < pEndOfInput && P[0] == '-' && P[1] == '-') { // Comment, use '-->' as end. @@ -293,7 +293,7 @@ void XMLParser::_parse_opening_xml_element() { } void XMLParser::_parse_current_node() { - char *start = P; + const char *start = P; node_offset = P - data; // more forward until '<' found @@ -458,15 +458,36 @@ bool XMLParser::is_empty() const { Error XMLParser::open_buffer(const Vector<uint8_t> &p_buffer) { ERR_FAIL_COND_V(p_buffer.size() == 0, ERR_INVALID_DATA); - if (data) { - memdelete_arr(data); + if (data_copy) { + memdelete_arr(data_copy); + data_copy = nullptr; } length = p_buffer.size(); - data = memnew_arr(char, length + 1); - memcpy(data, p_buffer.ptr(), length); - data[length] = 0; + data_copy = memnew_arr(char, length + 1); + memcpy(data_copy, p_buffer.ptr(), length); + data_copy[length] = 0; + data = data_copy; + P = data; + current_line = 0; + + return OK; +} + +Error XMLParser::_open_buffer(const uint8_t *p_buffer, size_t p_size) { + ERR_FAIL_COND_V(p_size == 0, ERR_INVALID_DATA); + ERR_FAIL_COND_V(!p_buffer, ERR_INVALID_DATA); + + if (data_copy) { + memdelete_arr(data_copy); + data_copy = nullptr; + } + + length = p_size; + data = (const char *)p_buffer; P = data; + current_line = 0; + return OK; } @@ -479,13 +500,15 @@ Error XMLParser::open(const String &p_path) { length = file->get_length(); ERR_FAIL_COND_V(length < 1, ERR_FILE_CORRUPT); - if (data) { - memdelete_arr(data); + if (data_copy) { + memdelete_arr(data_copy); + data_copy = nullptr; } - data = memnew_arr(char, length + 1); - file->get_buffer((uint8_t *)data, length); - data[length] = 0; + data_copy = memnew_arr(char, length + 1); + file->get_buffer((uint8_t *)data_copy, length); + data_copy[length] = 0; + data = data_copy; P = data; current_line = 0; @@ -512,8 +535,9 @@ void XMLParser::skip_section() { } void XMLParser::close() { - if (data) { + if (data_copy) { memdelete_arr(data); + data_copy = nullptr; } data = nullptr; length = 0; @@ -528,7 +552,8 @@ int XMLParser::get_current_line() const { } XMLParser::~XMLParser() { - if (data) { - memdelete_arr(data); + if (data_copy) { + memdelete_arr(data_copy); + data_copy = nullptr; } } diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h index aea252ddc7..be44f771dc 100644 --- a/core/io/xml_parser.h +++ b/core/io/xml_parser.h @@ -65,8 +65,9 @@ public: }; private: - char *data = nullptr; - char *P = nullptr; + char *data_copy = nullptr; + const char *data = nullptr; + const char *P = nullptr; uint64_t length = 0; uint64_t current_line = 0; String node_name; @@ -81,7 +82,7 @@ private: Vector<Attribute> attributes; - bool _set_text(char *start, char *end); + bool _set_text(const char *start, const char *end); void _parse_closing_xml_element(); void _ignore_definition(); bool _parse_cdata(); @@ -118,6 +119,7 @@ public: Error open(const String &p_path); Error open_buffer(const Vector<uint8_t> &p_buffer); + Error _open_buffer(const uint8_t *p_buffer, size_t p_size); void close(); |