TextureManager - Identifizieren von Texturen
-
Grüss euch.
Ich arbeite gerade an meinem TextureManager. Damit meine ich jetzt nicht eine Klasse die Texturen lädt, sondern eine Klasse die die verwendeten Texturen im Auge behält und lädt/entlädt.
Jetzt gehts um die Identifizierung von Texturen.
Grund:
Ich will doppeltes laden von Texturen verhindern, um Speicher zu sparen.
Wie würdet Ihr das anstellen? Ich dachte an 2 Möglichkeiten:
- Jede Textur bekommt einen String zugewiesen, optimalerweise den Namen mit dem sie auch aus den xml-dateien geladen wird. Ist zwar optional mit den xml, aber man kanns ja auch so festlegen.
- Wie oben, nur wird nicht der String abgespeichert, sondern ein Hash des Namens ODER der Daten.Es geht mir vor allem um Effizienz, allerdings weiss ich, dass bei Hashes es trotz allem zu Kollisionen kommen kann. Welche Methode würdet Ihr hier verwenden?
http://www.fantasy-coders.de/projects/gh/html/x435.html
Diese Übersicht hab ich mal als Auswahls-Möglichkeiten genommen.
Bin für Anregungen echt Dankbar :).
rya.
-
wie identifizierst du texturen zZ? vermutlich ueber den dateinamen, wieso machst du das nicht weiterhin so?
bzw.:
Wieviele texturen hast du vor zu laden, dass es ein performanceunterschied macht ob du ne hashstring-map oder ne string-map hast?
-
Zur Zeit identifizier ich sie gar nicht. Ich habe eine einfache Klasse, die eine Textur laden kann, sie binden kann (via glBindTexture), etc etc.
Benutzung läuft so:dtTexture texture; texture.load(_T("MyTexture.tga"); texture.attach(); [..] // Objekt zeichnen texture.detach();Ich möchte jetzt halt einen Manager einbauen, der als Singleton agiert und die Texturen direkt lädt, über diese Klasse.
Es wird dann so umgesetzt, dass von der Klasse dtTexture einfach nur die TexturID genommen und gespeichert wird.Und wieviel Texturen, tja das is die Frage^^. Ich weiss es nicht, wieviele es sind/werden, weil ich eine DLL programmiere, mit der theoretisch eben auch jemand anders seine Spiele oder was auch immer schreiben kann^^.
Nein, Engine nenne ich es nicht.
Es ist halt eine Studie von mir, in der ich Versuche alles gelernte umzusetzen und neue Sachen zu lernen :).rya.
-
Scorcher24 schrieb:
Zur Zeit identifizier ich sie gar nicht. Ich habe eine einfache Klasse, die eine Textur laden kann, sie binden kann (via glBindTexture), etc etc.
Benutzung läuft so:dtTexture texture; texture.load(_T("MyTexture.tga"); texture.attach(); [..] // Objekt zeichnen texture.detach();mach es weiter so, duerfte am besten und performantesten sein.
Ich möchte jetzt halt einen Manager einbauen, der als Singleton agiert und die Texturen direkt lädt, über diese Klasse.
Es wird dann so umgesetzt, dass von der Klasse dtTexture einfach nur die TexturID genommen und gespeichert wird.IDs gab es vor 20jahren unter c, heute verwendet man (auto)pointer und proxy klassen.
Und wieviel Texturen, tja das is die Frage^^. Ich weiss es nicht, wieviele es sind/werden, weil ich eine DLL programmiere, mit der theoretisch eben auch jemand anders seine Spiele oder was auch immer schreiben kann^^.
Nein, Engine nenne ich es nicht.
selbst wenn du eine textur mittels strings aus einer map mit 10000texturen raussuchst, dauert es sicher weniger zeit als eine textur zu laden. da besteht in der hinsicht also kaum optimierungsnot

Es ist halt eine Studie von mir, in der ich Versuche alles gelernte umzusetzen und neue Sachen zu lernen :).
dann versuch es ein wenig objekt orientierter zu machen, stichwoerter: waren eben resource proxy, autopointer, refcounting
-
Diese ID ist die von OpenGL... die muss ich verwenden *g*. Sonst kann ich ja die Textur nicht mehr anzeigen.
Ausser es gibt noch irgendeine Extension die ich übersehen hab :).selbst wenn du eine textur mittels strings aus einer map mit 10000texturen raussuchst, dauert es sicher weniger zeit als eine textur zu laden. da besteht in der hinsicht also kaum optimierungsnot
Danke für die Bestätigung. Es heisst halt immer, dass Strings so furchtbar langsam wären. Aber wenn das reicht, dann bin ich ja beruhigt. Ok, so ein Durschnitts-spiel hat ja auch nicht 10k Texturen... vllt 20-30, ein Industriespiel kommt vllt auf 200-300 geschätzt.
dann versuch es ein wenig objekt orientierter zu machen, stichwoerter: waren eben resource proxy, autopointer, refcounting
Uff, sagt mir jetzt gerade ehrlich gesagt alles nicht wirklich was..
Meinst du mit Resource-Proxy eine Klasse, der man versch. Orte angeben kann wie als "./data" und die dann automatisch die Dateien sucht?
Quasi so:ResourceMgr.addResourcePath("./data/"); ResourceMgr.loadTexture("myTexture.tga");Sowas hab ich nämlich schon in Arbeit :).
Danke :).
rya.
-
Scorcher24 schrieb:
Diese ID ist die von OpenGL... die muss ich verwenden *g*. Sonst kann ich ja die Textur nicht mehr anzeigen.
Ausser es gibt noch irgendeine Extension die ich übersehen hab :).Hast du oben auch nicht verwendet, sondern eine klasse. dein singleton sollte auch nicht mehr machen als diese klassen verwalten. von aussen hast du dann einen pointer drauf (autoptr im bestfall)
selbst wenn du eine textur mittels strings aus einer map mit 10000texturen raussuchst, dauert es sicher weniger zeit als eine textur zu laden. da besteht in der hinsicht also kaum optimierungsnot
Danke für die Bestätigung. Es heisst halt immer, dass Strings so furchtbar langsam wären. Aber wenn das reicht, dann bin ich ja beruhigt. Ok, so ein Durschnitts-spiel hat ja auch nicht 10k Texturen... vllt 20-30, ein Industriespiel kommt vllt auf 200-300 geschätzt.
man muss immer den kosten/nutzen sehen. strings sind langsam. aber wenn dein spiel eine stunge laeuft. davon vielleicht 90s ladezeit sind. davon wieder 0.1s fuers suchen von strings draufgeben beim laden, kann man mit der zeit viel wichtigerere optimierungen vornehmen

