piątek, 15 maja 2009

OpenGL w moim GUI

Cześć (Oddaję Tobie), czytelniku,

Pierwszy paragraf tak dla wyjaśnienia:
Jakieś dwa miesiące temu postanowiłem wprowadzić przyspieszenie sprzętowe i kompatybilność z OpenGL do mojej biblioteki GUI. Zrobiłem już Wysokopoziomowy interfejs rysujący i blitujący, który będzie wykorzystany w reszcie systemu GUI. Ten zestaw klas i funkcji deleguje żądania rysowania do kontekstu SDL (który jest tak naprawdę opakowaniem jakiegoś kontekstu odpowiedniego dla platformy, np. WinGDI) lub do OpenGL. Właściwymi miejscami do implementacji rysowania po ekranie bezpośrednio przez OpenGL lub SDL są klasy dziedziczące po PKgraphics_provider. PKgraphical_data zaś to klasa, która przechowuje bieżący obiekt PKgraphics_provider i umożliwia używanie zasobów, które muszą być wytworzone przy pomocy obiektu PKgraphics_provider, czyli zestawów tekstur klasy PKtexture_unit.
Mam już działające obiekty PKtexture_unit z wieloma teksturami (dla OpenGL) lub powierzchniami (dla SDL) wewnątrz. Powierzchnie graficzne, z których zostały stworzone tekstury są przywiązane do tych obiektów PKtexture_unit.
A teraz do rzeczy. Otóż z wprowadzenia do GUI tych machinacji wyniknął problem, mianowicie współdzielenie powierzchni (graficznych) przez różne obiekty w GUI nie wystarczy, bo są jeszcze obiekty PKtexture_unit, które nie są współdzielone (do samego współdzielenia obiektów używam inteligentnego wskaźnika). Wynika z tego fakt, że jeśli będzie 10 widżetów (np. przycisków) z tą samą teksturą, to w karcie graficznej będzie 10 kopii tej tekstury. To jest duży problem, zwłaszcza że GUI bywają bogate w widżety. Właśnie wymyśliłem rozwiązanie: flaga "immutable" w obiektach PKsurface, przechowujących powierzchnie graficzne. Jaki to ma związek? Rozumowanie jest proste: jeśli mam pewność, że powierzchnia nie będzie zmieniana, to mogę tworzyć z niej wiele obiektów PKtexture_unit i wszystkie będą takie same. A jeżeli wszystkie byłyby takie same, to można zamiast tego zrobić jeden i go współdzielić. To rozwiązanie jest dla mnie bardzo atrakcyjne, bo kod który teraz mam umożliwia bardzo łatwe zablokowanie wszelkich zmian w danej powierzchni, jeżeli jest w niej taka flaga. Wprowadza to jednak poważny problem: powierzchnia będzie niezmienna :) W takim razie powierzchnia jest właściwie "wymieniana" na teksturę. Można sobie wyobrazić funkcjonalność, która "oddaje" nam powierzchnię, gdy tekstura jest zwalniana. Idealne rozwiązanie polegałoby na wprowadzaniu wszystkich zmian powierzchni w teksturze, ale to oznaczałoby zmienianie dużej ilości kodu.
Muszę przyznać, ciekawi mnie, jak rozwiązano ten problem w innych GUI.
Po co piszę to na blogu? Po to, żeby uświadomić sobie, co tak naprawdę robię. Po krótkim przemyśleniu sprawy doszedłem do wniosku, że flaga "immutable" powinna być tam niezależnie od tego, czy obiekty PKtexture_unit są współdzielone, więc... kod, który teraz mam jest błędny. Kolejny wniosek to taki, że jeśli lepiej by było w ogóle nie "zaprzyjaźniać" powierzchni z teksturami. Istnienie powierzchni ma o tyle sens, że do niej można wczytać obrazek z pliku, albo można na niej coś łatwo narysować. Po przekształceniu w teksturę można ją natomiast wyrzucić. Po co zaśmiecać pamięć. Utrzymywanie powierzchni zaprzyjaźnionej z teksturą chyba ma sens tylko jeśli implementacja "odbija" na teksturze wszelkie zmiany popełnione na powierzchni. Wtedy jednak bardziej stosowna byłaby tekstura schowana w powierzchni, a nie odwrotnie.
Jeszcze inną sprawą jest to, że powierzchnia jest potrzebna np. do przeskalowania GUI. Sama tekstura nie wystarczy, bo powierzchnia może być np. złożona z wielu małych, co wymusza zupełnie inny algorytm skalowania niż rozciąganie. Skomplikowana sprawa.

Brak komentarzy:

Prześlij komentarz