Saturday 7 January 2012

2 Dimensional Matrix Rotation - Simple

Now, if curiosity killed the cat, but the cat has nine lives, that makes the cat eight times the wiser before it finally does get killed. Sounds like a fair trade to me, just so long as the curiosity is well spent. Doing all that OpenGL stuff that was in my previous posts is all well and dandy, but would it not be nice to at least have a superficial idea of what (sort of) goes on "under the hood" in order to supplement one's global understanding of 3D computer graphics? The following two or three posts, therefore, will concentrate on the heart of the matter where OpenGL rotation transformations are concerned...

THE MATRIX

There are tons of pages that "blah - blah" on about what matrices are, how they are arranged and multiplied, etcetera, but no simple example of their implementation. In this post, I am going to attack the simplest form of them, the 2D matrix, to enable the rotation of one point around the Z axis. It will probably be obvious that the matrix itself is the least of the worries. It is easy, for 2D stuff. Here's what happens, really.

Consider first the origin. That is, point (0, 0) on the X and Y axes. I have a point that is located at (150.0, -200.0) from that origin, which I want to rotate around the Z axis by 0.5 of a degree, every 1/60th of a second. The 2D matrix takes on this form...

- X - Y
X : cos(angle) : -sin(angle)
Y : sin(angle) : cos(angle)

To which the data of the old positions can be plugged in to achieve a rotation like this...

NEW_X_POSITION = (cos(angle) * old_x_position) + (-sin(angle) * old_y_position)
NEW_Y_POSITION = (sin(angle) * old_x_position) + (cos(angle) * old_y_position)

Do the math itself, on a piece of paper with a calculator, and the understanding will dawn. It is so simple, at this stage, that no further discussion is required. Here's some working source code, using Allegro 5.1.

#define _USE_MATH_DEFINES
#include "allegro5/allegro.h"
#include "allegro5/allegro_primitives.h"
#include "math.h"

/*
`pkg-config --libs allegro-5.1 allegro_primitives-5.1`
*/

//*******************
float deg_to_rad(float deg)
{
return deg * ((float)M_PI / 180.0f);
}


void matrix_2d_handler(float _angle, float &_x_pos, float &_y_pos)
{
float Matrix_2D[2][2];
float New_X, New_Y;

Matrix_2D[0][0] = cosf(_angle); Matrix_2D[0][1] = -sinf(_angle);
Matrix_2D[1][0] = sinf(_angle); Matrix_2D[1][1] = cosf(_angle);

New_X = (Matrix_2D[0][0] * _x_pos) + (Matrix_2D[0][1] * _y_pos);
New_Y = (Matrix_2D[1][0] * _x_pos) + (Matrix_2D[1][1] * _y_pos);

_x_pos = New_X;
_y_pos = New_Y;
}



//*******************
int main(int argc, char *argv[])
{
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer = NULL;

int SCREEN_X = 800;
int SCREEN_Y = 600;
int SC_X_CENT = SCREEN_X / 2;
int SC_Y_CENT = SCREEN_Y / 2;

float FPS = 60.0f;
float X_pos = 150.0f;
float Y_pos = -200.0f;
float angle = 0.5f;

bool draw = false;
bool loop = true;

al_init();
al_init_primitives_addon();


al_set_new_display_option(ALLEGRO_VSYNC, 1, ALLEGRO_SUGGEST);

display = al_create_display(SCREEN_X, SCREEN_Y);
event_queue = al_create_event_queue();
timer = al_create_timer(1.0f / FPS);

al_register_event_source(event_queue, al_get_display_event_source(display));
al_register_event_source(event_queue, al_get_timer_event_source(timer));

al_start_timer(timer);

while(loop)
{
ALLEGRO_EVENT event;
al_wait_for_event(event_queue, &event);

switch(event.type)
{
case ALLEGRO_EVENT_DISPLAY_CLOSE:
loop = false;
break;

case ALLEGRO_EVENT_TIMER:
draw = true;
break;

default:
break;
}

if(draw == true && al_event_queue_is_empty(event_queue))
{
draw = false;
al_clear_to_color(al_map_rgb(0,0,0));
matrix_2d_handler(deg_to_rad(angle), X_pos, Y_pos);
al_draw_circle(float(X_pos + SC_X_CENT), float(Y_pos + SC_Y_CENT), 10.0f, al_map_rgb(0,255,0), 0);
al_flip_display();
}
}

al_stop_timer(timer);
al_flush_event_queue(event_queue);
al_destroy_timer(timer);
al_destroy_event_queue(event_queue);
al_destroy_display(display);

return 0;
}

1 comment:

  1. thanks for these tutorials they are very useful :D

    ReplyDelete