## Rotation w/ Rectangular Pixels (2D & VAO)

Hi everyone,

I've been trying to learn some OpenGL this past couple of weeks. It's for my own interest, and just a 2D program I would like to create. I should also add that my maths is not great.

I want to display lots of images on the screen at once, each being moved and rotated, and all in 2D. Each image is just two triangles, with the image texture. All pretty basic stuff (or should be!).

After much Googling over the past couple of nights, I've worked out how to convert from the OpenGL co-ordinates to screen co-ordinates. However when I do so, and then rotate an image, squares become rectangles as the degree of rotation moves closer to 180. I've determined that it's because of rectangular pixels, but I just can't work out what I need to do to adjust for the pixel size/shape. I apologise because I know that co-ordinate conversion must be asked so often, but I've had so much trouble finding a solution in part because so many answers are non-VAO code.

The code below is my test code, and all it does is display a blue square and rotates it on the Z-axis. (I realise that GL_MODELVIEW_MATRIX and GL_PROJECTION_MATRIX are deprecated and haven't yet looked into what they should be replaced with, but if it's a quick answer then it would also be appreciated.)

Oh, and this is using MinGW on a Windows 7 system.

Thank you.

Tim

Code :
```#include <cstdio>
#include <GL/glew.h>
#include <GL/glfw.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#define WINDOW_WIDTH 720.0f
#define WINDOW_HEIGHT 450.0f

#define POSITIONS_LOC 0

GLuint ProgramId( void )
{
const GLuint r_program_id = glCreateProgram();

const char * vertex_shader_src = "\
uniform mat4 model_matrix;\
in vec3 position;\
void main()\
{\
gl_Position = model_matrix * vec4( position, 1.0 );\
}";
const GLuint vertex_shader_id = glCreateShader( GL_VERTEX_SHADER );
glShaderSource( vertex_shader_id, 1, &vertex_shader_src , NULL );
glCompileShader( vertex_shader_id );
glAttachShader( r_program_id, vertex_shader_id );

const char * fragment_shader_src = "\
out vec4 colour;\
void main()\
{\
colour = vec4( 0, 0, 1, 1 );\
}";
const GLuint fragment_shader_id = glCreateShader( GL_FRAGMENT_SHADER );
glShaderSource( fragment_shader_id, 1, &fragment_shader_src , NULL );
glCompileShader( fragment_shader_id );
glAttachShader( r_program_id, fragment_shader_id );

glLinkProgram( r_program_id );
glDeleteShader( vertex_shader_id );
glDeleteShader( fragment_shader_id );

return r_program_id;
}

void ScreenToOglPositions( const unsigned short i_num_positions, GLdouble * const io_positions )
{
GLdouble modelview[16];
GLdouble projection[16];
GLint viewport[4];

glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );

for ( unsigned short i = 0; i < i_num_positions; i += 3 )
{
gluUnProject( io_positions[i], io_positions[i+1], io_positions[i+2],
modelview, projection, viewport,
&io_positions[i], &io_positions[i+1], &io_positions[i+2] );
}
}

GLuint VaoId( const GLdouble x, const GLdouble y, const GLdouble w, const GLdouble h )
{
GLdouble positions[] =
{
( x - w/2 ), ( y - h/2 ), 0,
( x + w/2 ), ( y - h/2 ), 0,
( x - w/2 ), ( y + h/2 ), 0,
( x - w/2 ), ( y + h/2 ), 0,
( x + w/2 ), ( y - h/2 ), 0,
( x + w/2 ), ( y + h/2 ), 0
};

GLuint vao_id;
GLuint positions_buffer_id;

ScreenToOglPositions( 18, positions );
printf( "height = %f, width = %f\n", ( positions[7] * 2 ), ( positions[3] * 2 )); // height = 0.444444, width = 0.277778

glGenVertexArrays( 1, &vao_id );
glBindVertexArray( vao_id );

glGenBuffers( 1, &positions_buffer_id );
glBindBuffer( GL_ARRAY_BUFFER, positions_buffer_id );
glBufferData( GL_ARRAY_BUFFER, sizeof ( positions ), positions, GL_STATIC_DRAW );
glVertexAttribPointer( POSITIONS_LOC, 3, GL_DOUBLE, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( POSITIONS_LOC );

glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindVertexArray( 0 );

return vao_id;
}

int main( const int argc, const char * const argv[] )
{
glfwInit();
glfwOpenWindow( WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, 0, 0, 32, 0, GLFW_WINDOW );
glfwSwapInterval( 1 );
glewInit();

const GLuint program_id = ProgramId();
const GLuint vao_id = VaoId(( WINDOW_WIDTH / 2 ), ( WINDOW_HEIGHT /2 ), 100, 100 );
GLfloat rotation = 0.0f;

glUseProgram( program_id );
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );

do
{
rotation = fmod(( rotation + 1 ), 360 );
glm::mat4 model_matrix = glm::mat4( 1.0f );
model_matrix = glm::translate( model_matrix, glm::vec3( 0, 0, 0 ));
model_matrix = glm::rotate( model_matrix, 0.0f, glm::vec3( 1, 0, 0 ));
model_matrix = glm::rotate( model_matrix, 0.0f, glm::vec3( 0, 1, 0 ));
model_matrix = glm::rotate( model_matrix, rotation, glm::vec3( 0, 0, 1 ));
model_matrix = glm::scale( model_matrix, glm::vec3( 1.0f ));
glUniformMatrix4fv( glGetUniformLocation( program_id, "model_matrix" ), 1, GL_FALSE, glm::value_ptr( model_matrix ));

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glBindVertexArray( vao_id );
glDrawArrays( GL_TRIANGLES, 0, 6 );
glBindVertexArray( 0 );
glfwSwapBuffers();
} while (( glfwGetKey( GLFW_KEY_ESC ) == GLFW_RELEASE ) && glfwGetWindowParam( GLFW_OPENED ));

return 0;
}```