Meshloader macht Probleme



  • Hallo Leute ich hab gerade ein Problem, was wahrscheinlich leicht zu lösen sein wird, ich aber nach Tagelanger Arbeit an etwas anderem nicht mehr den Überblick habe, um das ganze zu lösen.

    Ich war nebenbei beschäftigt einen Meshloader für ein eigenes Format zu schreiben, der mit kleinen Stücken arbeitet und so ziemlich flexibel für neues bleibt.

    Jetzt habe ich zum Test einfach mal 3 Vertices in diese Datei gespeichert und diese von meinem Meshloader laden gelassen, und bekomme fast nur Müll raus.

    Erstmal etwas code und dann die Erklärung 😉

    Programm zum Schreiben der Datei-->

    struct Vertex
    {
    	D3DXVECTOR3 pos;
    	D3DXVECTOR2 tex;
    };
    
    enum MeshType
    {
    	GMESH_TYPE_VERTEX = 0,
    	GMESH_TYPE_INDEX,
    	GMESH_TYPE_MATERIAL
    };
    
    struct ChunckHeader
    {
    	MeshType _chuncktype;
    	DWORD _chunckSize;
    };
    
    struct VertexChunck
    {
    	DWORD _num;
    	DWORD _singlesize;
    };
    
    int main()
    {
    
    	ofstream out("model.gsm",ios::out|ios::binary);
    
            Vertex v[3];
    	v[0].pos = D3DXVECTOR3(-1.0f, -1.0f, 0.0f);
    	v[0].tex = D3DXVECTOR2(0.0f, 1.0f);
    
    	v[1].pos = D3DXVECTOR3(0.0f, 1.0f , 0.0f);
    	v[1].tex = D3DXVECTOR2(0.5f, 0.0f); 
    
    	v[2].pos = D3DXVECTOR3(1.0f, -1.0f, 0.0f);
    	v[2].tex = D3DXVECTOR2(1.0f, 1.0f);
    
    	VertexChunck vert_chunck;
    	vert_chunck._num = 3;
    	vert_chunck._singlesize = sizeof(Vertex);
    
    	ChunckHeader vert;
    
    	vert._chunckSize = sizeof(vert_chunck);
    	vert._chuncktype = GMESH_TYPE_VERTEX;
    
    	out.seekp(0, ios::beg);
    	out.write(reinterpret_cast<char*>(&vert),sizeof(ChunckHeader));
    	out.write(reinterpret_cast<char*>(&vert_chunck),sizeof(VertexChunck));
    	out.write(reinterpret_cast<char*>(&v),sizeof(Vertex) * ARRAYSIZE(v) );
    
    	out.close();
    

    Es wird dabei so vorgegangen, dass man immer diese ChunckHeader Teile liest.Danach bekommt man den Typ des folgenden Anteils und seine Größe.
    Jetzt leist man das ganze wieder in eine Struktur je nach Typ (z.B in den VertexChunck) und bekommt entgültige Daten wie die Anzahl kommender Vertices und desen Größe.

    Das ist zum Lesen:

    std::ifstream File_Stream(c->path.c_str(),std::ios::in | std::ios::ate | std::ios::binary );  //Öffne Datei im binären mode und setzte positionszeiger ans ende
    	File_Stream.seekg(0, std::ios::beg);
    
    	std::ofstream a("Engine.txt",std::ios::out);
    
    	if(File_Stream.good() )
    	{
    
    		while( !File_Stream.eof() )
    		{
    			ChunckHeader _chunckHeader;
    
    			File_Stream.read(reinterpret_cast<char*>(&_chunckHeader),sizeof(ChunckHeader)); 
    
    			switch(_chunckHeader._chunckType)
    			{
    			case GMESH_TYPE_VERTICES:
    
    				VertexChunck _vertexChunck;
    
    				if(File_Stream.read(reinterpret_cast<char*>(&_vertexChunck), sizeof(_chunckHeader._chunckSize)))
    				{
    					int _num = static_cast<int>(_vertexChunck._number);
    					a << _num << std::endl;
    					Vertex *_tempvertex = new Vertex[_num];
    					File_Stream.read(reinterpret_cast<char*>(&_tempvertex), sizeof(_vertexChunck._singleSize) * _vertexChunck._number);
    					a << "Size 1:" << sizeof(_vertexChunck._singleSize) * _vertexChunck._number << " Size 2:" << sizeof(&_tempvertex) << std::endl;
    
    					for(int i = 0; i < _num; i++)
    					{
    						a << "X:" << _tempvertex[i].position.x << " Y:" << _tempvertex[i].position.y << " Z:" << _tempvertex[i].position.z << std::endl;
    					}
    
    				}
    
    				break;
    			default:
    				File_Stream.seekg(_chunckHeader._chunckSize,std::ios::cur);  //Falls nicht erkannt einfach überspringen
    			};
    
    		}
    	}
    	else
    	{
    		return 1;
    	}
    

    Hier wird das ganze gelesen.Was komisch ist ich bekomme als erstes einmal einen Vertexchunck und kann die Anzahl Vertices rausfinden (_num) was auch richtig ist wenn ich es lese.Dann erstelle ich ein dynamisches Array aus der Vertex struktur und lese das ganze dort ein. Wenn ich versuche dass dan auszugeben bekomme ich ein ÄLaufzeitfehler von wegen Memory oder sowas.Obwohl ich nur einmal diesen Vertex chunbck in die Datei geschrieben habe kommt der irgendwie 2 mal dazu das ganze zu lesen.

    Ich hoffe mir kann da einer bei diesem Roman helfen und einen Fehler beim schreiben / lesen finden 🙂

    Dankeschön


  • Mod

    Immer der gleiche Fehler, woher kommt diese Seuche?

    while (not eof(datei))
    {
     lese(datei);
     verarbeite;
    }
    

    Diese Ausleselogik war mal vor 40 Jahren in Pascal richtig, aber in sonst keiner anderen Sprache die ich kenne. Eine Datei weiß nicht im Voraus, dass sie am Ende ist, das stellt sie nach dem (fehlgeschlagenen) Lesen fest.

    while (lese(datei))
    {
     verarbeite;
    }
    

    So geht das.

    Zu deinem Code: Ich schätze du bekommst gleich noch massenhaft Kommentare zu den ganzen Casts (noch dazu reinterpret_casts) und dem new[]. Merke: Casts deuten auf Fehler im Design hin. Hier fehlen deinen Klassen saubere Streamoperatoren (die dürfen auch gerne ein Binärformat benutzen, wenn du möchtest) und new[] ist immer das schlechtere vector.



  • VertexChunck _vertexChunck;
    File_Stream.read(reinterpret_cast<char*>(&_vertexChunck)
    
    vs.
    
    Vertex *_tempvertex = new Vertex[_num];
    File_Stream.read(reinterpret_cast<char*>(&_tempvertex)
    

    mach doch eine Schleife von 0 bis _num, dann kannste alles schön auf dem Stack lassen und schreibst nicht an die falschen Bereiche.

    greetz KN4CK3R



  • Hmmm also wegen dem Design wundere ich mich, da ich das ganze in dem Buch von David Scherfgen ( DirectX Programmieren....) gelesen hab und das ganz gut sein soll.

    Könnt ihr mir den ein anderes Design vorschlagen als mit den Chuncks, was besser ist oder war einfach nur diese Stelle mit dem Lesen falsch



  • Okey jetzt gehts ohne die Instanzierung der Struktur.Ich habe mal aus Interesse die Größe des puffers abgefragt.

    Ich speichere 3 Vertices in meiner Datei, wobei eins 4 Byte groß ist, was auf 12 Bytes kommt. Ich erstelle ja den puffer dynamisch mit der Anzahl der Vertices , aber mit sizeof bekomme ich nur 4 Bytes , als ob das nur einer währe.

    Wie genau könnte man das ohne das reinterpret_cast machen ???
    Ich hatte die Idee einen void Zeiger zu erstellen (quasie eine virtuelle Datei ) und dort zuerst die gesammte datei reinzukopieren und von dort aus dan parsen....



  • sizeof(zeiger) = 4 != 12
    Der reinterpret_cast beim Lesen/Schreiben würde mich bei einem POD Datentyp nicht sonderlich stören.

    greetz KN4CK3R



  • Bob Wolfskin schrieb:

    int main()
    {
    
    	ofstream out("model.gsm",ios::out|ios::binary);
    
            Vertex v[3];
    
    	// ...
    
    	out.write(reinterpret_cast<char*>(&v),sizeof(Vertex) * ARRAYSIZE(v) );
    
    	// ...
    

    Jo, moin!
    Wie is'n ARRAYSIZE definiert? (Und warum?)



  • Okey hab jetzt reinterpret_cast gegen (char*)&blah ersetzt.
    ARRAYSIZE is ein Macro was angibt wieviel Elemente ein array hat ( hier 3 Stück )

    Ich wundere mich einfach warum dasm it dem Array pointer nicht geht, was nicht so gut ist, da ich später zum ausfüllen Puffers ein solches dynamisches Array brauche.

    Die Frage ist warum folgendes verschiedene größen angibt.

    int _num = 3;
    Vertex* a = new Vertex[_num]; // das sind jetzt 3 Stück je 4 Bytes
    cout << sizeof(a) << endl; // Größe des Arrays
    cout << sizeof(Vertex) * 3 << endl; // Die richtige Größe jedoch größer als das Array
    

    Müsste ja eigendlich Vertex = 4 Bytes -> * 3 = 12 Bytes müssten es sein aber wenn ich Vertex* a= new Vertex[3]; erstelle bekomme ich nur 4 Bytes (liegt vieleicht daran dass die nicht ausgefüllt sind ?? )



  • Bob Wolfskin schrieb:

    Die Frage ist warum folgendes verschiedene größen angibt.

    int _num = 3;
    Vertex* a = new Vertex[_num]; // das sind jetzt 3 Stück je 4 Bytes
    cout << sizeof(a) << endl; // Größe des Arrays
    cout << sizeof(Vertex) * 3 << endl; // Die richtige Größe jedoch größer als das Array
    

    Die Antwort ist:

    sizeof(a) == sizeof(Vertex*) // a ist ein Vertex*
    


  • Aber durch die Instanzierung werden doch 3 Elemente reserviert oder icht ?



  • Bob Wolfskin schrieb:

    Aber durch die Instanzierung werden doch 3 Elemente reserviert oder icht ?

    Ja, aber die Information über die Größe des Arrays ist nicht über 'a' zu erreichen.
    Die musst Du irgendwie mitschleppen.

    PS: Der Compiler ist Dir hier klar im Vorteil, weil der nämlich die Größe für delete [] a; wieder auslesen kann...


  • Mod

    Es gibt da so eine Klasse in der Standardbibliothek, die die Größe mitschleppt und sich automatisch um das new und delete kümmert....



  • Bob Wolfskin schrieb:

    Aber durch die Instanzierung werden doch 3 Elemente reserviert oder icht ?

    Dadurch wird der Pointer selber aber nicht größer. Nur der reservierte Speicher, auf den er zeigt.

    Makro? schrieb:

    Der Compiler ist Dir hier klar im Vorteil, weil der nämlich die Größe für delete [] a; wieder auslesen kann...

    Streng genommen ist das nicht der Compiler, aber ich hab heute schon genug Haare gespalten 😉

    SeppJ schrieb:

    Es gibt da so eine Klasse in der Standardbibliothek, die die Größe mitschleppt und sich automatisch um das new und delete kümmert....

    Kschsch. Du willst hier doch niemanden zu sauberem C++ verführen, oder?



  • pumuckl schrieb:

    Makro? schrieb:

    Der Compiler ist Dir hier klar im Vorteil, weil der nämlich die Größe für delete [] a; wieder auslesen kann...

    Streng genommen ist das nicht der Compiler, aber ich hab heute schon genug Haare gespalten 😉

    Fiel mir auch auf, aber:
    Ohne Registrierung keine Editierung...



  • Ich könnte das ganze auch folgenderweise machen:
    (Wird jedoch nicht auf dem Stack sondern auf dem Heap verbleiben)

    Vertex *v = (Vertex*)malloc(sizeof(*v));
    new (v) Vertex();  //oder so ähnlich
    

    Dabei wird direkt der Speicherbereich reserviert 😉
    Ist aber vollkommen unnötig


  • Mod

    Nenn mal einen einzigen Vorteil von malloc/placement new gegenüber "normalem" new und einen einzigen Vorteil von new genenüber std::vector.



  • SeppJ schrieb:

    Nenn mal einen einzigen Vorteil von malloc/placement new gegenüber "normalem" new

    Man kann reallozieren. 🙂


  • Mod

    Kellerautomat schrieb:

    SeppJ schrieb:

    Nenn mal einen einzigen Vorteil von malloc/placement new gegenüber "normalem" new

    Man kann reallozieren. 🙂

    Nicht, wenn du einen Konstruktor brauchtest, denn dann geht eine eventuelle Verschiebung schief.


Anmelden zum Antworten