Jump to content

  • Log In with Google      Sign In   
  • Create Account


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


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
13 replies to this topic

#1 DarkHorseKnight   Members   -  Reputation: 143

Like
0Likes
Like

Posted 10 April 2012 - 04:22 AM

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());


Sponsor:

#2 kauna   Crossbones+   -  Reputation: 2356

Like
2Likes
Like

Posted 10 April 2012 - 05:14 AM

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<>.


int num_bytes=numfloats*sizeof(float);

You don't seem to initialize the numfloats in the code you provided.


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

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!

#3 DarkHorseKnight   Members   -  Reputation: 143

Like
0Likes
Like

Posted 10 April 2012 - 05:25 AM

GLBufferData - Parameter 2 size
Specifies the size in bytes of the buffer object's new data store.

#4 Hodgman   Moderators   -  Reputation: 29688

Like
2Likes
Like

Posted 10 April 2012 - 05:35 AM

What he meant is that sizeof(points) tells you how many bytes a std::vector takes up, not how many bytes a Point takes up.

#5 kauna   Crossbones+   -  Reputation: 2356

Like
0Likes
Like

Posted 10 April 2012 - 05:35 AM

Hi,


The correct way to calculate the size in bytes is then points.size()*sizeof(Point).


Best regards!



#6 Brother Bob   Moderators   -  Reputation: 8088

Like
4Likes
Like

Posted 10 April 2012 - 06:24 AM

Apart from the above, there are also (at least) four major fundamental errors with how you're trying to use your buffer objects.
  • 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.
  • 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.
  • 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.
  • 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.

#7 Ectara   Crossbones+   -  Reputation: 2929

Like
1Likes
Like

Posted 11 April 2012 - 11:04 AM

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.

#8 RobTheBloke   Crossbones+   -  Reputation: 2339

Like
-2Likes
Like

Posted 12 April 2012 - 10:05 AM

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/

#9 Ectara   Crossbones+   -  Reputation: 2929

Like
0Likes
Like

Posted 12 April 2012 - 11:53 AM

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...



#10 RobTheBloke   Crossbones+   -  Reputation: 2339

Like
-1Likes
Like

Posted 13 April 2012 - 06:13 AM

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.

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];


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.

#11 L. Spiro   Crossbones+   -  Reputation: 13391

Like
0Likes
Like

Posted 13 April 2012 - 07:11 AM

A structure with 3 floats could very well be padded out to four floats.

“Very well” is a bit optimistic. The very few cases in which this is possible are very exceptional and fully under your control. Anyone using __declspec() should know why this is being used, and, outside of that, #pragma pack defines the results of alignment and padding very clearly.

If you set packing to 1, neither the structure nor the members inside it will have any padding. Alignments are defined as min( packing, sizeof( TYPE ) ). Meaning that a packing of 8 still results in floating being aligned to 4-byte boundaries.

This is guaranteed behavior because it is important for certain operations that this pragma was specifically designed to address.

Giving newbies unnecessary concerns by saying it “very well” may be padded out is not a good idea. “It can be padded out (without your explicit request) on 64-bit target compiles under certain circumstances that most will never encounter, and even then it can be reliably handled,” might be a better way to put it.


L. Spiro


P.S.: When I refer to newbies I don’t mean anyone here including the topic poster; I was thinking about anyone stumbling onto this topic via Google search etc.
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#12 Ectara   Crossbones+   -  Reputation: 2929

Like
-1Likes
Like

Posted 13 April 2012 - 09:40 AM

No, I think _you're_ building a straw man. This is exactly the point I'm trying to make, and nothing else other than the aforementioned. He's using no compiler pragmas or declaration specifications. The standard says it's implementation defined, and could pad it to a million bytes. I know there are pragma directives and declaration options that can be used. There's no point in casting aspersions on my intelligence based on how I word it. My point is, if you leave it to assumptions, then one day, it just might break and you'll have to rewrite. If a beginner realizes this works for _majority_ of the compile targets, then what stops them from having a structure containing single bytes, like

struct {
uint_8 r;
uint_8 g;
uint_8 b;
}Color;

