# Matrix Transformations

###### Last Updated 8/09/12

Up until now, we've done texture rotation and scaling in hackish ways. In this tutorial we'll combine matrix tranformations to transform a textured quad without changing the original geometry.From LTexture.cpp

void LTexture::render( GLfloat x, GLfloat y, LFRect* clip )
{
//If the texture exists
if( mTextureID != 0 )
{
//Texture coordinates
GLfloat texTop = 0.f;
GLfloat texBottom = (GLfloat)mImageHeight / (GLfloat)mTextureHeight;
GLfloat texLeft = 0.f;
GLfloat texRight = (GLfloat)mImageWidth / (GLfloat)mTextureWidth;
//Vertex coordinates
GLfloat quadWidth = mImageWidth;
GLfloat quadHeight = mImageHeight;
//Handle clipping
if( clip != NULL )
{
//Texture coordinates
texLeft = clip->x / mTextureWidth;
texRight = ( clip->x + clip->w ) / mTextureWidth;
texTop = clip->y / mTextureHeight;
texBottom = ( clip->y + clip->h ) / mTextureHeight;
//Vertex coordinates
quadWidth = clip->w;
quadHeight = clip->h;
}
//Move to rendering point
glTranslatef( x, y, 0.f );
//Set texture ID
glBindTexture( GL_TEXTURE_2D, mTextureID );
//Render textured quad
glBegin( GL_QUADS );
glTexCoord2f( texLeft, texTop ); glVertex2f( 0.f, 0.f );
glTexCoord2f( texRight, texTop ); glVertex2f( quadWidth, 0.f );
glTexCoord2f( texRight, texBottom ); glVertex2f( quadWidth, quadHeight );
glTexCoord2f( texLeft, texBottom ); glVertex2f( 0.f, quadHeight );
glEnd();
}
}

The LTexture render() function has returned to it's pre stretching/rotating state with the origin of the textured quad at the top left. What different this time is that there's no
call to glLoadIdentity() in this version of render(). If we did that, any transformations made before this call would be pointless.

In modern OpenGL applications, vertex data is set in chunks (known as vertex buffers) to the GPU. It's inefficient to send different vertex data over and over again when we're essentially rendering the same quad that's just transformed in different ways. So it's important to know how to get the results you need without sending redundant vertex data.

In modern OpenGL applications, vertex data is set in chunks (known as vertex buffers) to the GPU. It's inefficient to send different vertex data over and over again when we're essentially rendering the same quad that's just transformed in different ways. So it's important to know how to get the results you need without sending redundant vertex data.

From LUtil.cpp

//OpenGL texture
LTexture gRotatingTexture;
//Rotation Angle
GLfloat gAngle = 0.f;
//Transformation state
int gTransformationCombo = 0;

At the top of LUtil.cpp we have a couple global variables. We have our rotating texture, the angle at which it will rotate, and lastly the transformation state.

In this tutorial, we'll be using different sets of matrix transformations. "gTransformationCombo" is just a variable to indicate which one we're using right now.

In this tutorial, we'll be using different sets of matrix transformations. "gTransformationCombo" is just a variable to indicate which one we're using right now.

From LUtil.cpp

bool loadMedia()
{
//Load texture
if( !gRotatingTexture.loadTextureFromFile( "13_matrix_transformations/texture.png" ) )
{
printf( "Unable to load OpenGL texture!\n" );
return false;
}
return true;
}
void update()
{
//Rotate
gAngle += 360.f / SCREEN_FPS;
//Cap angle
if( gAngle > 360.f )
{
gAngle -= 360.f;
}
}

As with last time, loadMedia() loads are texture and update() updates our angle of rotation.

From LUtil.cpp

