My code does look a bit simple compared to most implementations, but I think it does everything it needs to. I've seen other implementations use things like tan() and some other fluff, but it seems like useless fluff.
Line3f GetPickLine( void ) {
const int* vp = game->renderer.viewport;
// map UI mouse pos to [-1,1]
Vec3f pos( game->input.GetUIMousePos() );
pos.x = 2 * pos.x / vp[GL_VP_W] - 1; // todo * aspectRatio
pos.y = 1 - 2 * pos.y / vp[GL_VP_H]; // invert y axis
pos.z = -1;
// get the inverted modelViewProjection matrix
Mat4f mv( game->renderer.modelMatrix );
Mat4f mvpi = Mat4f( game->renderer.projectionMatrix ) * mv;
mvpi.InvertRotationOrtho();
mvpi.InvertTranspositionOrtho();
// multiply mouse pos and modelViewProjection matrix to get a point on that ray
pos = mvpi * pos;
Vec3f cam( -mv.Column3f(3) ); // camera position is last column of modelView matrix
return Line3f( cam, pos );
}
//matrices are column-major
void Mat4f::InvertRotationOrtho( void ) {
swap( data[0][1], data[1][0] );
swap( data[0][2], data[2][0] );
swap( data[1][2], data[2][1] );
}
void Mat4f::InvertTranspositionOrtho( void ) {
data[3][0] = -data[3][0];
data[3][1] = -data[3][1];
data[3][2] = -data[3][2];
}
Vec3f Mat4f::Column3f( const int c ) const {
ASSERT( c >=0 && c <= 3 , "Mat4f::Column3f: Bad argument\n." )
return Vec3f( data[c][0], data[c][1], data[c][2] );
}
void swap( float& one, float& two ) {
float tmp(one);
one = two;
two = tmp;
}