Search code examples
c++openglmatrixdirectxunions

Accessing Class / Union Data in "Column-Major" Format C++


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.


Solution

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