void render()
{
//Clear color buffer
glClear( GL_COLOR_BUFFER_BIT );
//Reset transformation
glLoadIdentity();
//Render current scene transformation
switch( gTransformationCombo )
{

At the top of our render() we clear the color buffer then load the identity matrix. Remember that the LTexture render() function no longer calls glLoadIdentity(), so now we have to
call it before we render our textured quad.

Then, depending on which transformation combination is selected, we apply some tranformations to the modelview matrix.

Then, depending on which transformation combination is selected, we apply some tranformations to the modelview matrix.

From LUtil.cpp

case 0:
glTranslatef( SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 0.f );
glRotatef( gAngle, 0.f, 0.f, 1.f );
glScalef( 2.f, 2.f, 0.f );
glTranslatef( gRotatingTexture.imageWidth() / -2.f, gRotatingTexture.imageHeight() / -2.f, 0.f );
break;

Here's the main transformation of the demo: making the double sized textured quad spin around it's center at the center of the screen. Let's step through this transformation to
see how it works. First here's our untransformed textured quad:

First thing we do is translate to the center of the screen:

Since the origin the quad is at the top left, the top left corner is touching the center of the screen.

Then we rotate the quad:

Remember: glRotate() rotates around the current point of rotation.

Since we want our quad to be double in size, we scale it using glScale():

The arguments in this call for glScale() say that we want to double it in size along the x and y axis.

We want the quad to rotate around its center, so we translate back half the span of the quad:

It's important to know when you apply a transformation, it transforms the transformations after it. Since we called glRotate before we translated half the span of the quad, the translation was also rotated. Since we called glScale to stretch the quad, the translation of half the span of the quad was also scaled.

A side note about order of operations: notice that the negation sign is by the float in gRotatingTexture.imageWidth() / -2.f. The function imageWidth() returns an unsigned int, which with a negation sign produces undesired results.

First thing we do is translate to the center of the screen:

Since the origin the quad is at the top left, the top left corner is touching the center of the screen.

Then we rotate the quad:

Remember: glRotate() rotates around the current point of rotation.

Since we want our quad to be double in size, we scale it using glScale():

The arguments in this call for glScale() say that we want to double it in size along the x and y axis.

We want the quad to rotate around its center, so we translate back half the span of the quad:

It's important to know when you apply a transformation, it transforms the transformations after it. Since we called glRotate before we translated half the span of the quad, the translation was also rotated. Since we called glScale to stretch the quad, the translation of half the span of the quad was also scaled.

A side note about order of operations: notice that the negation sign is by the float in gRotatingTexture.imageWidth() / -2.f. The function imageWidth() returns an unsigned int, which with a negation sign produces undesired results.

From LUtil.cpp

case 1:
glTranslatef( SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 0.f );
glRotatef( gAngle, 0.f, 0.f, 1.f );
glTranslatef( gRotatingTexture.imageWidth() / -2.f, gRotatingTexture.imageHeight() / -2.f, 0.f );
glScalef( 2.f, 2.f, 0.f );
break;

In this combination, we call glScale() last. What this does is when we the translate of half the span of the quad, the translation isn't scaled so the quad rotation is off.

From LUtil.cpp

case 2:
glScalef( 2.f, 2.f, 0.f );
glTranslatef( SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 0.f );
glRotatef( gAngle, 0.f, 0.f, 1.f );
glTranslatef( gRotatingTexture.imageWidth() / -2.f, gRotatingTexture.imageHeight() / -2.f, 0.f );
break;

In this combination we call glScale() first, which causes the quad to spin around its center but since the initial translation to the center of the screen is also scaled, the quad
spins around its center at the bottom right corner of the screen.

From LUtil.cpp

case 3:
glTranslatef( SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 0.f );
glRotatef( gAngle, 0.f, 0.f, 1.f );
glScalef( 2.f, 2.f, 0.f );
break;

In this combination, we don't translate of half the span of the quad which causes the quad to spin around its top left corner.

From LUtil.cpp

case 4:
glRotatef( gAngle, 0.f, 0.f, 1.f );
glTranslatef( SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 0.f );
glScalef( 2.f, 2.f, 0.f );
glTranslatef( gRotatingTexture.imageWidth() / -2.f, gRotatingTexture.imageHeight() / -2.f, 0.f );
break;
}

In this combination we rotate first, which cause the quad to rotate around the top left corner of the screen.

From LUtil.cpp

//Render texture
gRotatingTexture.render( 0.f, 0.f );
//Update screen
glutSwapBuffers();
}

Finally after applying our transformations we render our transformed quad.

From LUtil.cpp

void handleKeys( unsigned char key, int x, int y )
{
//If q is pressed
if( key == 'q' )
{
//Reset rotation
gAngle = 0.f;
//Cycle through combinations
gTransformationCombo++;
if( gTransformationCombo > 4 )
{
gTransformationCombo = 0;
}
}
}

In our key handler, when the user presses q we reset the angle of rotation and cycle through the transformation combinations.