Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 2 of 2

Thread: Matrix class

  1. #1
    Junior Member Newbie
    Join Date
    May 2014
    Posts
    2

    Matrix class & Matrix Stack class

    Hi folks,

    I'm trying to write a matrix class for use in a matrix stack that I will apply to vertices before sending them to a VBO. But I'm a little confused by row-major versus column-major order. This is my matrix class so far, but it doesn't seem to be applying any translations to the vertices I send it.

    Please help me find my bug (it's probably a silly mistake on my part), and any friendly advice about implementing a matrix stack for GL is much appreciated. Thanks new friends!

    Code :
    class Matrix
    {
    public:
    	//---Construction
    	Matrix()
    	{
    		identify();
    	}
    	Matrix(float m[4][4])
    	{
    		for (int y = 0; y < 4; y++)
    			for (int x = 0; x < 4; x++)
    				matrix[y][x] = m[y][x];
    	}
     
    	//---Arithmetic
    	const Matrix operator * (const Matrix& m) const
    	{
    		float result[4][4];
     
    		for (int y = 0; y < 4; y++)
    			for (int x = 0; x < 4; x++)
    			{
    				result[y][x] = 0.f;
    				for (int z = 0; z < 4; z++)
    					result[y][x] += matrix[y][z]*m.matrix[z][x];
    			}
     
    		return Matrix(result);
    	}
     
    	//---Transformations
    	Matrix& identify()
    	{
    		memset(matrix, 0.f, 4*4*sizeof(float));
    		for (int i = 0; i < 4; i++)
    			matrix[i][i] = 1.f;
    		return *this;
    	}
    	Matrix& translate(float tx, float ty, float tz)
    	{
    		Matrix other;
     
    		other.matrix[0][4] = tx;
    		other.matrix[1][4] = ty;
    		other.matrix[2][4] = tz;
     
    		*this = (*this)*other;
     
    		return *this;
    	}
     
    	//---Apply to vector
    	Matrix& transform(float vector[4])
    	{
    		float result[4];
     
    		//Calculate result
    		for (int y = 0; y < 4; y++)
    		{
    			result[y] = 0.f;
    			for (int z = 0; z < 4; z++)
    				result[y] += matrix[y][z]*vector[z];
    		}
     
    		//Copy result into vector
    		for (int y = 0; y < 4; y++)
    			vector[y] = result[y];
     
    		return *this;
    	}
     
    private:
    	float matrix[4][4];
    };


    The test I'm running is this:
    Code :
    float vector[4] = {0.f, 0.f, 0.f, 1.f};
    matrix.identify().translate(0.f, 1.f, 0.f).transform(vector);
    printf("%f, %f, %f, %f\n", vector[0], vector[1], vector[2], vector[3]);
    Last edited by lcdavis13; 05-06-2014 at 02:05 PM.

  2. #2
    Junior Member Newbie
    Join Date
    May 2014
    Posts
    2
    Fixed it! It was a silly error like I thought (in my translate function I was accessing index 4 in a 4-element array, which is of course an overflow; meant to access 3).

    I also implemented the matrix stack class. It was easier than I expected--I thought I was going to have to do some crazy stuff to make the operations apply in reverse order the way they do in OpenGL, but apparently it already does this...I guess because I'm using row-major order? I don't really understand, but I'm happy with it.

    Here is the functional code in case anyone else needed it too.

    Code :
    class Matrix
    {
    public:
    	//---Construction
    	Matrix()
    	{
    		identify();
    	}
    	Matrix(float m[4][4])
    	{
    		for (int y = 0; y < 4; y++)
    			for (int x = 0; x < 4; x++)
    				matrix[y][x] = m[y][x];
    	}
     
    	//---Arithmetic
    	const Matrix operator * (const Matrix& m) const
    	{
    		float result[4][4];
     
    		for (int y = 0; y < 4; y++)
    			for (int x = 0; x < 4; x++)
    			{
    				result[y][x] = 0.f;
    				for (int z = 0; z < 4; z++)
    					result[y][x] += matrix[y][z]*m.matrix[z][x];
    			}
     
    		return Matrix(result);
    	}
     
    	//---Transformations
    	Matrix& identify()
    	{
    		memset(matrix, 0.f, 4*4*sizeof(float));
    		for (int i = 0; i < 4; i++)
    			matrix[i][i] = 1.f;
    		return *this;
    	}
    	Matrix& translate(float tx, float ty, float tz)
    	{
    		Matrix other;
     
    		other.matrix[0][3] = tx;
    		other.matrix[1][3] = ty;
    		other.matrix[2][3] = tz;
     
    		*this = (*this)*other;
     
    		return *this;
    	}
    	Matrix& scale(float sx, float sy, float sz)
    	{
    		Matrix other;
     
    		other.matrix[0][0] = sx;
    		other.matrix[1][1] = sy;
    		other.matrix[2][2] = sz;
     
    		*this = (*this)*other;
     
    		return *this;
    	}
    	Matrix& rotate(float theta, float rx, float ry, float rz)
    	{
    		float other[4][4];
    		float sint = sin(theta), cost = cos(theta);
     
    		other[0][0] = rx*rx*(1 - cost) + cost;
    		other[1][0] = rx*ry*(1 - cost) + rz*sint;
    		other[2][0] = rx*rz*(1 - cost) - ry*sint;
     
    		other[0][1] = ry*rx*(1 - cost) - rz*sint;
    		other[1][1] = ry*ry*(1 - cost) + cost;
    		other[2][1] = ry*rz*(1 - cost) + rx*sint;
     
    		other[0][2] = rz*rx*(1 - cost) + ry*sint;
    		other[1][2] = rz*ry*(1 - cost) - rx*sint;
    		other[2][2] = rz*rz*(1 - cost) + cost;
     
    		other[0][3] = 0.f;
    		other[1][3] = 0.f;
    		other[2][3] = 0.f;
    		other[3][0] = 0.f;
    		other[3][1] = 0.f;
    		other[3][2] = 0.f;
    		other[3][3] = 1.f;
     
    		*this = (*this)*Matrix(other);
     
    		return *this;
    	}
     
    	//---Apply to vector
    	Matrix& transform(float vector[4])
    	{
    		float result[4];
     
    		//Calculate result
    		for (int y = 0; y < 4; y++)
    		{
    			result[y] = 0.f;
    			for (int z = 0; z < 4; z++)
    				result[y] += matrix[y][z]*vector[z];
    		}
     
    		//Copy result into vector
    		for (int y = 0; y < 4; y++)
    			vector[y] = result[y];
     
    		return *this;
    	}
     
    private:
    	float matrix[4][4];
    };
     
     
     
    class MatrixStack
    {
    public:
    	//---Construction & destruction
    	MatrixStack(int size = 100)
    	{
    		stack_size = std::max(size, 0);
    		stack_top = 0;
    		matrix = new Matrix[stack_size];
    		matrix[0].identify();
    	}
    	MatrixStack(int size, const Matrix& m)
    	{
    		stack_size = size;
    		stack_top = 0;
    		matrix = new Matrix[stack_size];
    		matrix[0] = m;
    	}
    	MatrixStack(const MatrixStack& ms)
    	{
    		stack_size = ms.stack_size;
    		stack_top = ms.stack_top;
    		matrix = new Matrix[stack_size];
    		for (int m = 0; m < stack_top; m++)
    			matrix[m] = ms.matrix[m];
    	}
    	~MatrixStack()
    	{
    		delete[] matrix;
    	}
     
    	//---Copying
    	MatrixStack& operator = (const MatrixStack& ms)
    	{
    		delete[] matrix;
    		stack_size = ms.stack_size;
    		stack_top = ms.stack_top;
    		matrix = new Matrix[stack_size];
    		for (int m = 0; m < stack_top; m++)
    			matrix[m] = ms.matrix[m];
    		return *this;
    	}
    	MatrixStack& operator = (const Matrix& m)
    	{
    		matrix[stack_top] = m;
    		return *this;
    	}
     
    	//---Resizing
    	MatrixStack& resize(int size)
    	{
    		delete[] matrix;
    		stack_size = std::max(size, 0);
    		stack_top = 0;
    		matrix = new Matrix[stack_size];
    		matrix[0].identify();
    		return *this;
    	}
     
    	//---Pushing, popping, and clearing stack
    	MatrixStack& push()
    	{
    		if (stack_top < stack_size - 1) 
    		{
    			stack_top++;
    			matrix[stack_top] = matrix[stack_top - 1];
    		}
    		else fatal_error("\nERROR: matrix stack capacity was exceeded\n");
    		return *this;
    	}
    	MatrixStack& pop()
    	{
    		if (stack_top > 0) stack_top--;
    		else fatal_error("\nERROR: popped below bottom of matrix stack\n");
    		return *this;
    	}
    	MatrixStack& clear()
    	{
    		stack_top = 0;
    		matrix[0].identify();
    		return *this;
    	}
    	int check_headway() const
    	{
    		return stack_size - stack_top - 1;
    	}
     
    	//---Transformations
    	MatrixStack& identify()
    	{
    		matrix[stack_top].identify();
    		return *this;
    	}
    	MatrixStack& translate(float tx, float ty, float tz)
    	{
    		matrix[stack_top].translate(tx, ty, tz);
    		return *this;
    	}
    	MatrixStack& scale(float sx, float sy, float sz)
    	{
    		matrix[stack_top].scale(sx, sy, sz);
    		return *this;
    	}
    	MatrixStack& rotate(float theta, float rx, float ry, float rz)
    	{
    		matrix[stack_top].rotate(theta, rx, ry, rz);
    		return *this;
    	}
     
    	//---Apply to vector
    	MatrixStack& transform(float vector[4])
    	{
    		matrix[stack_top].transform(vector);
    		return *this;
    	}
     
    private:
    	Matrix* matrix;
    	int stack_top, stack_size;
    };

    But note that, in the push and pop functions, I make a call to 'fatal_error' which I have not included. You will need to replace this with your own error handling functions.

    Suggestions and constructive criticism are welcome!!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •