/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined( INCLUDED_PIVOT_H ) #define INCLUDED_PIVOT_H #include "math/matrix.h" inline void billboard_viewplaneOriented( Matrix4& rotation, const Matrix4& world2screen ){ #if 1 rotation = g_matrix4_identity; Vector3 x( vector3_normalised( vector4_to_vector3( world2screen.x() ) ) ); Vector3 y( vector3_normalised( vector4_to_vector3( world2screen.y() ) ) ); Vector3 z( vector3_normalised( vector4_to_vector3( world2screen.z() ) ) ); vector4_to_vector3( rotation.y() ) = Vector3( x.y(), y.y(), z.y() ); vector4_to_vector3( rotation.z() ) = vector3_negated( Vector3( x.z(), y.z(), z.z() ) ); vector4_to_vector3( rotation.x() ) = vector3_normalised( vector3_cross( vector4_to_vector3( rotation.y() ), vector4_to_vector3( rotation.z() ) ) ); vector4_to_vector3( rotation.y() ) = vector3_cross( vector4_to_vector3( rotation.z() ), vector4_to_vector3( rotation.x() ) ); #else Matrix4 screen2world( matrix4_full_inverse( world2screen ) ); Vector3 near_( vector4_projected( matrix4_transformed_vector4( screen2world, Vector4( 0, 0, -1, 1 ) ) ) ); Vector3 far_( vector4_projected( matrix4_transformed_vector4( screen2world, Vector4( 0, 0, 1, 1 ) ) ) ); Vector3 up( vector4_projected( matrix4_transformed_vector4( screen2world, Vector4( 0, 1, -1, 1 ) ) ) ); rotation = g_matrix4_identity; vector4_to_vector3( rotation.y() ) = vector3_normalised( vector3_subtracted( up, near_ ) ); vector4_to_vector3( rotation.z() ) = vector3_normalised( vector3_subtracted( near_, far_ ) ); vector4_to_vector3( rotation.x() ) = vector3_normalised( vector3_cross( vector4_to_vector3( rotation.y() ), vector4_to_vector3( rotation.z() ) ) ); vector4_to_vector3( rotation.y() ) = vector3_cross( vector4_to_vector3( rotation.z() ), vector4_to_vector3( rotation.x() ) ); #endif } inline void billboard_viewpointOriented( Matrix4& rotation, const Matrix4& world2screen ){ Matrix4 screen2world( matrix4_full_inverse( world2screen ) ); #if 1 rotation = g_matrix4_identity; vector4_to_vector3( rotation.y() ) = vector3_normalised( vector4_to_vector3( screen2world.y() ) ); vector4_to_vector3( rotation.z() ) = vector3_negated( vector3_normalised( vector4_to_vector3( screen2world.z() ) ) ); vector4_to_vector3( rotation.x() ) = vector3_normalised( vector3_cross( vector4_to_vector3( rotation.y() ), vector4_to_vector3( rotation.z() ) ) ); vector4_to_vector3( rotation.y() ) = vector3_cross( vector4_to_vector3( rotation.z() ), vector4_to_vector3( rotation.x() ) ); #else Vector3 near_( vector4_projected( matrix4_transformed_vector4( screen2world, Vector4( world2screen[12] / world2screen[15], world2screen[13] / world2screen[15], -1, 1 ) ) ) ); Vector3 far_( vector4_projected( matrix4_transformed_vector4( screen2world, Vector4( world2screen[12] / world2screen[15], world2screen[13] / world2screen[15], 1, 1 ) ) ) ); Vector3 up( vector4_projected( matrix4_transformed_vector4( screen2world, Vector4( world2screen[12] / world2screen[15], world2screen[13] / world2screen[15] + 1, -1, 1 ) ) ) ); rotation = g_matrix4_identity; vector4_to_vector3( rotation.y() ) = vector3_normalised( vector3_subtracted( up, near_ ) ); vector4_to_vector3( rotation.z() ) = vector3_normalised( vector3_subtracted( near_, far_ ) ); vector4_to_vector3( rotation.x() ) = vector3_normalised( vector3_cross( vector4_to_vector3( rotation.y() ), vector4_to_vector3( rotation.z() ) ) ); vector4_to_vector3( rotation.y() ) = vector3_cross( vector4_to_vector3( rotation.z() ), vector4_to_vector3( rotation.x() ) ); #endif } inline void ConstructObject2Screen( Matrix4& object2screen, const Matrix4& object2world, const Matrix4& world2view, const Matrix4& view2device, const Matrix4& device2screen ){ object2screen = device2screen; matrix4_multiply_by_matrix4( object2screen, view2device ); matrix4_multiply_by_matrix4( object2screen, world2view ); matrix4_multiply_by_matrix4( object2screen, object2world ); } inline void ConstructObject2Device( Matrix4& object2screen, const Matrix4& object2world, const Matrix4& world2view, const Matrix4& view2device ){ object2screen = view2device; matrix4_multiply_by_matrix4( object2screen, world2view ); matrix4_multiply_by_matrix4( object2screen, object2world ); } inline void ConstructDevice2Object( Matrix4& device2object, const Matrix4& object2world, const Matrix4& world2view, const Matrix4& view2device ){ ConstructObject2Device( device2object, object2world, world2view, view2device ); matrix4_full_invert( device2object ); } //! S = ( Inverse(Object2Screen *post ScaleOf(Object2Screen) ) *post Object2Screen inline void pivot_scale( Matrix4& scale, const Matrix4& pivot2screen ){ Matrix4 pre_scale( g_matrix4_identity ); pre_scale[0] = static_cast( vector3_length( vector4_to_vector3( pivot2screen.x() ) ) ); pre_scale[5] = static_cast( vector3_length( vector4_to_vector3( pivot2screen.y() ) ) ); pre_scale[10] = static_cast( vector3_length( vector4_to_vector3( pivot2screen.z() ) ) ); scale = pivot2screen; matrix4_multiply_by_matrix4( scale, pre_scale ); matrix4_full_invert( scale ); matrix4_multiply_by_matrix4( scale, pivot2screen ); } // scale by (inverse) W inline void pivot_perspective( Matrix4& scale, const Matrix4& pivot2screen ){ scale = g_matrix4_identity; scale[0] = scale[5] = scale[10] = pivot2screen[15]; } inline void ConstructDevice2Manip( Matrix4& device2manip, const Matrix4& object2world, const Matrix4& world2view, const Matrix4& view2device, const Matrix4& device2screen ){ Matrix4 pivot2screen; ConstructObject2Screen( pivot2screen, object2world, world2view, view2device, device2screen ); ConstructObject2Device( device2manip, object2world, world2view, view2device ); Matrix4 scale; pivot_scale( scale, pivot2screen ); matrix4_multiply_by_matrix4( device2manip, scale ); pivot_perspective( scale, pivot2screen ); matrix4_multiply_by_matrix4( device2manip, scale ); matrix4_full_invert( device2manip ); } inline void Pivot2World_worldSpace( Matrix4& manip2world, const Matrix4& pivot2world, const Matrix4& modelview, const Matrix4& projection, const Matrix4& viewport ){ manip2world = pivot2world; Matrix4 pivot2screen; ConstructObject2Screen( pivot2screen, pivot2world, modelview, projection, viewport ); Matrix4 scale; pivot_scale( scale, pivot2screen ); matrix4_multiply_by_matrix4( manip2world, scale ); pivot_perspective( scale, pivot2screen ); matrix4_multiply_by_matrix4( manip2world, scale ); } inline void Pivot2World_viewpointSpace( Matrix4& manip2world, Vector3& axis, const Matrix4& pivot2world, const Matrix4& modelview, const Matrix4& projection, const Matrix4& viewport ){ manip2world = pivot2world; Matrix4 pivot2screen; ConstructObject2Screen( pivot2screen, pivot2world, modelview, projection, viewport ); Matrix4 scale; pivot_scale( scale, pivot2screen ); matrix4_multiply_by_matrix4( manip2world, scale ); billboard_viewpointOriented( scale, pivot2screen ); axis = vector4_to_vector3( scale.z() ); matrix4_multiply_by_matrix4( manip2world, scale ); pivot_perspective( scale, pivot2screen ); matrix4_multiply_by_matrix4( manip2world, scale ); } inline void Pivot2World_viewplaneSpace( Matrix4& manip2world, const Matrix4& pivot2world, const Matrix4& modelview, const Matrix4& projection, const Matrix4& viewport ){ manip2world = pivot2world; Matrix4 pivot2screen; ConstructObject2Screen( pivot2screen, pivot2world, modelview, projection, viewport ); Matrix4 scale; pivot_scale( scale, pivot2screen ); matrix4_multiply_by_matrix4( manip2world, scale ); billboard_viewplaneOriented( scale, pivot2screen ); matrix4_multiply_by_matrix4( manip2world, scale ); pivot_perspective( scale, pivot2screen ); matrix4_multiply_by_matrix4( manip2world, scale ); } #include "renderable.h" #include "cullable.h" #include "render.h" const Colour4b g_colour_x( 255, 0, 0, 255 ); const Colour4b g_colour_y( 0, 255, 0, 255 ); const Colour4b g_colour_z( 0, 0, 255, 255 ); class Shader; class RenderablePivot : public OpenGLRenderable { VertexBuffer m_vertices; public: mutable Matrix4 m_localToWorld; typedef Static StaticShader; static Shader* getShader(){ return StaticShader::instance(); } RenderablePivot(){ m_vertices.reserve( 6 ); m_vertices.push_back( PointVertex( Vertex3f( 0, 0, 0 ), g_colour_x ) ); m_vertices.push_back( PointVertex( Vertex3f( 16, 0, 0 ), g_colour_x ) ); m_vertices.push_back( PointVertex( Vertex3f( 0, 0, 0 ), g_colour_y ) ); m_vertices.push_back( PointVertex( Vertex3f( 0, 16, 0 ), g_colour_y ) ); m_vertices.push_back( PointVertex( Vertex3f( 0, 0, 0 ), g_colour_z ) ); m_vertices.push_back( PointVertex( Vertex3f( 0, 0, 16 ), g_colour_z ) ); } void render( RenderStateFlags state ) const { if ( m_vertices.size() == 0 ) { return; } if ( m_vertices.data() == 0 ) { return; } glVertexPointer( 3, GL_FLOAT, sizeof( PointVertex ), &m_vertices.data()->vertex ); glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof( PointVertex ), &m_vertices.data()->colour ); glDrawArrays( GL_LINES, 0, m_vertices.size() ); } void render( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const { renderer.PushState(); Pivot2World_worldSpace( m_localToWorld, localToWorld, volume.GetModelview(), volume.GetProjection(), volume.GetViewport() ); renderer.Highlight( Renderer::ePrimitive, false ); renderer.SetState( getShader(), Renderer::eWireframeOnly ); renderer.SetState( getShader(), Renderer::eFullMaterials ); renderer.addRenderable( *this, m_localToWorld ); renderer.PopState(); } }; #endif