Biblioteka SFML jest narzędziem, które do tej pory było omawiane przeze mnie w świetle glorii i chwały... niestety wszystko co ma blaski ma i również swe cienie, a teraz poznamy jeden z nich. Zanim jednak przejdę do sedna sprawy postaram się rzucić nieco światła na rangę problemu, który zostanie poruszony w niniejszym rozdziale.
Wyobraźmy sobie, że chcemy stworzyć sobie kontrolkę pola tekstowego. Pole tekstowe ma zazwyczaj to do siebie, że ma określone wymiary, a wewnątrz tego pola umieszczamy tekst. Ideą pola tekstowego jest również to, aby wpisana treść nie wychodziła poza jego obszar nawet jeżeli tekst jest zbyt długi by go całego wyświetlić. Do opisanego wyżej problemu zapewne podszedłbyś tak:
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow oknoAplikacji( sf::VideoMode( 320, 240, 32 ), "Kurs SFML - http://cpp0x.pl" );
sf::String tekst;
tekst.SetSize( 12 );
tekst.SetText( "to jest bardzo dlugi napis" );
tekst.SetColor( sf::Color::Red );
while( oknoAplikacji.IsOpened() )
{
sf::Event zdarzenie;
while( oknoAplikacji.GetEvent( zdarzenie ) )
{
if( zdarzenie.Type == sf::Event::Closed )
oknoAplikacji.Close();
if( zdarzenie.Type == sf::Event::KeyPressed && zdarzenie.Key.Code == sf::Key::Escape )
oknoAplikacji.Close();
if( zdarzenie.Type == sf::Event::MouseButtonPressed && zdarzenie.MouseButton.Button == sf::Mouse::Middle )
oknoAplikacji.Close();
}
oknoAplikacji.Clear( sf::Color( 0, 0, 0 ) );
oknoAplikacji.Draw( sf::Shape::Rectangle( 10, 10, 100, 30, sf::Color::White, 2, sf::Color::Green ) );
tekst.SetPosition( 12, 12 );
oknoAplikacji.Draw( tekst );
oknoAplikacji.Display();
}
return 0;
}
Powyższe podejście jest moim zdaniem całkowicie uzasadnione i naturalne, jednak efekt z pewnością nie będzie dla Ciebie zadowalający. Zrzut ekranu z działania powyższej aplikacji wygląda tak:
Pierwsze co prawdopodobnie Ci przyszło do głowy to 'ograniczyć w jakiś sposób obszar w którym tekst może być rysowany' - idea dobra, jednak SFML nie posiada takiego narzędzia, którym moglibyśmy to osiągnąć. Drugą metodą byłoby liczenie ile tekstu się zmieści i wyświetlanie tylko tego co się zmieści we wskazanym obszarze - niestety metoda ta wymaga stosunkowo dużego nakładu pracy, a i tak prędzej czy później natrafimy na przypadek gdzie takie ręczne wyliczanki nie będą po prostu możliwe.
Choć już czujesz w powietrzu złowrogą energię i czarne chmury zbierają się nad Tobą to możesz odetchnąć z ulgą, bowiem SFML ma furtkę zwaną
OpenGL. Wszystko co jest renderowane w oknie stworzonym za pomocą biblioteki SFML jest renderowane przy pomocy biblioteki
OpenGL. Biblioteka
OpenGL posiada z kolei narzędzie dzięki któremu możesz ograniczyć obszar renderowania do wskazanego fragmentu ekranu. Wszystko co zostanie narysowane poza wskazanym obszarem zostanie po prostu zignorowane. Brzmi pięknie? Myślę, że tak i teraz dowiesz się jak osiągnąć cel, który przez chwilę wydawał się być niemożliwy do osiągnięcia :)
Aby określić obszar, który może być modyfikowany należy skorzystać z funkcji
glScissor biblioteki
OpenGL. Skorzystanie z tej funkcji nie wymaga od Ciebie dołączania żadnych plików nagłówkowych ponieważ biblioteka SFML jest oparta o bibliotekę
OpenGL i dołącza wszelkie niezbędne pliki wspomnianej biblioteki. Funkcja
glScissor przyjmuje cztery argumenty i są nimi kolejno:
W myśl opisanej wyżej idei do wcześniej wspomnianej aplikacji powinniśmy dopisać następujący wiersz:
::glScissor( 12, oknoAplikacji.GetHeight() - 28, 86, 16 );
Wywołanie tej funkcji nie odniesie jednak skutku jeżeli nie włączymy mechanizmu obcinania. W bibliotece
OpenGL wszelkie mechanizmy włącza się przy pomocy funkcji
glEnable, natomiast funkcja
glDisable służy do wyłączania mechanizmów. Kod, który należy poprawić to:
::glEnable( GL_SCISSOR_TEST );
::glScissor( 12, oknoAplikacji.GetHeight() - 28, 86, 16 );
tekst.SetPosition( 12, 12 );
oknoAplikacji.Draw( tekst );
::glDisable( GL_SCISSOR_TEST );
Po naniesieniu wyżej opisanych poprawek nasz kod aplikacji będzie wyglądał tak:
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow oknoAplikacji( sf::VideoMode( 320, 240, 32 ), "Kurs SFML - http://cpp0x.pl" );
sf::String tekst;
tekst.SetSize( 12 );
tekst.SetText( "to jest bardzo dlugi napis" );
tekst.SetColor( sf::Color::Red );
while( oknoAplikacji.IsOpened() )
{
sf::Event zdarzenie;
while( oknoAplikacji.GetEvent( zdarzenie ) )
{
if( zdarzenie.Type == sf::Event::Closed )
oknoAplikacji.Close();
if( zdarzenie.Type == sf::Event::KeyPressed && zdarzenie.Key.Code == sf::Key::Escape )
oknoAplikacji.Close();
if( zdarzenie.Type == sf::Event::MouseButtonPressed && zdarzenie.MouseButton.Button == sf::Mouse::Middle )
oknoAplikacji.Close();
}
oknoAplikacji.Clear( sf::Color( 0, 0, 0 ) );
oknoAplikacji.Draw( sf::Shape::Rectangle( 10, 10, 100, 30, sf::Color::White, 2, sf::Color::Green ) );
::glEnable( GL_SCISSOR_TEST );
::glScissor( 12, oknoAplikacji.GetHeight() - 28, 86, 16 );
tekst.SetPosition( 12, 12 );
oknoAplikacji.Draw( tekst );
::glDisable( GL_SCISSOR_TEST );
oknoAplikacji.Display();
}
return 0;
}
Efekt, który uzyskamy po naniesieniu wspomnianych poprawek będzie następujący:
Wilk jest więc syty i owca cała - to by było na tyle w tym rozdziale :)