Liste mit Zeigern



  • Als erstes solltest du Ressourcen, Sprites und Spiellogik-Objekte voneinander differenzieren. Nicht jedes Objekt braucht seine eigene Textur. Mach dafür am besten eine eigene Klasse, z.B. Texture. In deinen Creep-Objekten speicherst du dann lediglich Zeiger auf die Texturen (=Instanzen von Texture).
    

    Naja ich weiß jetzt nicht so ganz genau wie du das meinst, aber ich mach das momentan so.

    Da ich momentan eignetlich nur TGAimages hernehm hab ich mir da eine Klasse mit hilfe vom Internet geschrieben die schaut so aus.

    class TGAImg
     {
      public:
       TGAImg();
       ~TGAImg();
       int Load(char* szFilename);
       int Load(string szFilename);
       int GetBPP();
       int GetWidth();
       int GetHeight();
       int GetPitch();
       unsigned char* GetImg();       // Return a pointer to image data
       unsigned char* GetPalette();   // Return a pointer to VGA palette
       SDL_Surface *GetSurface();     //Gibt das SDL_Surface zurueck (Nur bei SDL Anwendungen
      private:
       short int iWidth,iHeight,iBPP;
       unsigned long lImageSize;
       char bEnc;
       unsigned char *pImage, *pPalette, *pData;
    
       // Internal workers
       int ReadHeader();
       int LoadRawData();
       int LoadTgaRLEData();
       int LoadTgaPalette();
       void BGRtoRGB();
       void FlipImg();
     };
    

    So und dann lad ich so die Texture:

    Sprite.cpp

    void Sprite::LoadSprite(string filename, float PosX, float PosY, float w, float h)
    {
        LoadTexture(filename);
    
        m_x=PosX;
        m_y=PosY;
        m_w=w;
        m_h=h;
    }
    
    /**Ladet ein Sprite mit Animation**/
    void Sprite::LoadSprite(string filename, int NumX,int NumY,float PosX, float PosY,float w ,float h)
    {
        LoadSprite(filename,PosX,PosY,w,h);
        m_MaxRowX=NumX;
        m_MaxRowY=NumY;
        m_MaxClips=m_MaxRowX*m_MaxRowY;
    }
    
    /**Ladet die Texture**/
    void Sprite::LoadTexture(string TexName)
    {
       TGAImg Img;        // Image loader
    
       if(Img.Load(TexName)!=IMG_OK)
       {
           cout<<"Fehler beim laden der Textur: "<<TexName<<endl;
       }
    
       glGenTextures(1,&Texture);            // Allocate space for texture
       glBindTexture(GL_TEXTURE_2D,Texture); // Set our Tex handle as current
    
       // Create the texture
        if(Img.GetBPP()==24)
         glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0,GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg());
        else if(Img.GetBPP()==32)
         glTexImage2D(GL_TEXTURE_2D,0,4,Img.GetWidth(),Img.GetHeight(),0,GL_RGBA,GL_UNSIGNED_BYTE,Img.GetImg());
        else
        {
            cout<<"Fehler: falsches Format von: "<<TexName<<endl;
        }
    
       // Specify filtering and edge actions
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    
        /*
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
        */
    }
    

    So und was meinst du jetzt?
    Das ich das laden da Als extra Klasse mache oder wie? Und hast du dafür vielleicht ein paar Bsp.-Anwendungen oder Toturials dazu?

    Weil ich hab mir alles selbst über internet, Toturials beigebracht und hab da auch noch nicht so viel erfahrung wie man das am bestne schreibt. Also hab ich dann einfach mal mit SDL angefangen, dann bin ich damit zurechtgekommen und war dann soweit das die funktionen von SDL nicht mehr gereicht haben und bin dann auch SDL mit opengl umgestiegen, naja und da häng ich jetzt momentan und versuch mal wenigstens was halbwegs brauchbares hinzubekommen.

    Eigentlich hätt ich auch nicht gedacht dass das dann solche probleme macht das in die Liste zu tun. Aber es muss an irgetnwas dadrinnen liegen. Weil Konstrukter und Destruktor werden aufgerufan und erst wenn die Funktion zu Ende ist stürzt das Programm ab.



  • Naja, als erstes würde ich mir nicht irgendwas vom Internet zusammenklicken. Das führt selten zu sinnvollem Code. Zudem scheinst du in C++ noch nicht allzu sicher zu sein; ich würde zuerst ein C++-Buch gut durcharbeiten, bevor ich mich mit Grafik beschäftigte.

    Deine TGAImg -Klasse hat zum Beispiel keinen benutzerdefinierten Kopierkonstruktor und Zuweisungsoperator, aber einen Destruktor. Das ist schon mal ein Hinweis auf eine mögliche Fehlerquelle. Implementiere entweder diese drei Memberfunktionen, oder verbiete sie (in private deklarieren und nicht definieren). Ausserdem solltest du dich achten, Klassen wie std::string als Const-Referenz und nicht als Kopie zu übergeben. Oder Konstruktoren zu nutzen, um Instanzen zu initialisieren.

    Ich hätte grundsätzlich an sowas gedacht:

    class Texture
    {
        public:
            Texture(const std::string& FileName);
            Texture(const Texture&);
            ~Texture();
            void operator= (const Texture&);
            // hier deine Schnittstelle fürs Zeichnen
    
        private:
            GLuint MyTextureID;
    };
    
    class TextureManager
    {
        public:
            TextureManager();
            Texture& GetTexture(const std::string& Name);
    
        private:
            std::map<std::string, Texture> MyTextures;
    };
    

    Aber das ist nur mal ein grober Aufbau, ein möglicher Vorschlag. Du solltest schauen, dass du Texturen von den Sprites oder sogar Logikobjekten loslösen kannst, dann musst du nämlich auch nicht bei jedem neuen Objekt eine eigene Textur anlegen.

    Entweder du implementierst für Texturen eine sinnvolle Kopiersemantik (z.B. neue Textur anlegen) oder du verbietest den Kopierkonstruktor und Zuweisungsoperator und verwendest Zeiger. Da musst du allerdings etwas aufpassen. Ich bin kein Fan von besitzenden Zeigern in STL-Containern. Boost würde sonst noch Pointer-Container anbieten...



  • So hab mich jetzt einfach mal hier angemeldet, finds hier recht gut und man bekommt gute Tipps.

    Also naja aber ich find trotzdem das ich zuminderst die Grundlageen kann. Naja wegen Buch hab ich mir auch schon mal überlegt eins zu kaufen, aber irgendwie denk ich mir dann immer bzw. seh ich das in den Büchern nicht das drinnen steht was ich will, (brauch).
    Naja ich bräucht halt dann ein Buch was über C++ und OpenGl und ggf. SDL geht.

    Momentan nehm ich so als hauptinformation die Seite her
    http://wiki.delphigl.com/index.php/Hauptseite

    Find da sind die Funktionen recht gut beschrieben, zwar leider nicht in C++ aber ist eh fast gleich.

    Aber anscheinend bau ich die Klassen immer ein bischen falsch auf.

    Da musst du allerdings etwas aufpassen. Ich bin kein Fan von besitzenden Zeigern in STL-Containern. Boost würde sonst noch Pointer-Container anbieten...

    zu dem noch, ist das aus eigener Erfahrung so oder kann man das irgendwie belegen, oder geht es da dann nur darum das man da dann den Speicher nicht bzw nicht gut oder leicht wieder freigeben kann?

    EDIT:
    Für was sollte da dann der Überladene Operator gut sein?
    Um einer anderen Textur diese Textur zuzuweißen ode versteh ich das falsch?



  • stefan schrieb:

    zu dem noch, ist das aus eigener Erfahrung so oder kann man das irgendwie belegen, oder geht es da dann nur darum das man da dann den Speicher nicht bzw nicht gut oder leicht wieder freigeben kann?

    Ja, hauptsächlich wegen der Gefahr von Memory Leaks. Ein oder mehrere delete s bei erase() - bzw. clear() -Aufrufen können sehr schnell vergessen gehen. Die Sonderbehandlung ist auch hinderlich, wenn man generisch arbeitet (mit Templates). Ausserdem kann man den Container so nicht sinnvoll kopieren oder zuweisen, weil dann nur die Zeiger kopiert werden und somit mehrere Zeiger auf das Gleiche zeigen. Sich da immer zu merken, welcher Zeiger nun worauf zeigt und wie freizugeben ist, kann unter Umständen recht mühsam sein.

    Vielleicht bin ich aber auch nur ein bisschen verwöhnt von C++. 😉
    So tragisch sind Zeiger auch nicht, wenn du nicht viele Operationen auf dem Container anwendest. Sei einfach der Problematik bewusst, bevor du sowas exzessiv anwendest. Du kannst es also schon so versuchen (schreib dir fürs Löschen am besten eine Funktion, die zuerst delete und dann erase() aufruft).

    stefan schrieb:

    Für was sollte da dann der Überladene Operator gut sein?
    Um einer anderen Textur diese Textur zuzuweißen ode versteh ich das falsch?

    Ja, falls dies Sinn macht. Wenn nicht, verbiete den Zuweisungsoperator, sodass man ihn nicht aus Versehen benutzt (z.B. innerhalb von Containern). Dann kannst du allerdings wie gesagt keine Container mehr benutzen. Gleiches gilt für den Kopierkonstruktor.



  • Also du hast mich da jetzt auf jeden Fall mal überzeugt, werde mal das ganze neu machen und dann hier noch mal hertun. Kann aber sein das ich vielleicht dann beim Kopierkonstruktor noch mal hilfe brauch, da komm ich grad nicht ganz so mit wie der dann hinhauen soll...

    Naja bis dahin erst mal danke.

    EDIT:

    class Texture 
    { 
        public: 
            Texture(const std::string& FileName); 
            Texture(const Texture&); 
            ~Texture(); 
            void operator= (const Texture&); 
            // hier deine Schnittstelle fürs Zeichnen 
    
        private: 
            GLuint MyTextureID; 
    }; 
    
    class TextureManager 
    { 
        public: 
            TextureManager(); 
            Texture& GetTexture(const std::string& Name); 
    
        private: 
            std::map<std::string, Texture> MyTextures; 
    };
    

    So jetzt hab ich mir mal den funktionsablauf ausgedacht.

    Texture:

    Texture(const std::string& FileName); :
    Ladet die Textur mit dem FileName von dem String, wenn es schon eine Textur mit dem FileNamen im TexturManager gibt die nehmen.

    Texture(const Texture&); :
    Ladet die Textur Textur (also wird auch von der Funktion Texture(const std::string& FileName)) aufgerufen, schätz ich mal).

    ~Texture();
    Gibt den Speicher wieder frei, naja da wird es aber dann shcon schwieriger,weil es kann ja sein das eine Textur auch noch in einer anderen Funktion genutzt wird oder? Oder wie müsste man die dann löschen (also aus dem TexturManager?
    Das ist die Funktion was ich im Moment nicht weiß wie ich das anstellen soll.

    void operator= (const Texture&); :
    Naja einfach n Zuweisungsoperatot der eine Textur zuweist.

    Texturmanager:

    Texture& GetTexture(const std::string& Name); :
    Gibt die Textur ID von der Textur zurück wenn es die Gibt.

    Naja braucht man dann nicht auch eingentlich ein SetTexture? oder wie bringt man die sonst in die Map rein? Naja muss aber dazu sagen das ich noch nicht wirklich mit Maps(MultiMaps) gearbeitet hab, hab eigentlich immer entweder Arrays,Vektoren oder Listen hergenommen.



  • stefan schrieb:

    Kann aber sein das ich vielleicht dann beim Kopierkonstruktor noch mal hilfe brauch, da komm ich grad nicht ganz so mit wie der dann hinhauen soll...

    Sicher, kein Problem, frag ruhig. 🙂

    stefan schrieb:

    Texture(const std::string& FileName); :
    Ladet die Textur mit dem FileName von dem String, wenn es schon eine Textur mit dem FileNamen im TexturManager gibt die nehmen.

    Ja, wobei eine Textur eigentlich nichts über die anderen Texturen weiss. Zu schauen, dass keine Textur zweimal vorkommt, ist dann Aufgabe des Texturmanagers.

    stefan schrieb:

    Texture(const Texture&); :
    Ladet die Textur Textur (also wird auch von der Funktion Texture(const std::string& FileName)) aufgerufen, schätz ich mal).

    Das ist der Kopierkonstruktor. Der wird aufgerufen, falls eine Textur kopiert wird. Hier weiss ich wie gesagt nicht, welches Verhalten von dir erwünscht ist — sollen Kopien überhaupt möglich sein? Soll dabei eine neue identische Textur entstehen, die eigenen Speicher belegt und separat handhabt? Oder ...?

    stefan schrieb:

    ~Texture();
    Gibt den Speicher wieder frei, naja da wird es aber dann shcon schwieriger,weil es kann ja sein das eine Textur auch noch in einer anderen Funktion genutzt wird oder? Oder wie müsste man die dann löschen (also aus dem TexturManager?
    Das ist die Funktion was ich im Moment nicht weiß wie ich das anstellen soll.

    Das muss dich hier nicht kümmern. Der Destruktor soll lediglich dafür sorgen, dass eine Textur richtig aufgeräumt wird (also z.B. glDeleteTextures() aufruft). Wann der Destruktor aufgerufen wird, bestimmt wiederum der Texturmanager.

    stefan schrieb:

    void operator= (const Texture&); :
    Naja einfach n Zuweisungsoperatot der eine Textur zuweist.

    Ja — hier stellt sich die gleiche Frage wie beim Kopierkonstruktor.

    stefan schrieb:

    Texture& GetTexture(const std::string& Name); :
    Gibt die Textur ID von der Textur zurück wenn es die Gibt.

    Ja, kommt wieder ein wenig drauf an, wie du von aussen auf die Texturen zugreifen willst. Brauchst du die ID? Wer ist fürs Zeichnen zuständig? Könnte man das Zeichnen vielleicht sogar auch eine eigene Klasse übernehmen lassen, damit das zentral passiert?
    Und was ist, wenn ein ungültiger Name übergeben wird? Mit einer Referenzrückgabe wäre eine Exception am besten geeignet. Sonst kannst du einen Zeiger zurückgeben, und im Falle eines fehlerhaften Namens den Nullzeiger zurückgeben.

    stefan schrieb:

    Naja braucht man dann nicht auch eingentlich ein SetTexture? oder wie bringt man die sonst in die Map rein?

    Doch, man braucht noch einige Methoden. Das sollte nur das Grundgerüst darstellen, damit du einen ungefähren Ansatz hast. Diese beiden Methoden wären auch eine Möglichkeit:

    // Fügt eine Textur hinzu. 'Name' ist hierbei der Name, über den man die Textur anspricht
    // (bei GetTexture), 'FileName' der Name der Datei, von der die Textur geladen wird.
    void AddTexture(const std::string& Name, const std::string& FileName);
    
    // Gibt die Textur mit dem entsprechenden Namen frei. Ruft std::map::erase() auf.
    // Damit wäre auch das Problem mit dem Einsatzbereich des Texture-Destruktors geklärt.
    // Was passiert hier, wenn der Name nicht vorkommt? Exception? bool-Rückgabewert?
    void RemoveTexture(const std::string& Name);
    

    stefan schrieb:

    Naja muss aber dazu sagen das ich noch nicht wirklich mit Maps(MultiMaps) gearbeitet hab, hab eigentlich immer entweder Arrays,Vektoren oder Listen hergenommen.

    Das macht nichts, die hast du schnell begriffen, wenn du dich mit anderen Containern auskennst. Der primäre Unterschied besteht darin, dass die Elemente assoziativ statt sequenziell gespeichert werden. Das heisst, nicht du bestimmst die Reihenfolge, sondern ein zuvor festgelegtes Sortierkriterium (normalerweise der operator< ).

    Mehr Informationen findest du im Artikel über Container oder auf www.cplusplus.com.



  • So naje hab das jetzt mal angefangen und gleich mal auf ein Problem gekommen.

    und zwar schaut das momentan so aus.

    Texture::Texture(const string& FileName)
    {
    
       TGAImg Img;        // Image loader
    
       if(Img.Load(FileName)!=IMG_OK)
       {
           cout<<"Fehler beim laden der Textur: "<<FileName<<endl;
       }
    
       glGenTextures(1,&m_TextureID);
       glBindTexture(GL_TEXTURE_2D,m_TextureID);
    
       // Create the texture
        if(Img.GetBPP()==24)
         glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0,GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg());
        else if(Img.GetBPP()==32)
         glTexImage2D(GL_TEXTURE_2D,0,4,Img.GetWidth(),Img.GetHeight(),0,GL_RGBA,GL_UNSIGNED_BYTE,Img.GetImg());
        else
        {
            cout<<"Fehler: falsches Format von: "<<m_TextureID<<endl;
        }
    
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    
       g_pTexturManager->AddTexture(FileName, //???);
    }
    

    Naja und dann muss ja die Textur in dem Textureditor gespeichert werden. Oder wäre es besser wenn die Texturen auch direkt im Textureditor erstellt werden?

    Also das das nicht so ist sonderns das der Texturmanager dann die Funktionen zum erstellen von der Textur aufruft.

    Das ist der Kopierkonstruktor. Der wird aufgerufen, falls eine Textur kopiert wird. Hier weiss ich wie gesagt nicht, welches Verhalten von dir erwünscht ist — sollen Kopien überhaupt möglich sein? Soll dabei eine neue identische Textur entstehen, die eigenen Speicher belegt und separat handhabt? Oder ...?

    Naja gut wenn man das so mit dem TexturManager macht, braucht man Texturen eignetlich auch nicht mehr kopieren können. Weil man ja dann in dem Objekt (Sprite schon genau weiß welche Textur geladen wird und man sich die nur über die ID, Texturname holen braucht.

    Naja bin jetzt echt schon am überlegen ob ich mit dem grafischen aufhören soll und noch mal alles genau in der Konsole machen soll. Wobei mir da das meiste dann wieder so einfach vorgekommen ist, bzw. es ist nie was größeres geworden weil ich nicht wusste was ich da machen sollte.



  • stefan schrieb:

    Naja und dann muss ja die Textur in dem Textureditor gespeichert werden. Oder wäre es besser wenn die Texturen auch direkt im Textureditor erstellt werden?

    Also das das nicht so ist sonderns das der Texturmanager dann die Funktionen zum erstellen von der Textur aufruft.

    Ja. Du machst wieder den gleichen Fehler wie vorher: Du willt der Textur Aufgaben übergeben, für die sie nicht zuständig ist. Erstellung und Zerstörung erfolgt im Texturmanager. Implementiere die Textur als abgeschlossenes System, sodass sie nichts vom Manager weiss (dessen Header also auch nicht einbindet) und somit keine unnötigen Abhängigkeiten besitzt. Der Texturmanager muss dann die Texturen kennen, aber nicht umgekehrt.

    stefan schrieb:

    Naja bin jetzt echt schon am überlegen ob ich mit dem grafischen aufhören soll und noch mal alles genau in der Konsole machen soll. Wobei mir da das meiste dann wieder so einfach vorgekommen ist, bzw. es ist nie was größeres geworden weil ich nicht wusste was ich da machen sollte.

    Um objektorientierte Konzepte und Designsaspekte zu verstärken, empfiehlt sich die Konsole sehr gut. Hier ist auch Erfahrung sehr wichtig - mit der Zeit merkst du wahrscheinlich selber, was sinnvoll ist und was nicht. Auch wenn du neue Sprachmittel oder Dinge aus der Standardbibliothek lernen willst, kannst du in der Konsole gut damit herumexperimentieren.

    Ich würde das Projekt aber deswegen nicht über den Haufen werfen. Allerdings könnte es sich auszahlen, zuerst eine Pause mit Grafikprogrammierung einzulegen und andere Dinge zu vertiefen. Kennst du Polymorphie und Templates und kannst du sie gut anwenden? Diese Themen sind sehr wichtig, die würde ich unbedingt gut anschauen. Oder Operatorüberladung? Exception-Handling? Sagt dir RAII was? Weisst du, wie eine eigene Implementierung von operator new und operator delete aussehen könnte? Hast du schon einmal einen eigenen Container geschrieben? Durch solche Projekte kannst du sehr schnell wichtige Dinge von C++ dazulernen, die meines Erachtens grösstenteils von fundamentaler Bedeutung für das weitere Programmieren sind.



  • Naja ich hab schon von dem meisten was gelesen, aber ich hab eigentlich nie was davon so richtig gebraucht außer einmal hab ich Templates gebraucht, wo ich mir ne Singleton-Klasse geschrieben hab.
    Und dann halt vererbung grhört ja auch bei Polymorphie mit rein.

    Hmm ne eigenen Container hab ich mir noch nicht geschrieben. Aber ist das überhaupt so sinvoll sich da einen eigenne zu schreiben, gibts ja schon gute. Oder ist das mehr so zum verständnis dann gedacht? Nimmst du da einen selbstgeschriebenen her?

    RAII sagt mir nichts werd ich mir heute aber dann mal anschauen.

    Implementierung von operator new und operator delete

    Muss ich auch sagen weiß ich nicht...

    Naja werd mir wahrscheinlich doch auch mal ein Buch kaufen müssen. Was gibt es denn da gutes?
    Hab mal so geschaut und hab dann das gefunden:
    "C++ Für Spieele-Programmierer"

    Weißt wer ob das was ist oder gibt es da bessere Bücher?

    EDIT: Oder gibt es Seiten wo Übunsaugaben gestellt werden (vielleicht dann auch mit möglichen Lösungen) wo eine feste Aufgaben stellung ist? Also die Aufgaben sollen aber shcon ein bisschen Sinn haben.



  • stefan schrieb:

    Hmm ne eigenen Container hab ich mir noch nicht geschrieben. Aber ist das überhaupt so sinvoll sich da einen eigenne zu schreiben, gibts ja schon gute. Oder ist das mehr so zum verständnis dann gedacht? Nimmst du da einen selbstgeschriebenen her?

    Nein, mehr fürs Verständnis. Ich hab das auch mal gemacht und dabei recht viel gelernt (vor allem, was new und delete und Templates betrifft). Sollte nur so ein Beispiel sein, natürlich muss man das nicht zwingend einmal getan haben.
    Momentan verwende ich eigentlich nur Standardcontainer und ab und zu solche von Boost, aber eigentlich nie selbstgeschriebene.

    stefan schrieb:

    Naja werd mir wahrscheinlich doch auch mal ein Buch kaufen müssen. Was gibt es denn da gutes?
    Hab mal so geschaut und hab dann das gefunden:
    "C++ Für Spieele-Programmierer"

    Weißt wer ob das was ist oder gibt es da bessere Bücher?

    Das Buch kenne ich nicht, allerdings würde ich eher zu einem "reinen" C++-Buch raten. Das Spieleprogrammierer-Buch bindet dich wahrscheinlich an eine API (wenns blöd kommt, SDL, was eher kontraproduktiv für das Lernen von C++ ist) und vernachlässigt C++-Teile eher. Aber das ist nur meine Vermutung.

    Als C++-Buch wird oft der C++-Primer empfohlen. Ich habe sehr viel durch das C/C++-Kompendium von Dirk Louis gelernt. Wäre gut, wenn noch andere User ihre Empfehlungen abgeben könnten...



  • Das Buch kenne ich nicht, allerdings würde ich eher zu einem "reinen" C++-Buch raten. Das Spieleprogrammierer-Buch bindet dich wahrscheinlich an eine API (wenns blöd kommt, SDL, was eher kontraproduktiv für das Lernen von C++ ist) und vernachlässigt C++-Teile eher. Aber das ist nur meine Vermutung.

    Nein, es bindet sich nicht daran. Mit der SDL wird am Ende lediglich ein (Grafik) Spiel geschrieben. Ansonsten hat das Buch nicht wirklich viel mit Spielen zu tun, ausser, dass man halt anstatt eines Rechners ein kleines Konsolenspiel macht und dass man keine Äpfel und Birnen hat, sondern Raumschiffe. 😉

    Bestimmt nicht das beste Buch, um C++ zu lernen, allerdings gibt es trotzdem einen guten Einstieg.



  • konnte es icht lassen es doch zu versuchen...

    Also erst mal Texturmanager.hpp

    #ifndef TEXTUREMANAGER_HPP
        #define TEXTUREMANAGER_HPP
    
    #include "Singleton.hpp"
    #include <map>
    
    #include "Texture.hpp"
    
    #define g_pTexturManager TextureManager::Get()
    class TextureManager : public TSingleton<TextureManager>
    {
        public:
        TextureManager();
        ~TextureManager();
    
        void AddTexture(const string& fileName);
        void RemoveTexture(const string& fileName);
        Texture& GetTexture(const string& fileName);
    
        private:
        map<string, Texture> MyTextures;
    };
    
    #endif //TEXTUREMANAGER_HPP
    

    Dann TexturManager.cpp

    #include "TextureManager.hpp"
    
    TextureManager::TextureManager()
    {
    }
    
    TextureManager::~TextureManager()
    {
        MyTextures.clear();
    }
    
    void TextureManager::AddTexture(const string& fileName)
    {
        bool Textureerstellen=true;
    
        if(MyTextures.empty()==false)
        {
            map<string,Texture>::iterator i;
            for(i=MyTextures.begin(); i!=MyTextures.end();i++)
            {
                if(i->first==fileName)
                {
                    cout<<"Textur existiert bereits"<<endl;
                    Textureerstellen=false;
                }
            }
        }
        if(Textureerstellen==true)
        {
            pair<string, Texture> T;
            Texture Tex(fileName);
            T=make_pair(fileName,Tex);
            cout<<"Textur wurde erstellt"<<endl;
        }
    }
    
    void TextureManager::RemoveTexture(const string& fileName)
    {
        if(MyTextures.empty()==false)
        {
            map<string,Texture>::iterator i;
    
            for(i=MyTextures.begin(); i!=MyTextures.end();i++)
            {
                if(i->first==fileName)
                {
                    MyTextures.erase(i);
                }
            }
        }
        else
        {
            cout<<"Kein Element in der Map"<<endl;
        }
    }
    
    Texture& TextureManager::GetTexture(const string& fileName)
    {
        map<string,Texture>::iterator i;
    
            for(i=MyTextures.begin(); i!=MyTextures.end();i++)
            {
                if(i->first==fileName)
                {
                    return i->second;
                }
                else
                {
                    cout<<"Textur wurde nicht gefunden"<<endl;
                }
            }
    }
    

    Ah und da noch ne Frage: Ist es besser den Iterator (und das pair?) in jeder Funktion neu zu erstellen oder in die Klasse als Membervariable zu schreiben?

    Dann Texture.hpp

    #ifndef TEXTURE_HPP
        #define TEXTURE_HPP
    
    #include <SDL/SDL.h>
    #include <SDL/SDL_opengl.h>
    #include <iostream>
    
    #include "TGA_Loader.hpp"
    
    using namespace std;
    
    class Texture
    {
        public:
    
        Texture();
        Texture(const string& FileName);
        //Texture(const Texture&);
        ~Texture();
        //void operator= (const Texture&);
    
        private:
        GLuint m_TextureID;
    };
    
    #endif //TEXTURE_HPP
    

    Die beiden Funktionen da als Kommentar(Kopierkonstruktor und Zuweisungsoperator) wusst ich nicht wie ich schreiben soll.

    und dann noch Textur.cpp

    #include "Texture.hpp"
    
    Texture::Texture()
    {
    }
    
    Texture::Texture(const string& FileName)
    {
        TGAImg Img;        // Image loader
    
       if(Img.Load(FileName)!=IMG_OK)
       {
           cout<<"Fehler beim laden der Textur: "<<FileName<<endl;
       }
    
       glGenTextures(1,&m_TextureID);
       glBindTexture(GL_TEXTURE_2D,m_TextureID);
    
       // Create the texture
        if(Img.GetBPP()==24)
         glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0,GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg());
        else if(Img.GetBPP()==32)
         glTexImage2D(GL_TEXTURE_2D,0,4,Img.GetWidth(),Img.GetHeight(),0,GL_RGBA,GL_UNSIGNED_BYTE,Img.GetImg());
        else
        {
            cout<<"Fehler: falsches Format von: "<<FileName<<endl;
        }
    
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    }
    
    Texture::Texture(const Texture&)
    {
    }
    
    Texture::~Texture()
    {
         glDeleteTextures(GL_TEXTURE_2D,&m_TextureID);
    }
    

    So hoffe mal du hast das so in der Art gemeint.



  • Ja, du bist auf dem richtigen Weg. Willst du Texturen gleich über den Dateinamen identifizieren? Ich habe in meinem vorherigen Beispiel einen separaten ID-String verwendet, aber du kannst es auch so wie von dir gewünscht machen. Eventuell böte sich auch ein enum an, dann müssten aber die Anzahl Texturen schon zur Kompilierzeit feststehen.

    Du musst bei einer Map übrigens nicht immer durchiterieren, sonst kannst du gerade so gut einen anderen Container nehmen. 😉
    Schau dir am besten mal das an: http://www.cplusplus.com/reference/stl/map/.
    Besonders die Funktionen find() fürs Finden von Einträgen, insert() fürs Erstellen und erase() fürs Löschen. Du musst dabei nicht selber prüfen, ob Duplikate vorkommen, die std::map macht das für dich.

    Was den Kopierkonstruktor und Zuweisungsoperator angeht: Ich weiss nicht, ob sich das für dich lohnt, aber grundsätzlich wäre Reference Counting eine Möglichkeit. Das bedeutet, es wird gezählt, wie viele Instanzen sich eine Textur teilen. Am Anfang ist das nur eine, bei einer Kopie wird der Counter erhöht, im Destruktor reduziert. Die letzte Instanz (bei welcher der Count im Destruktor 0 wird) sorgt dann für die Freigabe. Aber eben, das nur mal so als Hinweis. Irgendwie sind das etwas viele neue Dinge aufs Mal, vielleicht lässt du das vorerst auch (d.h. du erstellst eine normale Kopie, einfach die defaultgenerierten Methoden zu verwenden ist keine Option).



  • ok also danke erst mal das du dir das alles durchgeschaut hast.

    Ja, du bist auf dem richtigen Weg. Willst du Texturen gleich über den Dateinamen identifizieren?

    Naja ich hätt mir halt gedacht ich mach das so, weil dann könnt ich dann wenn es die Textur nicht mehr gibt gleich mit dem Dateinamen die Textur erstellen. Also nur als Überlegeung. Und 2. wäre das nicht bisschen viel aufwand, wenn man dann vonmiraus mal so 200 Texturen hat?

    Eventuell böte sich auch ein enum an, dann müssten aber die Anzahl Texturen schon zur Kompilierzeit feststehen.

    Kann ich zwar jetzt nicht mit 100% sagen, würd aber eher mal sagen nein.

    Reference Counting eine Möglichkeit. Das bedeutet, es wird gezählt, wie viele Instanzen sich eine Textur teilen

    Das hört sich nicht schlecht an. Werd ich wahrscheinlich einbauen, dürfte ja eigentlich nicht so schwer sein einfach einen Zähler im Texturmanager der von jeder Textur alle Instanzen zählt.

    (d.h. du erstellst eine normale Kopie, einfach die defaultgenerierten Methoden zu verwenden ist keine Option).

    Versteh ich nicht ganz was du damit meinst



  • Also ich mache das genau auch so. Ich Identifiziere eine Textur anhand des Pfades. (Muss ja auch einmalig sein) und dann wird bei jedem, der genau auch diese Textur laden will, ob sie bereits vorhanden ist und ggf. wird ein Counter hochgezählt, respektive wieder runtergezählt, wenn das Objekt die Textur wieder freigibt.

    Somit wird eine Textur genau nur einmal geladen. Sofern man eine Textur noch irgendwie bearbeiten muss, kann man da ja schliesslich auch noch etwas mit COW machen.



  • stefan schrieb:

    Naja ich hätt mir halt gedacht ich mach das so, weil dann könnt ich dann wenn es die Textur nicht mehr gibt gleich mit dem Dateinamen die Textur erstellen. Also nur als Überlegeung. Und 2. wäre das nicht bisschen viel aufwand, wenn man dann vonmiraus mal so 200 Texturen hat?

    Stimmt, dein Vorgehen ist wie drakon (der übrigens auch so ein Fan von "naja" ist ;)) gesagt hat eine gute Idee, mach es also ruhig so.

    stefan schrieb:

    Das hört sich nicht schlecht an. Werd ich wahrscheinlich einbauen, dürfte ja eigentlich nicht so schwer sein einfach einen Zähler im Texturmanager der von jeder Textur alle Instanzen zählt.

    Nein, das müsstest du in der Texture -Klasse selbst einbauen, da das dort benötigt wird (für Konstruktoren, Zuweisungsoperator und Destruktor). Würdest du TextureManager dafür verwenden, hättest du wieder die unnötige Abhängigkeit.

    stefan schrieb:

    Versteh ich nicht ganz was du damit meinst

    Falls dir Reference Counting nicht passt, implementierst du normale Kopiersemantik (es wird eine neue Textursemantik erzeugt). Die vom Compiler automatisch generierten Kopierkonstruktor und Zuweisungsoperator sind insofern keine Option, als sie nur alle Member kopieren (und damit auf die gleiche Textur verweisen). Trotzdem versuchen dann beide Destruktoren, die Textur freizugeben, was kaum gut geht.



  • Naja hab jetzt das alles mal durchgelesen, aber ich komm nicht drauf.

    Und zwar hier wenn ich eine Textur erstellen will:

    void TextureManager::AddTexture(const string& fileName)
    {
        Texture Tex(fileName);
        cout<<"4."<<endl;
        m_T=make_pair(fileName,Tex);
        cout<<"5."<<endl;
        MyTextures.insert(m_T);
    
        cout<<"Textur wurde erstellt"<<endl;
    }
    
    Anders ist noch alles
    

    Es zeigt "4" an und danach stürzt das Program ab...
    Hab alles mögliche versucht, aber es sürzt immer ab oder es kommen haufen fehler.

    Anders sind die Funktionen so wie weiter oben noch, hab die zwar bisschen abgeändert. Also Iteratoren raus usw. So wie ich das halt am sinvollsten gefunden hab.

    Also hoffe mal ihr könnt mir noch mal helfen 🙂

    Und danke schon mal im vorraus.
    Und jetzt gut Nacht an alle.



  • Wäre noch gut, wenn wir etwas mehr über den Kontext von m_T erfahren könnten (Deklaration, andere wichtige Verwendung). Übrigens würde ich einen aussagekräftigeren Bezeichner wählen. 😉

    stefan schrieb:

    Hab alles mögliche versucht, aber es sürzt immer ab oder es kommen haufen fehler.

    Debuggt hast du wahrscheinlich noch nicht, oder? Wie stürzt das Programm ab? Normalerweise gelangt man zu der Stelle im Code, bei der das Programm abbricht. Wenn du die Variablenwerte mit dem Debugger laufend überprüfst, solltest du eigentlich schnell auf den Fehler stossen. Schau doch zum Beispiel mal, ob der Texture -Konstruktor richtig ausgeführt wird.



  • Hallo ____stefan____ 🙂

    zuersteinmal:

    #define g_pTexturManager TextureManager::Get()
    

    n e i n. da stellen sich alle c++ haare auf. Get musst nicht vermakrot werden.

    der code sieht an sich ok aus. wenn du aber "haufen fehler" bekommst, zeig sie
    uns. sogut raten können wir auch nicht. einfach 1zu1 ins forum mit dem fehler!

    ich könnte mir denken, dass es am ctor, copy-ctor oder sowas liegt. um genaueres
    zu sagen, brauchen wir den (aktuellen) code von

    Texture::Texture(const std::String &);
    Texture::Texture(const Texture &); // ich vermute den hauptfehler hier
    Texture::~Texture();

    so 🙂

    wenn ich auch mal das design bemäkeln darf, würde ich, wie bereits gesagt
    dass ganze mit refcounting machen. im idealfall nutzt du dafür zeiger:

    um dir einen hinweis zu geben, baue ich deinen texmanager + texture um 🙂

    class Texture
    {
    public:
        Texture(TextureManager *texmanager, unsigned ein_weiterer_parameter)
        {
            parent = texmanager;
            refcounter = 1;
    
            paramater = ein_weiterer_parameter; // stellvertretend für die variablen
    
            glGenTextures(); // das normale
        }
        ~Texture()
        {
            parent->RemoveTextureFromList(this); // entfernen vom manager
    
            // das übliche
    
            glDeleteTexture();
        }
        void AddRef()
        {
            ++refcounter;
        }
        void Release()
        {
            if (!--refcounter) // oje, wir ham die 0 erreicht
                parent->RemoveTexture(this); // und weg mit uns
        }
    private:
        Texture(const Texture &){} // wir werden nicht kopiert!
    
        TextureManager *parent;
        unsinged refcounter;
    
        unsigned alles_andere;
    };
    ///////////////////////////////////////
    ///////////////////////////////////////
    class TextureManager
    {
    public:
        typedef std::map<std::string, Texture *> texmap; // neu mit zeigern
        typedef texmap::iterator iter;
    
        friend class Texture;
    
        TextureManager()
        {
            // wir machen GARNICHTS
        }
        ~TextureManager()
        {
            for (iter = m.begin(); iter != m.end(); ++iter)
                delete iter->second;
    
            // ACHTUNG ACHTUNG
            // wenn eine textur auch ohne manager leben darf, muss hier ein
            // iter->second->Release(); hin
            // ansonsten bleibts hierbei
        }
        Texture *GetTexture(const std::string &filename)
        {
            iter it = m.find(filename);
            if (it != m.end())
            {
                it->second->AddRef(); // referenz-zählung
                return it->second;
            }
            else
            {
                Texture *tex = new Texture(filename, 42);
                m[filename] = tex;
                return tex;
            }
        }
        void RemoveTexture(Texture *tex)
        {
            for (iter it = m.begin(); it != m.end(); ++i)
            {
                if (it->second == tex)
                {
                    delete it->second; // entfernt sich automatisch aus der liste
                    return;
                }
            }
        }
    private: // PRIVAT
        void RemoveTextureFromList(Texture *tex)
        {
            for (iter it = m.begin(); it != m.end(); ++i)
            {
                if (it->second == tex)
                {
                    m.erase(it); // NUR entfernen
                    return;
                }
            }
        }
    
        texmap m;
    };
    
    // SO ab sofort fordern wir einen zeiger auf eine textur über GetTexture
    // an und Releasen ihn, wenn wir fertig sind. wenn wir ihn kopieren machen
    // wir vorher ein AddRef!
    
    class EinDings
    {
    public:
        EinDings(Texture *tex)
        {
            texture = tex;
            texture->AddRef();
        }
        EinDings(const EinDings &dings)
        {
            texture = dings.texture;
            texture->AddRef();
        }
        ~EinDings()
        {
            texture->Release();
        }
    private:
        Texture *texture;
    };
    
    // oder als funktion
    
    Texture *tex = texmanager->GetTexture("keksdose.bmp"); // refcount ist schon eins
    
    tex->Draw();
    
    // fertig
    tex->Release();
    

    wenn du das design zu 100% durchziehst, wirst du keine probleme haben,
    grade bei dem mehrfachverwenden ist das system sehr sinnvoll. wenn es dir jetzt
    noch abschmiert, dann nurnoch durch flüchtigkeitsfehler.

    ideal netürlcih, wenn du so alle ressourcen verwaltest.

    puh ganz schön viel code, aber es musste sein.

    dir weiterhin viel spaß ich geh ins bett 😃


Anmelden zum Antworten