Page 1 of 3 123 LastLast
Results 1 to 10 of 23

Thread: Using a class instead of array

  1. #1
    Member Contributor
    Join Date
    Jul 2003
    Posts
    92

    Using a class instead of array

    Hi,

    I am writting an utility library similar to D3DX for my new OpenGL engine.

    I have noticed that a class can be given to OpenGL's functions like glLightfv. The first member of the class will correspond to the elements of the array. It works, but is it a good idea ? Will it not be slower ?

    Here is an example:

    My class:
    Code :
    class GLGXVECTOR3{
    public:
    	union{
    		float x;
    		float u;
    	};
    	union{
    		float y;
    		float v;
    	};
    	union{
    		float z;
    		float r;
    	};
     
    	GLGXVECTOR3();
    	GLGXVECTOR3( float x , float y , float z );
    	~GLGXVECTOR3(){};
     
    	GLGXVECTOR3 operator+ (GLGXVECTOR3 &B);
    	GLGXVECTOR3 operator- (GLGXVECTOR3 &B);
    	float	  operator* (GLGXVECTOR3 &B);
    	GLGXVECTOR3 operator* (float factor);
    	GLGXVECTOR3 operator/ (float factor);
    };
    The way i use it:

    Code :
    GLGXVECTOR3 Loc(0.0f,100.0f,0.0f);
    glLightfv(GL_LIGHT0, GL_POSITION,(float*)&Loc);
    Thanks.

  2. #2
    Senior Member OpenGL Pro
    Join Date
    May 2000
    Location
    Naarn, Austria
    Posts
    1,102

    Re: Using a class instead of array

    It will not be slower, but it's dangerous. You never know for sure how your compiler will pack class data into the class. This could go as far as breaking your code when you update to the next compiler version.

    Better use something like that:
    Code :
    class GLGXVECTOR4 {
    private:
        float vec[4];
    public:
        ...
        float x() { return vec[0]; }
        ...
        operator float*() { return vec; }
        ...
    }
    Then you can use it:
    Code :
    GLGLXVECTOR4 Loc;
    glLightfv(GL_LIGHT0, GL_POSITION, Loc);
    This does not assume anything about the compiler dependant class layout, the speed is still the same, and as an additional bonus you don't need an explicit typecast

  3. #3
    Senior Member OpenGL Guru
    Join Date
    Mar 2001
    Posts
    3,574

    Re: Using a class instead of array

    The C++ ANSI/ISO specification does not guarantee that this will work, though it almost always will.

    Unless you suddenly decide that GLGXVECTOR3 (horrible name, btw) needs to have virtual functions.

    In general, you should not rely on this. Indeed, it's better for you to have a specialized "glxLightPosition" function that takes this class natively. It could be inlined to the standard "glLightfv" class if you feel performance could be an issue.

  4. #4
    Member Contributor
    Join Date
    Jul 2003
    Posts
    92

    Re: Using a class instead of array

    Korval, i don't want to write specialized "glxLightPosition" function because i want to be able to use my vector classes with any openGL function or non openGL function. (and it would be like rewritting a new 3D API, a thing i don't want). And even with "inline", i would have to do some conversion in the function which will not be better for performances.

    i have used the overmind's suggestion to write this:

    Code :
    class GLGXVECTOR4{
    private:
    	float vec[4];
    public:
    	union{
    		float& x;
    		float& u;
    	};
    	union{
    		float& y;
    		float& v;
    	};
    	union{
    		float& z;
    		float& r;
    	};
    	union{
    		float& w;
    		float& q;
    	};
     
    	GLGXVECTOR4():x(vec[0]),y(vec[1]),z(vec[2]),w(vec[3]),u(vec[0]),v(vec[1]),r(vec[2]),q(vec[3])
    	{
    		x=0.0f;y=0.0f;z=0.0f;w=0.0f;
    	};
     
    	GLGXVECTOR4( float x , float y , float z, float w ):x(vec[0]),y(vec[1]),z(vec[2]),w(vec[3]),u(vec[0]),v(vec[1]),r(vec[2]),q(vec[3])
    	{ 
    		this->x = x; this->y = y; this->z = z;this->w = w;
    	}
     
    	operator float*() 
    	{ 
    		return vec; 
    	}
     
    	GLGXVECTOR4 operator= (GLGXVECTOR4 &B)
    	{
    		if (this == &B) return B;
    		this->x = B.x;
    		this->y = B.y;
    		this->z = B.z;
    		this->w = B.w;
    		return B;
    	}
    	~GLGXVECTOR4(){};
     
    	GLGXVECTOR4 operator+ (GLGXVECTOR4 &B);
    	GLGXVECTOR4 operator- (GLGXVECTOR4 &B);
    	float	  operator* (GLGXVECTOR4 &B);
    	GLGXVECTOR4 operator* (float factor);
    	GLGXVECTOR4 operator/ (float factor);
    };
    It allow me to have direct access to the xyz variables ( Loc.x, Loc.y ,...), i can do sometings like v3 = v1 + v2 (where v1,v2,v3 are GLGXVECTOR4), and i can give the vector to the opengl function like glLightfv.

    It seems to work.

    Do you have other suggestions ? Is there something wrong in this class ?

  5. #5
    Senior Member Regular Contributor
    Join Date
    May 2003
    Location
    New York
    Posts
    194

    Re: Using a class instead of array

    There is a safe way to do what you originally wanted, and that's to add a cast-to-float-pointer converter. Doing this always finds the right memory offset for your members and avoids the problems Korval mentioned.

    Basically, just add to your class:

    Code :
    inline operator float*()             { return &x; }
    inline operator const float*() const { return (const float*)&x; }
    With that, you can call glVertex3fv(object) without even using the (float*) cast. Object is in this case not a pointer, but if it was, you would just dereference it.

    Now you're not dependent on where in your class the XYZ floats wind up, but you could potentially be burned if XYZ are not contiguous (which only really happens in unusual alignment schemes, say of multiple sub-structures). The safest way to prevent problems is to declare these members as a union of two or more structures, see below.

    This also works for non-float types just as well. One thing to watch, though, is that you should make a habit of putting the 'explicit' keyword on constructors that might accidentally invoke this auto-conversion inappropriately.

    I'll give you my Vec3 template (minus the math functions) in case this helps:

    Code :
    template <class T> struct Vec3
    {
    	typedef T	ElemType;
    	static uint ElemGLID;
    	enum { ElemCount = 3 };
     
    	Vec3<T>() { x = y = z = 0; }
            Vec3<T>(T x, T y, T z) : x(x), y(y), z(z) { }
    	Vec3<T>(const Vec3<T>&amp; u) : x(u.x), y(u.y), z(u.z) { }
     
    	explicit Vec3<T>(const T  val) : x(val), y(val), z(val) { }
            explicit Vec3<T>(const T* xyz) : x(xyz[0]), y(xyz[1]), z(xyz[2]) { }
    	explicit Vec3<T>(const Vec2<T>&amp; u) : x(u.x), y(u.y), z((T)1) { }
    	explicit Vec3<T>(const Vec4<T>&amp;);
     
    	inline void Set(T _x, T _y, T _z) { x = _x; y = _y; z = _z; }
    	inline Vec3<T>&amp; operator=(T val)  { Set(val,val,val); return *this; }
    	inline Vec3<T>&amp; operator=(const Vec3<T>&amp; v) { Set(v.x,v.y,v.z); return *this; }
    	inline Vec3<T>&amp; operator=(const Vec4<T>&amp; v);
     
        Bool operator==(const Vec3<T> & u) const
        {
            return (u.x == x &amp;&amp; u.y == y &amp;&amp; u.z == z) ? true : false;
        }
     
    	typedef T* pointer;
     
    	operator pointer()			   { return &amp;x; }
    	operator const pointer() const { return (const pointer)&amp;x; }
     
        union {
            struct {
                T x,y,z;
            };
            struct {
                T s,t,u;
            };
            struct {
                T r,g,b;
            };
            T elem[3];     // array access
        };
    };

  6. #6
    Member Contributor
    Join Date
    Jul 2003
    Posts
    92

    Re: Using a class instead of array

    Thanks. I will see what i can do with all that.

  7. #7
    Senior Member OpenGL Pro
    Join Date
    May 2000
    Location
    Naarn, Austria
    Posts
    1,102

    Re: Using a class instead of array

    Basically, just add to your class: ...
    That's equally dangerous. Ok, the offset to the first element is guaranteed to be correct, but the elements inside the struct are not guaranteed to be tightly packed. You're still making assumptions that may be correct or not, depending on the compiler, architecture, operating system and so on...

  8. #8
    Senior Member OpenGL Pro k_szczech's Avatar
    Join Date
    Feb 2006
    Location
    Poland
    Posts
    1,107

    Re: Using a class instead of array

    I've just found an interesting article with this example:
    Code :
    struct A
    {
      char c;
      int i;
    }
    struct B
    {
      char c;
    public:
      int i;
    };
    They say that: "a compiler could move B::i before B::c, but A::c must precede A::i."

    Full article here:
    http://www.open-std.org/JTC1/sc22/wg...wg_active.html

    Another thing is that people rely on structure member order pretty much and I guess no one wants to make a compiler that will not be used by anyone. So this relation between member order in structure and real order in memory will be somewhat enforced by programmers upon compilers.

    Just look at Windows API and DirectX - they rely on member order in structures. A great example would be vertex structure in Direct3D.

  9. #9
    Member Contributor
    Join Date
    Jul 2003
    Posts
    92

    Re: Using a class instead of array

    I have looked at the D3DX header, and they seems to use a basic x,y,z declaration in the structure, so they probably just return the adresse of x in "operator float*()". They also use an union of "float _11,_12,..." and "float array[4][4]" for D3DXMATRIX. The memory is probably allocated in the same order.

    But The DirectX SDK is written to be used on Windows and with Visual C++ only.

    I want to create a library which could work with any operating system and compiler ( Windows, Haiku, Linux).

    The use of references in initialization lists seems to be 100% safe but maybe not 100% optimized.

  10. #10
    Senior Member OpenGL Pro k_szczech's Avatar
    Join Date
    Feb 2006
    Location
    Poland
    Posts
    1,107

    Re: Using a class instead of array

    Ok, let's make it official (I knew I read it somewhere ):
    Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object.
    This is from ISO/IEC 14882:1998.
    Here is the link:
    http://www.kuzbass.ru:8086/docs/isocpp/class.html

    So if your compiler does not place structure/class member in proper order then report C++ standard violation to compiler developer

Page 1 of 3 123 LastLast

Similar Threads

  1. making Vertex array object in class constructor
    By Ben Beazley in forum OpenGL: Basic Coding
    Replies: 3
    Last Post: 01-04-2017, 10:02 AM
  2. Replies: 0
    Last Post: 04-24-2014, 09:28 AM
  3. Generate Indices array from Vertex array
    By VirtualMan in forum OpenGL: Basic Coding
    Replies: 1
    Last Post: 10-28-2013, 02:51 AM
  4. Replies: 2
    Last Post: 07-10-2013, 01:51 AM
  5. upload struct array to uniform block array?
    By Schnulla in forum OpenGL: Basic Coding
    Replies: 5
    Last Post: 07-27-2010, 03:32 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Proudly hosted by Digital Ocean