/* 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_EXPRESSION_H ) #define INCLUDED_EXPRESSION_H #include template class Literal { Value m_value; public: typedef Value value_type; Literal( const Value& value ) : m_value( value ){ } const value_type& eval() const { return m_value; } }; template inline Literal float_literal( const Value& value ){ return Literal( value ); } template inline float float_for_expression( const Expression& expression ){ return expression.eval(); } template class ScalarDivided { First first; Second second; public: typedef typename First::value_type value_type; ScalarDivided( const First& first_, const Second& second_ ) : first( first_ ), second( second_ ){ } value_type eval() const { return static_cast( first.eval() / second.eval() ); } }; template inline ScalarDivided float_divided( const First& first, const Second& second ){ return ScalarDivided( first, second ); } template inline ScalarDivided, First> float_reciprocal( const First& first ){ typedef typename First::value_type first_value_type; return ScalarDivided, First>( float_literal( first_value_type( 1.0 ) ), first ); } template class SquareRoot { First first; public: typedef typename First::value_type value_type; SquareRoot( const First& first_ ) : first( first_ ){ } value_type eval() const { return static_cast( sqrt( first.eval() ) ); } }; template inline SquareRoot float_square_root( const First& first ){ return SquareRoot( first ); } template class BasicVector3Literal { const BasicVector3 m_value; public: typedef Element value_type; typedef IntegralConstant<3> dimension; BasicVector3Literal( const BasicVector3& value ) : m_value( value ){ } const value_type& eval( unsigned int i ) const { return m_value[i]; } }; template inline BasicVector3Literal vector3_literal( const BasicVector3& value ){ return BasicVector3Literal( value ); } typedef BasicVector3Literal Vector3Literal; template class BasicVector3Identity { const BasicVector3& m_value; public: typedef Element value_type; typedef IntegralConstant<3> dimension; BasicVector3Identity( const BasicVector3& value ) : m_value( value ){ } const value_type& eval( unsigned int i ) const { return m_value[i]; } }; template inline BasicVector3Identity vector3_identity( const BasicVector3& value ){ return BasicVector3Identity( value ); } typedef BasicVector3Identity Vector3Identity; template inline BasicVector3 vector3_for_expression( const Expression& expression ){ return Vector3( expression.eval( 0 ), expression.eval( 1 ), expression.eval( 2 ) ); } template class VectorScalar { First first; Literal second; public: typedef typename First::value_type value_type; typedef typename First::dimension dimension; VectorScalar( const First& first_, const Second& second_ ) : first( first_ ), second( second_.eval() ){ } value_type eval( unsigned int i ) const { return Operation::apply( first.eval( i ), second.eval() ); } }; template class VectorVector { First first; Second second; public: typedef typename First::value_type value_type; typedef typename First::dimension dimension; VectorVector( const First& first_, const Second& second_ ) : first( first_ ), second( second_ ){ } value_type eval( unsigned int i ) const { return Operation::apply( first.eval( i ), second.eval( i ) ); } }; template class Added { public: typedef First value_type; static value_type apply( const First& first, const Second& second ){ return static_cast( first + second ); } }; template inline VectorVector, First, Second> vector_added( const First& first, const Second& second ){ typedef typename First::value_type first_value_type; typedef typename Second::value_type second_value_type; return VectorVector, First, Second>( first, second ); } template class Multiplied { public: typedef First value_type; static value_type apply( const First& first, const Second& second ){ return static_cast( first * second ); } }; template inline VectorVector, First, Second> vector_multiplied( const First& first, const Second& second ){ typedef typename First::value_type first_value_type; typedef typename Second::value_type second_value_type; return VectorVector, First, Second>( first, second ); } template inline VectorScalar, First, Second> vector_scaled( const First& first, const Second& second ){ typedef typename First::value_type first_value_type; typedef typename Second::value_type second_value_type; return VectorScalar, First, Second>( first, second ); } template class Negated { public: typedef First value_type; static value_type apply( const First& first ){ return -first; } }; template class VectorUnary { First first; public: typedef typename First::value_type value_type; typedef typename First::dimension dimension; VectorUnary( const First& first_ ) : first( first_ ){ } value_type eval( unsigned int i ) const { return Operation::apply( first.eval( i ) ); } }; template inline VectorUnary > vector_negated( const First& first ){ typedef typename First::value_type first_value_type; return VectorUnary >( first ); } template class VectorCross { First first; Second second; public: typedef typename First::value_type value_type; typedef typename First::dimension dimension; VectorCross( const First& first_, const Second& second_ ) : first( first_ ), second( second_ ){ } value_type eval( unsigned int i ) const { return first.eval( ( i + 1 ) % 3 ) * second.eval( ( i + 2 ) % 3 ) - first.eval( ( i + 2 ) % 3 ) * second.eval( ( i + 1 ) % 3 ); } }; template inline VectorCross vector_cross( const First& first, const Second& second ){ return VectorCross( first, second ); } template class VectorDot { First first; Second second; public: typedef typename First::value_type value_type; typedef typename First::dimension dimension; VectorDot( const First& first_, const Second& second_ ) : first( first_ ), second( second_ ){ } template struct eval_dot { static value_type apply( const First& first, const Second& second ){ return static_cast( first.eval( Index::VALUE ) * second.eval( Index::VALUE ) + eval_dot< IntegralConstant >::apply( first, second ) ); } }; template<> struct eval_dot< IntegralConstant<0> > { static value_type apply( const First& first, const Second& second ){ return first.eval( 0 ) * second.eval( 0 ); } }; value_type eval() const { return eval_dot< IntegralConstant >::apply( first, second ); } }; template inline VectorDot vector_dot( const First& first, const Second& second ){ return VectorDot( first, second ); } template class VectorLengthSquared { First first; public: typedef typename First::value_type value_type; typedef typename First::dimension dimension; VectorLengthSquared( const First& first_ ) : first( first_ ){ } static value_type squared( const value_type& value ){ return value * value; } template struct eval_squared { static value_type apply( const First& first ){ return static_cast( squared( first.eval( Index::VALUE ) ) + eval_squared< IntegralConstant >::apply( first ) ); } }; template<> struct eval_squared< IntegralConstant<0> > { static value_type apply( const First& first ){ return squared( first.eval( 0 ) ); } }; value_type eval() const { return eval_squared< IntegralConstant >::apply( first ); } }; template inline VectorLengthSquared vector_length_squared( const First& first ){ return VectorLengthSquared( first ); } template inline SquareRoot< VectorLengthSquared > vector_length( const First& first ){ return float_square_root( vector_length_squared( first ) ); } #if 1 template inline VectorScalar< Multiplied, First, // multiple evaulations of subexpression ScalarDivided< Literal, SquareRoot< VectorLengthSquared > > > vector_normalised( const First& first ){ typedef typename First::value_type first_value_type; return vector_scaled( first, float_reciprocal( vector_length( first ) ) ); } #else template inline VectorScalar< Multiplied, First, // single evaluation of subexpression Literal > vector_normalised( const First& first ){ typedef typename First::value_type first_value_type; return vector_scaled( first, float_literal( static_cast( first_value_type( 1.0 ) / vector_length( first ).eval() ) ) ); } #endif class Matrix4Literal { const Matrix4 m_value; public: typedef float value_type; typedef IntegralConstant<4> dimension0; typedef IntegralConstant<4> dimension1; Matrix4Literal( const Matrix4& value ) : m_value( value ){ } const value_type& eval( unsigned int r, unsigned int c ) const { return m_value[r * 4 + c]; } }; inline Matrix4Literal matrix4_literal( const Matrix4& value ){ return Matrix4Literal( value ); } class Matrix4Identity { const Matrix4& m_value; public: typedef float value_type; typedef IntegralConstant<4> dimension0; typedef IntegralConstant<4> dimension1; Matrix4Identity( const Matrix4& value ) : m_value( value ){ } const value_type& eval( unsigned int r, unsigned int c ) const { return m_value[r * 4 + c]; } }; inline Matrix4Identity matrix4_identity( const Matrix4& value ){ return Matrix4Identity( value ); } template inline Matrix4 matrix4_for_expression( const Expression& expression ){ return Matrix4( expression.eval( 0, 0 ), expression.eval( 0, 1 ), expression.eval( 0, 2 ), expression.eval( 0, 3 ), expression.eval( 1, 0 ), expression.eval( 1, 1 ), expression.eval( 1, 2 ), expression.eval( 1, 3 ), expression.eval( 2, 0 ), expression.eval( 2, 1 ), expression.eval( 2, 2 ), expression.eval( 2, 3 ), expression.eval( 3, 0 ), expression.eval( 3, 1 ), expression.eval( 3, 2 ), expression.eval( 3, 3 ) ); } template inline Matrix4 matrix4_affine_for_expression( const Expression& expression ){ return Matrix4( expression.eval( 0, 0 ), expression.eval( 0, 1 ), expression.eval( 0, 2 ), 0, expression.eval( 1, 0 ), expression.eval( 1, 1 ), expression.eval( 1, 2 ), 0, expression.eval( 2, 0 ), expression.eval( 2, 1 ), expression.eval( 2, 2 ), 0, expression.eval( 3, 0 ), expression.eval( 3, 1 ), expression.eval( 3, 2 ), 1 ); } template class PointMultiplied { const First& first; const Second& second; public: typedef typename First::value_type value_type; typedef typename First::dimension dimension; PointMultiplied( const First& first_, const Second& second_ ) : first( first_ ), second( second_ ){ } value_type eval( unsigned int i ) const { return static_cast( second.eval( 0, i ) * first.eval( 0 ) + second.eval( 1, i ) * first.eval( 1 ) + second.eval( 2, i ) * first.eval( 2 ) + second.eval( 3, i ) ); } }; template inline PointMultiplied point_multiplied( const First& point, const Second& matrix ){ return PointMultiplied( point, matrix ); } template class Matrix4Multiplied { const First& first; const Second& second; public: typedef typename First::value_type value_type; typedef typename First::dimension0 dimension0; typedef typename First::dimension1 dimension1; Matrix4Multiplied( const First& first_, const Second& second_ ) : first( first_ ), second( second_ ){ } value_type eval( unsigned int r, unsigned int c ) const { return static_cast( second.eval( r, 0 ) * first.eval( 0, c ) + second.eval( r, 1 ) * first.eval( 1, c ) + second.eval( r, 2 ) * first.eval( 2, c ) + second.eval( r, 3 ) * first.eval( 3, c ) ); } }; template inline Matrix4Multiplied matrix4_multiplied( const First& first, const Second& second ){ return Matrix4Multiplied( first, second ); } template class MatrixTransposed { const First& first; public: typedef typename First::value_type value_type; typedef typename First::dimension0 dimension0; typedef typename First::dimension1 dimension1; MatrixTransposed( const First& first_ ) : first( first_ ){ } value_type eval( unsigned int r, unsigned int c ) const { return first.eval( c, r ); } }; template inline MatrixTransposed matrix_transposed( const First& first ){ return MatrixTransposed( first ); } #endif