Dlaczego tekst zawijany jest w nieprawidłowy sposób?

0

Witam! Mam metodę, która wyświetla tekst i chciałem dodać do niej możliwość przesunięcia tekstu do następnej linijki w momencie kiedy wystąpi '\n'

typedef unsigned int uint;

inline void RemoveCharFromString(std::string& string, char remove)						   
	{
		if (string.find(remove) != std::string::npos) {
			string.erase(std::remove(string.begin(), string.end(), remove), string.end());
		}
	}

void DrawString(const std::string& text, const Vector2& position, uint color, float scale, const Font& font)
	{
		using namespace ftgl;
		texture_font_t* ftFont = font.getFTFont();

		Vector2 finalPosition = position;
		std::string finalText = text;

		float lineHeight = font.getFontSize() * scale;
																													
		for (uint i = 0; i < finalText.length(); ++i) {
			texture_glyph_t* glyph = texture_font_get_glyph(ftFont, finalText.c_str() + i);
			if (glyph) {
				float kerning = 0.0f;
				if (i > 0) {
					kerning = texture_glyph_get_kerning(glyph, finalText.c_str() + i - 1);
				}	
				finalPosition.x += kerning * scale;
		
                                //Usuwam '\n', bo na ekranie pokazywał się kwadrat, a tego nie chce
				RemoveCharFromString(finalText, '\n');
                                //sprawdzam czy w tym nie usuniętym tekście jest gdzieś '\n', jeśli jest to tekst przesuwamy w dół i pozycję X ustawiamy na początek tekstu
				if(text[i] == '\n') {
					finalPosition.y -= lineHeight;
					finalPosition.x = position.x;
				}

				float x0 = finalPosition.x + static_cast<float>(glyph->offset_x) * scale,
					  y0 = finalPosition.y + static_cast<float>(glyph->offset_y) * scale,
					  x1 = x0 + static_cast<float>(glyph->width) * scale,
					  y1 = y0 - static_cast<float>(glyph->height) * scale,
					
					  u0 = glyph->s0,
					  v0 = glyph->t0,
					  u1 = glyph->s1,
					  v1 = glyph->t1;

                               //Dalej są x0, x1 itd.. przekazywane do buffera, nie ma znaczenia dla sprawy

				finalPosition.x += glyph->advance_x * scale;
			}
		}
	}

Problem pojawia się gdy w tekście jest więcej niż jeden '\n'

np.

Font jakisFont(...);

DrawString("String\nString", {300.0f, 300.0f}, 0xffffffff, 1.0f, jakisFont);

wyświetla

String
String

ale już

DrawString("String\nString\nString", {300.0f, 300.0f}, 0xffffffff, 1.0f, jakisFont);

wyświetla

String
Strings
tring

a powinien

String
String
String

Dlaczego tak się dzieje? W jaki sposób to naprawić?

0

IMO problemem jest samo podejście do tego zadania.

Niepotrzebnie usuwasz znaki z ciągu, przez co trudniej później dobrać się do danych konkretnych linii. Chyba najłatwiejszy sposób – i przy okazji czytelny – to podzielenie ciągu znaków na linie w pierwszym kroku, a w drugim ustalenie pozycji każdej linii. Ogólnie mowa o rozbiciu problemu renderowania tekstu na kilka kroków, gdzie każdy z nich to osobna metoda wykonująca jedną, konkretną czynność.

Nie jestem specjalistą od gamedevu (ani od C++), ale w swoim platformerku implementowałem znacznie bardziej złożony mechanizm renderowania tekstu z bitmap znaków (wieloliniowość, dowolny align i proste formatowanie), więc jeśli chcesz, to co nieco mogę na ten temat napisać.

0

Niepotrzebnie usuwasz znaki z ciągu, przez co trudniej później dobrać się do danych konkretnych linii.

Jak nie usunę to \n jest renderowane właśnie tak (na jakość tekstu proszę nie zwracać uwagi, korzystam z algorytmu signed distance field i mam ustawione wartości dla małego tekstu, a dla zwykłego sprawdzania nie chce mi się zmieniać):
screenshot-20181110210557.png
a problemu z odczytaniem danych kolejnej linii nie powinno być problemu, bo zawsze mamy const std::string& text, który jest niezmienny.

Chyba najłatwiejszy sposób – i przy okazji czytelny – to podzielenie ciągu znaków na linie w pierwszym kroku, a w drugim ustalenie pozycji każdej linii.

tutaj nie za bardzo rozumiem o co ci chodzi.

0

Mam na myśli to, że dla ułatwienia roboty możesz sobie najpierw podzielić wejściowy ciąg na podciągi, łącznie z pustymi liniami. Wrzuć sobie je do jakiegoś kontenera, np. do wektora stringów. Wydziel sobie kod odpowiedzialny za renderowanie do osobnej metody, do której owy wektor przekaż w parametrze. W tej metodzie po prostu iteruj po ciągach i renderuj tekst linia po linii, inkrementując offset Y w każdej iteracji.

Po prostu rozbij sobie jeden problem na dwa mniejsze – jeden to podział tekstu na linie, a drugi to renderowanie. Możesz sobie też samo renderowanie rozbić na dwie metody, bo malowanie jednej linii też wymaga kilku instrukcji i obliczeń (offsety, skalowanie).

1 użytkowników online, w tym zalogowanych: 0, gości: 1