Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

std::vector problems

Started by jagot Jun 3, 2006 at 9:09 AM 6 replies 1.1k views
Original Post
jagot
jagot
Hello! I'm writing a model loader for my own 3D model format, and before rendering I'm loading all the vertex data and so on into vectors. I've found an example in the source code accompanying Evan Pipho's "Focus on 3D models" on how to use std::vector's of 2 dimensions:
[source lang=cpp]
struct Vector3
{
	float m_fVec[3];

	Vector3(float * fVec)
	{
		memcpy(m_fVec, fVec, sizeof(float[3]));
	}
};


And then:
[source lang=cpp]
vector<Vector3> m_vVertices;
Vector3 * m_pVerts;


And finally, after loading the data like this...
[source lang=cpp]
//get the line
fgets(cLine, 256, fp);
//get the vertex coords
sscanf(cLine, " %f %f %f", &fTemp[0], &fTemp[1], &fTemp[2]);
//add to the vertex array
m_vVertices.push_back(fTemp);


...it is addressed like this...
[source lang=cpp]
m_pVerts = &m_vVertices[0];


...and accessed like this:
[source lang=cpp]
glVertex3fv(m_pVerts[vertexIndex].m_fVec);



I tried to implement those ideas myself like this...
[source lang=cpp]
#include <cstdlib>
#include <cstring>
#include <vector>
#include <iostream>
#include <fstream>
#include <windows.h>
#include <GL/GL.h>

int main(int argc, char *argv[]){
    struct vertVector{
		GLfloat co[3];
		
		vertVector(GLfloat *inCo){
			memcpy(co, inCo, sizeof(GLfloat[3]));
		}
	};
	unsigned int hMagic, fMagic;
	char hIdent[5]="    ", fIdent[5]="    ";
	unsigned int vCount, fCount;
	
	std::ifstream inFile;
	inFile.open("house.opsm");
	if(inFile){
		{
			inFile.read((char*)&hMagic,
				std::streamsize(sizeof(hMagic)));
			inFile.read((char*)&hIdent,
				std::streamsize(sizeof(char[4])));
			inFile.read((char*)&vCount,
				std::streamsize(sizeof(vCount)));
			inFile.read((char*)&fCount,
				std::streamsize(sizeof(fCount)));
		}
		printf("Header:\nMagic number: %i\tIdent: %s\nVertices: %i\tFaces: %i\nIdent correct: %i\n",
			hMagic, hIdent, vCount, fCount,
			!strcmp(hIdent, "OPSM"));
		
		std::vector<vertVector> verts;
		
		vertVector *vertsPtr;
		
		GLfloat tempVert[3];
		
		{
			for(unsigned int i=0;i<vCount;i++){
				inFile.read((char*)&tempVert,
					std::streamsize(sizeof(GLfloat[3])));
				verts.push_back(tempVert);
			}
		}
		vertsPtr=&verts[0];
		
		for(unsigned int i=0;i<vCount;i++)
			printf("I: %i\t X: %f\tY: %f\tZ: %f\n",
				i, vertsPtr.co[0], vertsPtr.co[1], vertsPtr.co[2]);		
	}
	else{
		printf("File not found!\n");
	}
	inFile.close();
	
	return 0;
}


...but upon compiling I got this:

Compiler: Default compiler
Building Makefile: "G:\Documents and Settings\Dim-Or Jagot\Mina dokument\programmering\Projects\opModelLoader\Makefile.win"
Executing  make...
make.exe -f "G:\Documents and Settings\Dim-Or Jagot\Mina dokument\programmering\Projects\opModelLoader\Makefile.win" all
g++.exe -c main.cpp -o main.o   
main.cpp: In function `int main(int, char**)':

main.cpp:38: error: `main(int, char**)::vertVector' uses local type `main(int, char**)::vertVector'
main.cpp:38: error:   trying to instantiate `template<class _Alloc> class std::allocator'

main.cpp:38: error: template argument 2 is invalid
main.cpp:38: error: invalid type in declaration before ';' token

main.cpp:48: error: `push_back' has not been declared
main.cpp:48: error: request for member of non-aggregate type before '(' token
main.cpp:51: error: invalid types `int[int]' for array subscript

make.exe: *** [main.o] Error 1
Execution terminated
What am I doing wrong? I might mention that Pipho declared the structs and the vectors in a header to a wrapper class, but I can't see that that should make any difference. I'm using MinGW32 right now, and compiling Evan Pipho's code whith g++ did not pose any problem, so I can't understand why my code's not working. Have a nice day! Stefanos Carlström
deffer
deffer
Your problem can be reduced to this sample:

struct s1 {};void f(void){   struct s2 {};   std::vector<s1> vs1; // ok   std::vector<s2> vs2; // error};


s2 is locally defined, and as such, cannot be used as a template argument, whereas s1 can. You got to move the definition of vertVector outside of main.

This behaviour can vary across different compilers, so g++ could be able to eat this, but it is not required to, because it is non-standard (AFAIK).
jagot
jagot
Thanks!
That solved the problem. I've stepped into another problem though. Under Windows when reaching i=56 or something all the follows X values are the same, as are the Y and Z values, respectively. This problem does not arise when printing the values directly (from a Python script) or when running the C++ program under Linux. I reckon this has something to do with memory. Since I got 196 vertices with 1 coordinate per axis (3 axes), each coordinate a float, 4 bytes long, that makes the vector 196*3*4 bytes which is approximately 2.3 MB. That should not be a problem though, as Pipho's code loads in a much more detailed model (under Windows), and 2.3 MB isn't that much either. The same problem arose when trying to create a vector the old way:

[source lang=cpp]GLfloat *vector = new GLfloat[vCount*3]


Where vCount in this example is 196.

Why is this happening?

Stefanos
Enigma
Enigma
Try opening your file in binary mode and see if that helps.

Σnigma
Captain P
Captain P
You can create vectors containing vectors as following:

vector< vector > name;

Just be sure to leave at least one space or tab between the two >'s, otherwise it's seen as the >> operator.

However, for your type of data, perhaps it's easier to create an array of vertices with the new[] operator. You can read from the file and map the data directly to the adress of this array. Just make sure the struct you write to is the same as the data you read, so if a vertex consists of 3 floats, 12 bytes, then you should use an array of structs that contain exactly 3 floats. Be aware of member variable alignment here, as some compilers adjust the size of such types to make them a little faster to read. A 12 byte struct would become a 16 byte one, and that obviously messes up such read operations.
I think this is a little more compact than using a vector. Don't forget to clear the data with the delete[] operator, but I guess you knew that already. Hope this helps you. :)
Bob III
Bob III
Check as you read in each value that you havn't hit an I/O problem. Specifically, EoF.
"That''s to do with the day I finally realized the world had gone totally mad and built the Asylum to put it in, poor thing, and hoped it would get better."-Wonko the SaneSo Long, and Thanks for All the Fish
jagot
jagot
Σnigma:
Thanks, that helped! I forgot that Windoze differs text and binary files. I like Linux better at that point.

Captain P: If I use multidimensional vectors, how do I assign values?
Like this?
vector< vector<int> > name;name.reserve(10);name[0].push_back(56);name[1].push_back(454);

And so on?

Well, anyway the way I do it right now is fine with me, and no, I did not reach EoF Bob II, but thanks anyway. As I designed the file format (and the exporter) myself, I knew exactly how much I could read in (header size + vCount*3*4 + fCount*3*4 + fCount*3*2*4 + footer size). I also put a footer which I checked and found to be correct later on.

My only problem right now is that I can't render the model in any other ways than points, or else the app just crashes down on me. I'll see if I can figure it out myself, or else I'll come back.

Thanks for help!

Stefanos
jagot
jagot
Now all problems with std::vector are solved; the loader works as it should!

Have a nice day!
Stefanos

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.