dann versuch es ein wenig objekt orientierter zu machen, stichwoerter: waren eben resource proxy, autopointer, refcounting
Uff, sagt mir jetzt gerade ehrlich gesagt alles nicht wirklich was..
Meinst du mit Resource-Proxy eine Klasse, der man versch. Orte angeben kann wie als "./data" und die dann automatisch die Dateien sucht?
Quasi so:ResourceMgr.addResourcePath("./data/"); ResourceMgr.loadTexture("myTexture.tga");Sowas hab ich nämlich schon in Arbeit :).
du weisst was ein proxyserver ist. du verbindest dich an den und er 'taeuscht' vor er waere ein anderer indem er deine anfragen weiterleitet und dann die antworten vom 'richtigen' server an dich weitergibt.
sowas ist eine proxy klasse bzw resource auch.du erstellst also deine proxytextur
diese fragt dann selbst beim singleton nach der textur und merkt sich deren ptr und addiert einen refcount.
gibst du dein proxy frei, subtrahiert der proxy nen wert von der textur und meldet das dem singleton zur not.du arbeitest also in etwa weiter so
dtProxyTexture texture;
texture.load(_T("MyTexture.tga");
texture.attach();
[..] // Objekt zeichnen
texture.detach();im grunde ein aufwendigerer spezifischer autoptr.
-
Hmm, ist schon fast das, was ich mit dem Textur-Manager machen wollte, nur ne Ecke fortgeschrittener vllt.
Ich wollte es im Endeffekt so basteln:
Gespeichert wird:struct dtTextureInfo { int glID; wxString name; };Später dann im Programm:
dtTextureManager::getInstance().setTexture("MyTexture"); dtTextureManager::getInstance().attach(); dtMesh::drawObject(); dtTextureManager::getInstance().detach();Ist ja schon fast bis auf den Reference-Count und den Proxy an sich das selbe.
Ok, den Reference-Count kann man noch benutzen um die Textur vorm entladen zu schützen, wenn ein Unload() Befehl kommt und die Textur noch in Gebrauch ist.
Kann man denke ich verwenden. Super Sache. Warum liest man sowas nur nicht in Büchern über Spieleprogrammierung oder in C++-Büchern -.-.
rya.
-
Scorcher24 schrieb:
Hmm, ist schon fast das, was ich mit dem Textur-Manager machen wollte, nur ne Ecke fortgeschrittener vllt.
Ich wollte es im Endeffekt so basteln:
Gespeichert wird:struct dtTextureInfo { int glID; wxString name; };das ist wohl das textur objekt was du sowieso schon hast? das kannst du ja auch weiterhin so behalten, nur wird das dann vom singleton verwaltet.
Später dann im Programm:
dtTextureManager::getInstance().setTexture("MyTexture"); dtTextureManager::getInstance().attach(); dtMesh::drawObject(); dtTextureManager::getInstance().detach();emm, du wolltest beim rendern jedesmal ueber den namen die textur raussuchen lassen statt dir einen pointer zu merken bzw das im proxy zu machen? welchen vorteil erhoffst du dir?
Ist ja schon fast bis auf den Reference-Count und den Proxy an sich das selbe.
Ok, den Reference-Count kann man noch benutzen um die Textur vorm entladen zu schützen, wenn ein Unload() Befehl kommt und die Textur noch in Gebrauch ist.
Kann man denke ich verwenden. Super Sache. Warum liest man sowas nur nicht in Büchern über Spieleprogrammierung oder in C++-Büchern -.-.
rya.der grosse unterschied ist, dass man c++ dazu nutzen kann um viele maechtige dinge auf sichere und schnelle weise im hintergrund zu machen. so wie du das machst, baust du sehr viel dinge ein 'an die man denken muss' z.b. aufruf von 'unload'. das ist unneotig wenn dein proxy bzw autoptr das automatisch im destruktor macht.
IMO ist gutes c++, wenn du mit deinem beispiel vom anfang, die funktionalitaet kapselst die in deinem letzten beispiel ist.also:
- einfach und sicher anzuwaenden.
- maechtig im hintergrund.
-
das ist wohl das textur objekt was du sowieso schon hast? das kannst du ja auch weiterhin so behalten, nur wird das dann vom singleton verwaltet.
Nein, atmo verwende ich die Texturklasse...
Nochmal zur Verdeutlichung meine komplette Texturklasse:
class DIESELEXPORT dtGLTexture : public dtObject { public: dtGLTexture(); ~dtGLTexture(); bool load(const dtImage* file, const bool anisotropic = true, const bool mipmap = true ); bool unload(); bool attach(); void detach(); bool isOk() const; float getMaxAnisotropic() const; void setQuality(GLenum magFilter, GLenum minFilter); GLuint detachTexture(); private: float m_maxAnisotropic; GLenum m_minFilter; GLenum m_magFilter; bool m_detached; GLuint m_textureID; };Das ist die Klasse. Die will ich jetzt natürlich nicht komplett mehrfach in einer Liste führen. Deswegen gibts dieses Struct. Über dtTexture::detachTexture() kann ich die Klasse anweisen, die Textur-ID nicht mehr zu verwalten. Sie wird dann beim Zerstören der Klasse nicht per glDeleteTextures() gelöscht. Ich denke, es ist Speicherschonender nur die minimal benötigten Daten zu speichern.
So wars gedacht. Funktioniert so natürlich nicht mehr, wenn man einen Proyx verwenden will... ausser ich mach nach aussen hin eine 2te Textur-Klasse die eben nur eine ID empfangen und die Textur binden kann.emm, du wolltest beim rendern jedesmal ueber den namen die textur raussuchen lassen statt dir einen pointer zu merken bzw das im proxy zu machen? welchen vorteil erhoffst du dir?
Ja, das is quatsch... falscher Gedankengang.
baust du sehr viel dinge ein 'an die man denken muss' z.b. aufruf von 'unload
Sowas machen meine Dekonstruktoren natürlich alle automatisch. Das war jetzt nur ein doofes Beispiel wegen dem Referencecount...
Beispiel: Um eine neue Textur zu laden, ist der Aufruf von dtTexture::unload() nicht nötig, weil das automatisch gemacht wird.
Ich bin da schon sehr drauf bedacht, den Code bzw die Verwendung der API so angenehm und mächtig wie möglich zu gestalten.rya.