Jump to content
  • Advertisement
Sign in to follow this  
DominicHughes

How do I get the data out my std::vector and use it in OpenGL?

This topic is 2320 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hay All I'm working on a 3d model loader and I need to get the vector data into OpenGL I tried using float* point=reinterpret_cast<float*>(&points[0]); to convert the vector into a float but I don't think it works as I don't see anything on the frustum upon compiling the program.

Below is my attempt at trying to do this myself.

Here is my structure and vector setup:



//Structure for vertex points x y z
struct Point {float x, y , z; };

//vector for faces
std::vector<int>faces;

//vector for vertex points x y z
std::vector<Point>points;

//push back values
points.push_back(Point());

//create a structure variable
Point p;

//declare a interger
int face[4];


Here are my conversions:


//this is just my vector conversions/size conversions
int numfloats;
float* point=reinterpret_cast<float*>(&points[0]);
int num_bytes=numfloats*sizeof(float);


Here are my functions I'm using to render:


GLuint vertexbuffer;

glGenVertexArrays(1, &vao[3]);

glGenBuffers(1, &vertexbuffer);

glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);

glBufferData(GL_ARRAY_BUFFER, points.size() * sizeof(points), &points.front(), GL_STATIC_DRAW);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,num_bytes ,points);

glEnableClientState(GL_VERTEX_ARRAY);

glVertexPointer(3, GL_FLOAT, points.size(),points.data());

glEnableClientState(GL_INDEX_ARRAY);

glIndexPointer(GL_FLOAT, faces.size(), faces.data());

glEnableVertexAttribArray(0);

glDrawElements(GL_QUADS, points.size(), GL_UNSIGNED_INT, points.data());

Share this post


Link to post
Share on other sites
Advertisement
I'm not familiar with OpenGL syntax but you may use points.data() to get pointer to your data. No need to use &points[0] or &points.front(). I just noticed that you are using the .data() already in several places. Anyway, you may cast your pointer after with reinterpret_cast<>.


