what happens when I cast a glm::vec3* to a double*? - c++

I am trying to understand a framework I have been provided with and slowly debugging it. In my case I have an array of vec3, memorized with a pointer
vec3 *cx =....;
First of all, every time I try to check the content of a glm::vec3 through debugging I see many values: x, r, s, y, g, t, z, b, p. I don't know why I have all these members, and according to the documentation I see that glm::vec3 is a struct with inside:
if(GLM_COMPONENT == GLM_COMPONENT_ONLY_XYZW)
value_type x, y, z;
elif(GLM_COMPONENT == GLM_COMPONENT_MS_EXT)
union
{
struct{value_type x, y, z;};
struct{value_type r, g, b;};
struct{value_type s, t, p;};
};
else//(GLM_COMPONENT == GLM_COMPONENT_GLSL_NAMES)
union {value_type x, r, s;};
union {value_type y, g, t;};
union {value_type z, b, p;};
endif//GLM_COMPONENT
I don't know where in the huge framework I am studying which one of the options above is actually chosen. And I don't know the meaning of all those members.
I only know that through debugging I see all those values but, as any other vec3, I use the x,y,z values for my calculations.
After this, I would like to know what actually happens if I cast an array of vec3 to an array of doubles. In practice:
double * cast = (double*)cx;
What does it give me back?
In order to understand, I tried to do this:
vec3 boh(1.0);
vec3 boh2(2.0);
vec3 * try = new vec3[2];
try[0] = boh;
try[1] = boh2;
double* try2 = (double*)try;
I realize that try points to the first vec3, which is boh1, so if I go debugging, I see all the x, r, s, y, g, t, z, b, p set to 1.0. Likewise try2 should be pointing to "something" related to boh1, but the debug shows me that try2 has the value 0.0078125018480932340. So, what is actually happening?

Officially, that is undefined behavior. It all depends what the glm::vec3 structure contains.
I would refer to the glm reference pages. They clearly explains what glm::vec3 is and how to use it.

Related

C++ vector class definition

I'm only beginning in C++ and I'm struggling to understand some code from a custom vector class in an article I'm working through. The author writes it as:
class vec3
{
public:
vec3() {}
vec3(float e0, float e1, float e2)
{
e[0] = e0;
e[1] = e1;
e[2] = e2;
}
(...)
But so far I've only seen class definitions where the types of data it holds are defined, such as:
class vec3
{
public:
float m_x;
float m_y;
float m_z;
vec3(float x, float y, float z) : m_x(x), m_y(y), m_z(z)
{}
My guess was that the code in the article is creating an empty vector which it then populates with floats or there was something assumed in the definition. Is this just a syntax difference or is there something more fundamental that I'm missing? Apologies for what seems like a basic question but I couldn't find any similar questions. . . it might be too basic for that! But I just wanted to understand it before I moved on.
Thanks,
Paddy
In the code you've posted, you are correct that there is no declaration for the variable e anywhere. I'm not sure if this is because you didn't post that part of the code from the book, or if the book omitted that for brevity.
Without knowing what the book author was meaning by e, I don't want to suggest a completion of the code. There are several things that e could be declared as that would be compatible with the code you've posted.
It defines e as just a float array [e[3]].
With this information added, then there is no relevant difference between three separate members and an array. In the end, both variants will require the same amount of memory, and in most cases, the (optimised!) code generated by the compiler will be exactly the same:
float getY()
{
return m_y;
// will result in address of object + offset to m_y
}
float getY()
{
return e[1];
// will result in address of object + offset to e + offset to second element
// as both offsets are constant, they will be joined to one single summand
// and we are back at first variant...
}
One of the few things you can do with arrays but not with separate members is having a loop, such as the following:
float magnitude()
{
float sum = 0.0F;
for(auto f : e)
sum += f*f;
return sqrtf(sum);
}
However, for such short loops, loop unrolling is pretty likely, and the code generated again is with high probability equivalent to the separate member variant:
float magnitude()
{
return sqrtf(m_x * m_x + m_y * m_y + m_z * m_z);
}
With an array, you could pass all three members in one single parameter to other functions (as pointer to first element), with separate members, you'd have to pass all of them separately (well, there are ways around, but they either require extra effort or are "dirty"...).

What is the advantage of using union for struct and array of same size

I read somewhere a piece of code for defining 3d coordinate. So, they used x, y & z coordinate like this below:
union
{
struct
{
float x, y, z;
};
float _v[3];
};
My question is that why a union is required here and also what is the advantage of using struct with an array?
Important note: this construct leads to undefined behavior. What follows is a description of its authors' intentions, which, unfortunately, many compilers translate to precisely the behavior the authors expect, which in turn leads to proliferation of code like that.
union construct is not really required here: the authors used it for convenience. The reason they put a union there is to give themselves a syntax for accessing x, y, and z in two distinct ways:
By specifying the field name - that is, coord.x, coord.y, or coord.z, or
By specifying the field index - that is, coord._v[0], coord._v[1], or coord._v[2].
An approach that provides comparable functionality without running into undefined behavior is to use inline member functions for your access:
struct Vector3D {
int v[3];
int& x() { return v[0]; }
int& y() { return v[1]; }
int& z() { return v[2]; }
};
int main() {
Vector3D coord;
coord.v[0] = 5;
cout << coord.x() << endl;
coord.y() = 10;
cout << coord.v[1] << endl;
return 0;
}
Demo.
As Gill Bates says, in this way you can (maybe) access the 3 coordinates both as x, y, z and as v[0], v[1], v[2]
But as per #Richard Critten comment, this is actually an UB.
You can get the same result in a "safe" way with something like this:
struct Coordinates
{
Coordinates():x(v[0]), y(v[1]), z(v[2])
{
}
int v[3];
int& x;
int& y;
int& z;
};
i.e., using references to the array values and initializing them in constructor
Size of this struct will be obviously different (larger) than the union you show in OP
This way you can address the 3d coordinate as a struct..
foo.x;
foo.y; // etc
But it also allows you to get the 3 variables as an array while occupying the same space (that's the plan at least), accessing them like..
foo._v[0] // x, etc
Anyway, that's the idea. But the moment the struct has any sort of padding between members your array will be misaligned and you will end up reading garbage values. Long story short, this code has undefined behaviour, a bad implementation that shouldn't be used.

3D vertices class or struct

I am writing a small program for learning C++ and 3D.
I have already written a vertex class with usefull methods. (like Dot,Cross, etc...)
class cVector {
...
float x, y, z;
...
float dot(cVector& v);
cVector cross(cVector& v);
...
}
Now I realize OpenGL expects buffers where elements are more like a struct (VBO).
struct sVector {
float x, y, z;
}
So my vertex class is no longer useless, because if i want to manipulate data in the buffer :
1 - I need to extract data of elements in the buffer.
2 - Create a temporary instance of vertex class with the data.
3 - Use vertex class method. (Dot, cross, etc...)
4 - Put the data back to the buffer.
It's not very efficient :(.
I wonder if I should not use a struct to organize my vectors and create global functions that take a pointer to a struct as an argument.
I could handle data buffers more efficiently (just moving pointer) but I feel i would lose the "convenient power" of C++.
In every 3D C++ source code i ever see, all use class for vertex but i dont understand how they can manipulate large amount of vertex in a "struct like" buffer.
Can you help me to understand ? What is the best approach ?
The most common approach in a language like C++ is actually neither of these things.
You are more likely to encounter the following:
struct Vector3 {
union {
struct {
float x,y,z;
};
float v [3];
};
...
Vector3 (float x_, float y_, float z_) : x (x_), y (y_), z (z_) { };
float Norm (void) { return sqrt ((x * x) + (y * y) + (z * z)); }
void Normalize (void) {
float norm = Norm ();
v [0] /= norm;
v [1] /= norm;
v [2] /= norm;
}
};
The reason for this is because using anonymous unions and structs, you can treat the data as either an array of floats (v [...]) or reference the individual components by their name (x, y, z) without a lot of muss or fuss. You get the best of both worlds by using the language more intelligently.
As for the difference between a struct and a class in this particular case, there is none from the perspective of memory representation. The only real difference between a class and a struct in C++ is the default access; struct has public access by default.
When GL needs to access the object's internal memory, you would accomplish this by passing it the pointer: Vector3::v or the individual components, depending on the particular function.
For instance:
Vector3 vec (1.0f, 2.0f, 3.0f);
---------------------------------
glVertex3fv (vec.v);
and
glVertex3f (vec.x, vec.y, vec.z);
are equivalent
On a side-note, anonymous structures are a non-standard extension to C++ but supported virtually everywhere. In the case that you have a compiler that does not support them, you may have to qualify access to x, y, and z by giving the struct a name.
struct Vector3 {
union {
struct {
float x,y,z;
} s;
float v [3];
};
};
If you write your struct this way, then:
Vector3 vec;
assert (vec.v [0] == vec.s.x);
It is messier to have to qualify x that way (using an anonymous struct you can use vec.x).
There is exactly one difference between struct and class: For class the default scope is private, while for struct it is public.
So
class cVector {
...
float x, y, z; // data
...
float dot(cVector& v); // just a function
cVector cross(cVector& v); // just a function
...
}
and
struct sVector {
float x, y, z; // data
}
have exactly the same memory layout (given that x,y,z are the only members variables of cVector).
You can use &v.x to get a pointer to (x,y,z) for OpenGL, e.g. glVertex3f(&v.x);.
You can even do the following to get a pointer to a continuous sequence of vertices for usage with OpenGL:
std::vector<cVector> vertices(100);
const float* data = &(vertices[0].x);

Setting Struct Bounding Box Values

I'm trying to create some bounding boxes around some objects that I have.
I create them like this:
struct boundingBox{
float top;
float bottom;
float left;
float right;
};
I'm having issues setting their values. I have this function which I was hoping would set their values:
void makeBoundingBox(boundingBox bound, float t, float b, float l, float r){
bound.top =t;
bound.bottom =b;
bound.left=l;
bound.right=r;
}
and I am trying to set them like this:
makeBoundingBox(car,b_Size,b_Size,b_Size,b_Size); //where car is a boundingBox object and b_Size is a calculated box size
When I'm using the above line, the values aren't set; I know this because I print to the console to check the values and they always come back 0. However, if within the same function I use makeBoundingBox, I set car.top = 500 manually instead, and print, the car.top is set successfully to 500 and works...
Does the makeBoundingBox method not work correctly by passing a struct object how I am expecting it too?
You're passing the box by value. For the routine to change the actual argument, pass it by reference. I.e.
void makeBoundingBox(boundingBox& bound, float t, float b, float l, float r){
bound.top =t;
bound.bottom =b;
bound.left=l;
bound.right=r;
}
However, instead of that, in C++11 just write
boundingBox{ 1, 1, 10, 10 }
when you need a boundingBox with those values.
In C++03 you can instead define a constructor for the boundingBox class.
Read up on that in your favorite C++ text book.
Here is an example class definition:
struct boundingBox{
float top;
float bottom;
float left;
float right;
boundingBox( float a_top, float a_bottom, float a_left, float a_right )
: top( a_top ), bottom( a_bottom )
, left( a_left ), right( a_right )
{}
};
and you can then create an instance like
boundingBox( 1, 1, 10, 10 )
As a general observation, using float instead of double can create some problems (especially with C++11 curly braces initialization), it has less precision than double, and it has no special advantages except where you need zillions of values, like a few billion.
So, use double.
That's the default floating point type in C++, e.g. it's the type of 3.14.
You're passing the boundingBox by value, not by reference. This means the makeBoundingBox function is operating on a local copy and changes do not propagate back to the original object.
Change your function definition as follows:
void makeBoundingBox(boundingBox& bound, float t, float b, float l, float r)
You're passing the struct to the function by VALUE, you need to pass by REFERENCE so:
void makeBoundingBox(boundingBox &bound, float t, float b, float l, float r){
bound.top =t;
bound.bottom =b;
bound.left=l;
bound.right=r;
}
Notice the & to pass by reference.
In your function call, do the same & in front of the variable name.

C++ Fill a vector with another vector

I have two vectors, and I would like to fill the first one with the second. The vectors are declared like this:
vector<Vec3> firstVector;
Where Vec3 is a struct with float x, y, z.
I have tried liked this with assign:
secondVector.assign(firstVector.begin(), firstVector.end());
But it stops and complains, that there is problem with the end().
I have also tried pushback, but of course it's not working.
As I read before I should do it with assign, but I don't know how to solve it properly.
EDIT:
The error message with insert and assign are the same:
this 0x00000000 ... std::vector > * const
[size] CXX0030: Error: expression cannot be evaluated
[capacity] CXX0030: Error: expression cannot be evaluated
And it points to Visual Studio's vector file to iterator end to the return. With insert it points to iterator begin.
THE CODE:
The first Vector is also part of a struct:
struct o3DModel
{
vector<Vec3> v_Vertices;
};
struct Vec3 {
public:
Vec3() {}
Vec3(float X, float Y, float Z)
{
x = X;
y = Y;
z = Z;
}
float x, y, z;
};
I declare the "o3DModel" struct above in my app class like this and send it to my loader class:
o3DModel *tfTable;
void TheApp::Init()
{
objLoader->ImportOBJ(tfTable, "testcube.obj");
}
The objLoader class, where I successfully fill my "v_Vertices" vector, where "oModel" is the sent "tfTable":
bool OBJLoader::ImportOBJ(o3DModel *oModel, char *strFileName)
{
FillObjData(oModel);
...
return true;
}
void OBJLoader::FillObjData(o3DModel *oModel)
{
oModel->v_Vertices.insert(oModel->v_Vertices.begin(), v_Vertices.begin(), v_Vertices.end());
// This here with insert
outFile2 << oModel->v_Vertices[0].x << "\n";
}
Hope this helps.
If you want secondVector to take on all of the values of firstVector and no others,
secondVector = firstVector;
If you want each of the elements of firstVector to be added to the end secondVector:
secondVector.insert(secondVector.end(),
firstvector.begin(), firstVector.end());
If you want each of the elements of firstVector to be added to the beginning of secondVector:
secondVector.insert(secondVector.begin(),
firstVector.begin(), firstVector.end());
Or if you don't want to do it in the ctor use
secondVector = firstVector
This should work:
vector<Vec3> secondVector(firstVector.begin(), firstVector.end());
That's the case when you're interested in using the vector constructor.
You second vector needs to be declared as a vector of vectors of Vec3 strucs.
vector<vector<Vec3>> secondVector;
secondVector.push_back(firstVector);
Okay, I have solved it, but with a little roundabout. In FillObjData I have created a new Vec3, created an if, gived the first vector x, y, z coordinate to the new Vec3, and pushed the Vec3 into the vector. And when I declared my struct I have declared it real not as a pointer. Now it works perfectly.