Created
June 15, 2020 09:21
-
-
Save SasLuca/2115826b6f6369a05e9f5115179a96a0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| typedef struct rf_sizef | |
| { | |
| float width, height; | |
| } rf_sizef; | |
| RF_API rf_sizef rf_measure_text_rec(rf_font font, const char* text, int text_len, rf_rec rec, float font_size, float extra_spacing, bool wrap) | |
| { | |
| rf_sizef result = {0}; | |
| if (font.valid) | |
| { | |
| int text_offset_x = 0; // Offset between characters | |
| int text_offset_y = 0; // Required for line break! | |
| float scale_factor = 0.0f; | |
| int letter = 0; // Current character | |
| int index = 0; // Index position in sprite font | |
| scale_factor = font_size / font.base_size; | |
| enum | |
| { | |
| MEASURE_WRAP_STATE = 0, | |
| MEASURE_REGULAR_STATE = 1 | |
| }; | |
| int state = wrap ? MEASURE_WRAP_STATE : MEASURE_REGULAR_STATE; | |
| int start_line = -1; // Index where to begin drawing (where a line begins) | |
| int end_line = -1; // Index where to stop drawing (where a line ends) | |
| int lastk = -1; // Holds last value of the character position | |
| int max_y = 0; | |
| int first_y = 0; | |
| bool first_y_set = false; | |
| for (int i = 0, k = 0; i < text_len; i++, k++) | |
| { | |
| int glyph_width = 0; | |
| rf_decoded_rune decoded_rune = rf_decode_utf8_char(&text[i], text_len - i); | |
| letter = decoded_rune.codepoint; | |
| index = rf_get_glyph_index(font, letter); | |
| // NOTE: normally we exit the decoding sequence as soon as a bad unsigned char is found (and return 0x3f) | |
| // but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1 | |
| if (letter == 0x3f) decoded_rune.bytes_processed = 1; | |
| i += decoded_rune.bytes_processed - 1; | |
| if (letter != '\n') | |
| { | |
| glyph_width = (font.glyphs[index].advance_x == 0) ? | |
| (int)(font.glyphs[index].width * scale_factor + extra_spacing) : | |
| (int)(font.glyphs[index].advance_x * scale_factor + extra_spacing); | |
| } | |
| // NOTE: When word_wrap is ON we first measure how much of the text we can draw before going outside of the rec container | |
| // We store this info in start_line and end_line, then we change states, draw the text between those two variables | |
| // and change states again and again recursively until the end of the text (or until we get outside of the container). | |
| // When word_wrap is OFF we don't need the measure state so we go to the drawing state immediately | |
| // and begin drawing on the next line before we can get outside the container. | |
| if (state == MEASURE_WRAP_STATE) | |
| { | |
| // TODO: there are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more | |
| // See: http://jkorpela.fi/chars/spaces.html | |
| if ((letter == ' ') || (letter == '\t') || (letter == '\n')) { end_line = i; } | |
| if ((text_offset_x + glyph_width + 1) >= rec.width) | |
| { | |
| end_line = (end_line < 1) ? i : end_line; | |
| if (i == end_line) { end_line -= decoded_rune.bytes_processed; } | |
| if ((start_line + decoded_rune.bytes_processed) == end_line) { end_line = i - decoded_rune.bytes_processed; } | |
| state = !state; | |
| } | |
| else if ((i + 1) == text_len) | |
| { | |
| end_line = i; | |
| state = !state; | |
| } | |
| else if (letter == '\n') | |
| { | |
| state = !state; | |
| } | |
| if (state == MEASURE_REGULAR_STATE) | |
| { | |
| text_offset_x = 0; | |
| i = start_line; | |
| glyph_width = 0; | |
| // Save character position when we switch states | |
| int tmp = lastk; | |
| lastk = k - 1; | |
| k = tmp; | |
| } | |
| } | |
| else | |
| { | |
| if (letter == '\n') | |
| { | |
| if (!wrap) | |
| { | |
| text_offset_y += (int)((font.base_size + font.base_size/2)*scale_factor); | |
| text_offset_x = 0; | |
| } | |
| } | |
| else | |
| { | |
| if (!wrap && (text_offset_x + glyph_width + 1) >= rec.width) | |
| { | |
| text_offset_y += (int)((font.base_size + font.base_size/2)*scale_factor); | |
| text_offset_x = 0; | |
| } | |
| if ((text_offset_y + (int)(font.base_size*scale_factor)) > rec.height) break; | |
| // The right side expression is the offset of the latest character plus its width (so the end of the line) | |
| // We want the highest value of that expression by the end of the function | |
| result.width = rf_max_f(result.width, rec.x + text_offset_x - 1 + glyph_width); | |
| if (!first_y_set) | |
| { | |
| first_y = rec.y + text_offset_y; | |
| first_y_set = true; | |
| } | |
| max_y = rf_max_i(max_y, rec.y + text_offset_y + font.base_size * scale_factor); | |
| } | |
| if (wrap && i == end_line) | |
| { | |
| text_offset_y += (int)((font.base_size + font.base_size/2)*scale_factor); | |
| text_offset_x = 0; | |
| start_line = end_line; | |
| end_line = -1; | |
| glyph_width = 0; | |
| k = lastk; | |
| state = !state; | |
| } | |
| } | |
| text_offset_x += glyph_width; | |
| } | |
| result.height = max_y - first_y; | |
| } | |
| return result; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment