Recently I've learned about the Union storage specifier for data types - it's particularly for OpenGL / DirectX transformation matrix use, since I don't want to keep using the deprecated gluLookAt, gluOrtho, and various MatrixStack functions of the fixed-function pipeline. It's been fantastic, and I recently had lots of fun creating the 4x4 basic Transformation Matrix Class whose internal data is union-packed to allow different ways of accessing the data within the Matrix. The problem is when I want to create a way of aggregating / accessing the data by its columns, without having to make some weird
float* Column(int index);
function. I know C++ stores its data in row-major form, so how do I provide column access? There's ??? in my below matrix data declaration as to where I'm lost.
//#define ROW_EFFIN_MAJOR
union {
struct {
#ifdef ROW_EFFIN_MAJOR
// Eat one of several nasty things, OpenGL :|
float m11, m12, m13, m14,
m21, m22, m23, m24,
m31, m32, m33, m34,
m41, m42, m43, m44;
#else
float m11, m21, m31, m41,
m12, m22, m32, m42,
m13, m23, m33, m43,
m14, m24, m34, m44;
#endif
};
float m[16];
// Use at your own risk: m[1] COLUMNMAJOR is not the same as m[1] ROWMAJOR
// Rows!
union MatrixRow {
struct {
float r1, r2, r3, r4;
};
float r[4];
} row[4];
// .... Columns...?
union MatrixColumn {
// TODO:
// Set Union
// Column Access ?
// ???
// Profit
} col[???];
};
Any advice, tips, tricks, or even help would be nice. Ideally, I'd like to access the colums by col[0].c1, or just col[0].c (c being a float[4] of the whole column). However, if this ideal is to be slain for the greater justice of column access (though, leaning towards not-a-function, because I can do it with a special struct and a function. It's just less convenient and a little slower than accessing the data directly via a data member).
I've spent a fair amount of time trying to bash this with google-fu, but I can't figure out how to make a non-contiguous union.
As pointed out by Marcelo, C++ is neither row-major nor column-major. It is exactly and only what you put into it. If you call the first four values in a float
array a "column", it's fine with that. If you call it a "row", it's fine with that too.
In general, you should not switch back and forth between conventions. Don't develop structs that can do "both"; just pick a side and stick with it. If you make your matrices row-major, then they're row-major. When you upload them to OpenGL, you can either manually transpose them or just pass GL_TRUE
for the "transpose" parameter of glUniformMatrix
.
More details are available.