and passing it to OpenGL, thinking they'll all fall one after another? The compiler should pad. And I appreciate the condescension, but there's no confusion. This "don't confuse the newbie" mentality will bite him. Sure, because there are three 4 byte floats on a 32bit system, it more than likely will not maybe possibly add padding that it could. We'd consider the compiler broken, because it is supposed to be optimal, but it simply could. I know this is just inviting people to nitpick, but if he has all of his code working, and has a decent engine, and decides to use SSE to speed up his transformations, he might choose to align to 16 bytes. This code will break if he uses the wrong stride, and assumes it is laid out like an array, and he must go back and fix all of it. I've read my compiler's documentation on it, and the language standard. Who hasn't? In this case, it has no reason to pad, but if it does, then it may, and I typically hope it would and plan for it. All I'm saying is not to make an assumption, that might not be true all of the time. It'll optimize in your best interest, but that might not always hold true. Since when is not making assumptions bad advice when the API acknowledges that this condition can happen and allows you to work around it, with 100% certainty that it will work?

And once again, the answers ignore the fact that in this case, it probably won't pad, but in my example above, it might. It doesn't have to, but it might. These arguments are taking one case to misconstrue my argument that this isn't always safe. Not just if he uses the same code on different targets or compilers, but if he makes a different structure with different members, and assumes they're tightly packed because someone told him one such case worked, so all of them must work.

Anyway, this witch hunt aside, what about my advice that if he is looking to use an array of floats, that he should use an array of floats, and if he is going to use the array of structures, then he should set up the call to use the stride like an array of structures, and not rely on an array and a structure to have the same representation? This sounds like a pretty solid argument to me, but the straw man of what a compiler will likely do is clouding the conversation. It's this kind of squabble that keeps me from posting here; few people read my posts in entirety, and they'll ignore my advice to start an argument. If he sets up the stride properly, or use an array of floats, he'll avoid the problem entirely. Right now, he's using a mix of the two, by not having the correct stride, and using structures. I'm not posting here for my benefit, I'm advising that he use the tools properly. Somehow, the correct answer ballooned into people trying to earn reputation by browbeating.

In addition:

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...


Once again, I get the feeling that you skimmed my post, and didn't read it in entirety. This has to be the definition of a straw man; you're criticizing me for believing things I explicitly said were unlikely. I essentially indicated that x, y, and z will have a 99% probability of being contiguous, aside from the edge cases outlined above. Then you ignored my point, and criticized me for a fictional argument that I was never making. On a 32bit system, although the compiler is allowed to, it most likely will not align each member to a value greater than four bytes. I am not arguing this, so I don't know to whom you are replying.

#13 L. Spiro   Crossbones+   -  Reputation: 13391

Like
1Likes
Like

Posted 13 April 2012 - 09:54 PM

I wasn’t being condescending, but if that is what you appreciate-

My concerns were real. I don’t want to see some beginner getting too nervous about this topic based on your suggestion, particularly with the example you provided. As I mentioned, unrequested padding beyond 4 bytes is extremely rare across all compilers, and will only ever rear its head on 64-bit platforms, and even then it is still rare as most compilers still prefer to pad to 4 bytes for compatibility.

Your second example above is a more realistic case for padding, but can still be manually handled via #pragma pack.

You aren’t wrong. People should be aware of padding. But if it is worth mentioning padding, it is equally worth mentioning #pragma pack.


L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#14 Cornstalks   Crossbones+   -  Reputation: 6974

Like
1Likes
Like

Posted 14 April 2012 - 01:50 PM


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.

No it's not. Not according to the C++ standard, at least.

I don't get why people (particularly RobTheBloke) are so against the valid point that Ectara raised about padding. Yes, it's unlikely that the compiler will pad a structure of nothing but floats, but that doesn't change the fact that naively casting the structure to a pointer and using it like an array is undefined behavior (which is what the OP is doing).

Yes, padding can be controlled with compiler flags, but the OP isn't doing that right now, and until he does, he needs to worry about potential padding if he's going to write robust, valid C++ code.

No sense in starting a holy war about this. I think a lot of the disagreement here is caused by people just wording things poorly. Take a step back, all, and breathe. I think L. Spiro's last post has a nice summary of what the last 6 posts have been trying to say.
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS