Liste mit Zeigern
-
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 newundoperator deleteaussehen 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
newunddeleteund 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_HPPDann 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_HPPDie 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
enuman, 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 Funktionenfind()fürs Finden von Einträgen,insert()fürs Erstellen underase()fürs Löschen. Du musst dabei nicht selber prüfen, ob Duplikate vorkommen, diestd::mapmacht 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 duTextureManagerdafü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 allesEs 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_Terfahren 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 vonTexture::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