[color=#000088]int[color=#000000] num_bytes[color=#666600]=[color=#000000]numfloats[color=#666600]*[color=#000088]sizeof[color=#666600]([color=#000088]float[color=#666600]);

[color=#666600]You don't seem to initialize the numfloats in the code you provided.


[color=#000000]glBufferData[color=#666600]([color=#000000]GL_ARRAY_BUFFER[color=#666600],[color=#000000] points[color=#666600].[color=#000000]size[color=#666600]()[color=#000000] [color=#666600]*[color=#000000] [color=#000088]sizeof[color=#666600]([color=#000000]points[color=#666600]),[color=#000000] [color=#666600]&[color=#000000]points[color=#666600].[color=#000000]front[color=#666600](),[color=#000000] GL_STATIC_DRAW[color=#666600]);[color=#000000]

points.size() * sizeof(points) probably doesn't give you the result you are after. sizeof(points) won't give you the size of a single element in the vector.


Cheers!

Share this post


Link to post
Share on other sites
What he meant is that sizeof(points) tells you how many bytes a [font=courier new,courier,monospace]std::vector[/font] takes up, not how many bytes a [font=courier new,courier,monospace]Point[/font] takes up.

Share this post


Link to post
Share on other sites

Hi,



[color=#000000][font=helvetica, arial, verdana, tahoma, sans-serif]

The correct way to calculate the size in bytes is then points[/font][color=#666600][font=helvetica, arial, verdana, tahoma, sans-serif]

.[/font][color=#000000][font=helvetica, arial, verdana, tahoma, sans-serif]

size[/font][color=#666600][font=helvetica, arial, verdana, tahoma, sans-serif]

()[/font][color=#666600][font=helvetica, arial, verdana, tahoma, sans-serif]

*[/font][color=#000088][font=helvetica, arial, verdana, tahoma, sans-serif]

sizeof[/font][color=#666600][font=helvetica, arial, verdana, tahoma, sans-serif]

([/font][color=#660066][size=2]Point[color=#666600][font=helvetica, arial, verdana, tahoma, sans-serif]

).[/font]



[color=#666600][font=helvetica, arial, verdana, tahoma, sans-serif]

Best regards![/font]

Share this post


Link to post
Share on other sites
Apart from the above, there are also (at least) four major fundamental errors with how you're trying to use your buffer objects.

  1. When a buffer object is bound, any pointer passed to the vertex array functions uses the buffer objects storage as a reference. The pointer is, in effect, an offset into the buffer object. If you want the vertex array to point to the beginning of a bound buffer object, you have to pass 0, which means the buffer object's storage plus 0 bytes into the buffer.
  2. You're mixing the old style glVertexPointer with the modern style glVertexAttribPointer. Although not a error in itself, it appears to be incorrect usage in this case. Why are you binding the attribute to the hardcoded index zero? If you're not using shaders and generic attributes, then you shouldn't be using this function.
  3. The index buffer is not what you think it is. It has nothing to do with faces or vertex indices. It is the indexed color mode equivalent to the RGB color mode function glColorPointer. The index array is stored in an element array array buffer, and is used by the last parameter to glDrawElements and equivalent functions.
  4. Point three is related to this point. Beside having the same problem as point one (you should store the index array in an element array buffer and pass the proper pointer), you are passing a conceptually wrong pointer to glDrawElements. You have to pass an index array, not vertex data. But then again, you shouldn't pass a pointer to th

You also appear to allocate three vertex array object names you never use. Perhaps you're using them later, but from the code you showed they appear to have no effect.

Share this post


Link to post
Share on other sites
Might I also add that passing a pointer to a structure of float data and using it as a float array might have undefined results. If the compiler decides to pad the structure, to make it an even multiple of 16 bytes for example, your stride will likely be off if you assume they will be one after another.

Another point, is you are passing points.size() as the stride to glVertexPointer(). http://www.opengl.org/sdk/docs/man/xhtml/glVertexPointer.xml
The stride parameter is how many bytes should be added to its internal pointer to move to the next element. This is where you would use the size of the structure, to prevent the problem I said before, though you should use an array if you are passing an array. std::vector::size() will return the number of elements in the array. http://www.cplusplus.com/reference/stl/vector/size/

If there are 5 points in the vector, passing its size as the stride will assume that the start of each set of data is 5 bytes apart. If it is 2, then it will assume 2 bytes apart. Pass the correct stride, and in addition to the above points, you may make progress.

Share this post


Link to post
Share on other sites

Might I also add that passing a pointer to a structure of float data and using it as a float array might have undefined results.


1. a C++ compiler that inserts padding in a struct containing nothing but floats is one that is horribly broken. Realistically you'd need to use a struct member alignment of 5, 6, 7, 9, or 10 to cause any problems. Since those are not valid values, you have nothing to fear. Using a declspec alignment may cause padding at the end of the structure, but X/Y/Z will still be next to each other in memory.

2. Adding a virtual function could cause problems.

3. Although not really. If your stride param is sizeof(MyStruct), and you are using &myData[0].x as the data pointer to glBufferData/glBufferSubData, then you really aren't going to have any problems (unless myData is a zero length std::vector). You might be munging some additional data into the VBO (eg an unused 'w' used for padding, or a vtable pointer if you're mental). This won't cause problems, it's just a little wasteful.





If the compiler decides to pad the structure, to make it an even multiple of 16 bytes for example, your stride will likely be off if you assume they will be one after another.


Always use sizeof(MyStruct). Problem solved! \o/

Share this post


Link to post
Share on other sites

1. a C++ compiler that inserts padding in a struct containing nothing but floats is one that is horribly broken. Realistically you'd need to use a struct member alignment of 5, 6, 7, 9, or 10 to cause any problems. Since those are not valid values, you have nothing to fear. Using a declspec alignment may cause padding at the end of the structure, but X/Y/Z will still be next to each other in memory.

A structure with 3 floats could very well be padded out to four floats. There's nothing weird about that, especially if you explicitly say you need to align this data on a 16 byte boundary for SIMD or something. This answer, by the way, is ignoring the actual problem that
float data[9];
is not the same as
struct {
float x, y, z;
}data[3];
The compiler likely even gives you options that could break this easily. Relying on structure elements to be placed one after another as if it were an array is dangerous. If you want an array, use an array. Otherwise, use the stride to set it up like an array of structures. The API purposely allows it. The compiler will likely not put padding between x, y, or z, but likely will put padding between z and the next x. Note that he's passing an array of structures.

I have no idea if the other two points are in response to me; they have little to do with what I said.


Always use sizeof(MyStruct). Problem solved! \o/



... This is where you would use the size of the structure, to prevent the problem I said before...

Share this post


Link to post
Share on other sites

The compiler likely even gives you options that could break this easily.

That statement is false. The only way you can break this is through the use of declspec/__attribute__ alignments within your code. The compiler options you seem to think exist, don't actually exist, or you are simply confused as to how they work.


[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

This answer, by the way, is ignoring the actual problem that

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

float data[9];

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

is not the same as

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

struct {

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

float x, y, z;

[/font]
[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

}data[3];

[/font]



That's a strawman argument. Understand your compiler better, because it doesn't work in the way you think.


Relying on structure elements to be placed one after another as if it were an array is dangerous.

It is not dangerous, it's called having a full appreciation for the meaning of structure member alignment. The valid values for this are 1, 2, 4, 8 or 16. If the values are 1, 2 or 4, then x, y, and z will be laid out one after each other. Now you might think that setting the value to 8 will cause problems, but it won't. In the case of a member alignment of 8 or 16, you still get the following:

struct Vec3
{
float x; ///< offset = 0
float y; ///< offset = 4
float z; ///< offset = 8
};


The compiler will not align each member to 8 bytes. It will assume that because X&Y are 8 bytes, it should just pack them into a single 8byte chunk. If you set it to 16, the size of the struct is still 12 bytes, and X/Y/Z will still be continuous. The only (purely theoretical) problem would occur if your compiler offered a struct member alignment of 5 bytes (or something equally silly). In theory (only), that could lead to a structure size of 14. Since C++ compilers only offer power-of-2 alignments, it is impossible for bytes to be inserted between the variables.



The compiler will likely not put padding between x, y, or z, but likely will put padding between z and the next x.


Again. The compiler will do no such thing, unless otherwise instructed by you. A simple struct of 3 floats is always going to be 12 bytes which ever compiler you use. Where you are getting is confused, is with this:


struct _MM_ALIGN Vec3
{
float x; //< aligned to 0
float y; //< aligned to 4
float z; //< aligned to 8
};


It is true that the above structure will be padded, but then it is also true that the developer has an error in their code. If the Vec3 MUST always be aligned to 16 bytes, then it logically follows that the size of the struct must also be 16 bytes (since the second element in an array would not be aligned). Every C++ compiler around will rectify this mistake automatically, but they will all print out a warning to notify you that you've made a mistake ("Warning: this structure has been padded due to declspec align").



So yes, if you make your structs 16bytes in size, they will be 16 bytes in size. But it is entirely false to claim that there may be some mythical compiler settings that might change a 12byte struct into something larger. Those compiler settings simply do not exist. Virtual functions may change the size of the structure, but again this has absolutely nothing to do with the compiler settings, and everything to do with your code.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!