etqw-sdk/source/idlib/PropertiesImpl.h
2008-05-29 00:00:00 +00:00

929 lines
22 KiB
C++

// Copyright (C) 2007 Id Software, Inc.
//
#ifndef __PROPERTIES_IMPL_H__
#define __PROPERTIES_IMPL_H__
namespace sdProperties {
/*
============
sdPropertyValue< T >::operator==
============
*/
template< class T > ID_INLINE bool sdPropertyValue< T >::operator==( const sdPropertyValue< T >& rhs ) const {
return( rhs.value == value );
}
/*
============
sdPropertyValue< T >::operator==
============
*/
template< class T > ID_INLINE bool sdPropertyValue< T >::operator==( const T& rhs ) const {
return( rhs == value );
}
/*
============
sdPropertyValue< T >::operator!=
============
*/
template< class T > ID_INLINE bool sdPropertyValue< T >::operator!=( const sdPropertyValue< T >& rhs ) const {
return( rhs.value != value );
}
/*
============
sdPropertyValue< T >::operator!=
============
*/
template< class T > ID_INLINE bool sdPropertyValue< T >::operator!=( const T& rhs ) const {
return( rhs != value );
}
/*
============
sdPropertyValue< T >::operator=
============
*/
template< class T > ID_INLINE sdPropertyValue< T >& sdPropertyValue< T >::operator=( const sdPropertyValue< T >& rhs ) {
if( &rhs != this ) {
*this = rhs.value;
}
return *this;
}
/*
============
operator==
============
*/
template<class T, class U> ID_INLINE bool operator==( sdPropertyValue< T >& lhs, const U& rhs ) {
return lhs.GetValue() == rhs;
}
/*
============
operator==
============
*/
template<class T, class U> ID_INLINE bool operator==( const U& lhs, sdPropertyValue< T >& rhs ) {
return lhs == rhs.GetValue();
}
/*
============
sdFromString
============
*/
ID_INLINE bool sdFromString( int& value, const char* str ) {
int i;
if( sscanf( str, "%i", &i ) != 1 ) {
assert( 0 );
value = 0;
return false;
} else {
value = i;
return true;
}
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( unsigned int& value, const char* str ) {
unsigned int i;
if( sscanf( str, "%u", &i ) != 1 ) {
assert( 0 );
value = 0;
} else {
value = i;
}
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( float& value, const char* str ) {
float f;
if( sscanf( str, "%g", &f ) != 1 ) {
assert( 0 );
value = 0.0f;
} else {
value = f;
}
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( idVec2& value, const char* str ) {
idVec2 vec;
if( sscanf( str, "%g %g", &vec.x, &vec.y ) != 2 ) {
assert( 0 );
value = vec2_origin;
} else {
value = vec;
}
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( idVec3& value, const char* str ) {
idVec3 vec;
if( sscanf( str, "%g %g %g", &vec.x, &vec.y, &vec.z ) != 3 ) {
assert( 0 );
value = vec3_origin;
} else {
value = vec;
}
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( idAngles& value, const char* str ) {
idAngles vec;
if( sscanf( str, "%g %g %g", &vec.pitch, &vec.yaw, &vec.roll ) != 3 ) {
assert( 0 );
value.Zero();
} else {
value = vec;
}
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( idVec4& value, const char* str ) {
idVec4 vec;
if( sscanf( str, "%g %g %g %g", &vec.x, &vec.y, &vec.z, &vec.w ) != 4 ) {
assert( 0 );
value = vec4_origin;
} else {
value = vec;
}
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( sdColor3& value, const char* str ) {
sdColor3 c;
if( sscanf( str, "%g %g %g", &c.r, &c.g, &c.b ) != 3 ) {
assert( 0 );
value = sdColor3::white;
} else {
value = c;
}
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( sdColor4& value, const char* str ) {
sdColor4 c;
if( sscanf( str, "%g %g %g %g", &c.r, &c.g, &c.b, &c.a ) != 4 ) {
assert( 0 );
value = sdColor4::white;
} else {
value = c;
}
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( bool& value, const char* str ) {
int i;
if( sscanf( str, "%i", &i ) != 1 ) {
assert( 0 );
value = false;
} else {
value = ( i != 0 );
}
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( idStr& value, const char* str ) {
value = str;
}
/*
============
sdFromString
============
*/
template< class T >
ID_INLINE void sdFromString( sdPropertyValue< T >& value, const char* str ) {
T v;
sdFromString( v, str );
value = v;
}
/*
============
sdEnforceNumericFormat
============
*/
ID_INLINE idStr sdEnforceNumericFormat( const int numItems, const char* input ) {
idStr retStr;
idToken token;
idLexer src( input, idStr::Length( input ), "sdEnforceNumericFormat" );
int readItems = 0;
while( src.ReadToken( &token ) ) {
if( token == "-" ) {
retStr += token;
continue;
}
if( token.IsNumeric() ) {
retStr += token;
if( token != "-" && token != "." ) {
retStr += " ";
}
} else {
retStr += "0 ";
}
++readItems;
}
if( numItems != readItems || !src.EndOfFile() ) {
assert( 0 );
retStr.Clear();
for( int i = 0; i < numItems - 1; i++ ) {
retStr += "0 ";
}
retStr += "0";
}
retStr.StripTrailing( ' ' );
return retStr;
}
/*
============
sdFromString
============
*/
ID_INLINE void sdFromString( sdProperty& value, const char* str ) {
if( !value.IsValid() ) {
assert( !"sdFromString:: Invalid property" );
return;
}
switch( value.GetValueType() ) {
case PT_STRING: *value.value.stringValue = str; break;
case PT_WSTRING: *value.value.wstringValue = va( L"%hs", str ); break;
case PT_INT: sdFromString( *value.value.intValue, sdEnforceNumericFormat( sdPropertyTraits< int >::dimension, str ) ); break;
case PT_FLOAT: sdFromString( *value.value.floatValue, sdEnforceNumericFormat( sdPropertyTraits< float >::dimension, str ) ); break;
case PT_BOOL: sdFromString( *value.value.boolValue, sdEnforceNumericFormat( sdPropertyTraits< bool >::dimension, str ) ); break;
case PT_VEC2: sdFromString( *value.value.vec2Value, sdEnforceNumericFormat( sdPropertyTraits< idVec2 >::dimension, str ) ); break;
case PT_VEC3: sdFromString( *value.value.vec3Value, sdEnforceNumericFormat( sdPropertyTraits< idVec3 >::dimension, str ) ); break;
case PT_VEC4: sdFromString( *value.value.vec4Value, sdEnforceNumericFormat( sdPropertyTraits< idVec4 >::dimension, str ) ); break;
case PT_COLOR3: sdFromString( *value.value.color3Value, sdEnforceNumericFormat( sdPropertyTraits< sdColor3 >::dimension, str ) ); break;
case PT_COLOR4: sdFromString( *value.value.color4Value, sdEnforceNumericFormat( sdPropertyTraits< sdColor4 >::dimension, str ) ); break;
case PT_ANGLES: sdFromString( *value.value.anglesValue, sdEnforceNumericFormat( sdPropertyTraits< idAngles >::dimension, str ) ); break;
default:
assert( !"sdFromString:: Invalid property type" );
break;
}
}
/*
============
sdToString
============
*/
template< class T >
ID_INLINE idStr sdToString( const sdPropertyValue< T >& value ) {
return value.GetValue().ToString();
}
/*
============
sdToString
============
*/
ID_INLINE idStr sdToString( const sdPropertyValue< int >& value ) {
return va( "%i", value.GetValue() );
}
/*
============
sdToString
============
*/
ID_INLINE idStr sdToString( const sdPropertyValue< float >& value ) {
return va( "%g", value.GetValue() );
}
/*
============
sdToString
============
*/
ID_INLINE idStr sdToString( const sdPropertyValue< bool >& value ) {
return va( "%i", value.GetValue() ? 1 : 0 );
}
/*
============
sdToString
============
*/
ID_INLINE idStr sdToString( const sdProperty& value ) {
if( !value.IsValid() ) {
assert( !"sdToString:: Invalid property" );
return "";
}
switch( value.GetValueType() ) {
case PT_STRING: return value.value.stringValue->GetValue();
case PT_WSTRING: return va( "%ls", value.value.wstringValue->GetValue().c_str() );
case PT_INT: return sdToString( *value.value.intValue );
case PT_FLOAT: return sdToString( *value.value.floatValue );
case PT_BOOL: return sdToString( *value.value.boolValue );
case PT_VEC2: return sdToString( *value.value.vec2Value );
case PT_VEC3: return sdToString( *value.value.vec3Value );
case PT_VEC4: return sdToString( *value.value.vec4Value );
case PT_COLOR3: return sdToString( *value.value.color3Value );
case PT_COLOR4: return sdToString( *value.value.color4Value );
case PT_ANGLES: return sdToString( *value.value.anglesValue );
default:
assert( !"sdFromString:: Invalid property type" );
}
return "";
}
#if defined( MACOS_X )
template< typename T >
struct isNaN_impl {
bool operator()(T) { return false; }
};
template<>
struct isNaN_impl<float> {
bool operator()(float x) { return x != x; }
};
template<>
struct isNaN_impl<double> {
bool operator()(double x) { return x != x; }
};
template< typename T > bool isNaN( T x ) {
static isNaN_impl<T> impl;
return impl(x);
}
#endif
/*
============
sdPropertyValue< T >::SetIndex
============
*/
template< class T >
template< typename ST >
ID_INLINE void sdPropertyValue< T >::SetIndex( int index, ST newValue ) {
assert( !Traits::integral && index >= 0 && ( Traits::dimension == 0 || index < Traits::dimension ));
#if defined( MACOS_X )
// Avoid a crash due to infinite recursion if newValue is NaN.
// TTimo - no indication this would happen with final/released assets. leaving for mac build only
if ( newValue != value[ index ] && !( isNaN( newValue ) && isNaN( value[ index] ) ) ) {
#else
if ( newValue != value[ index ] ) {
#endif
if( onValidate.Num() ) {
T tempValue = value;
if( !Validate( tempValue )) {
return;
}
}
const T oldValue = value;
value[ index ] = newValue;
if ( flags.callbackEnabled ) {
for( int i = 0; i < onChange.Num(); i++ ) {
if( onChange[ i ].IsValid() ) {
onChange[ i ]( oldValue, value );
}
}
}
}
}
/*
============
sdPropertyValue< T >::operator=
============
*/
template< class T > ID_INLINE sdPropertyValue< T >& sdPropertyValue< T >::operator=( typename Traits::ConstParameter rhs ) {
if( flags.readOnly ) {
return *this;
}
if( rhs != value ) {
if( !Validate( rhs )) {
return *this;
}
const T oldValue = value;
value = rhs;
if ( flags.callbackEnabled ) {
for( int i = 0; i < onChange.Num(); i++ ) {
if( onChange[ i ].IsValid() ) {
onChange[ i ]( oldValue, value );
}
}
}
}
return *this;
}
template<> ID_INLINE void sdPropertyValue< idStr >::Set( const char* rhs ) {
if( flags.readOnly ) {
return;
}
if( value.Cmp( rhs ) ) {
if( !Validate( rhs )) {
return;
}
const idStr oldValue = value;
value = rhs;
if ( flags.callbackEnabled ) {
for( int i = 0; i < onChange.Num(); i++ ) {
if( onChange[ i ].IsValid() ) {
onChange[ i ]( oldValue, value );
}
}
}
}
}
/*
============
operator|=
============
*/
template<class T, class U> ID_INLINE sdPropertyValue< T >& operator|=( sdPropertyValue< T >& lhs, const U& rhs ) {
return ( lhs = ( lhs.GetValue() | rhs ));
}
/*
============
operator&=
============
*/
template<class T, class U> ID_INLINE sdPropertyValue< T >& operator&=( sdPropertyValue< T >& lhs, const U& rhs ) {
return ( lhs = ( lhs.GetValue() & rhs ));
}
/*
============
operator^=
============
*/
template<class T, class U> ID_INLINE sdPropertyValue< T >& operator^=( sdPropertyValue< T >& lhs, const U& rhs ) {
return ( lhs = ( lhs.GetValue() ^ rhs ));
}
/*
============
operator+=
============
*/
template<class T, class U> ID_INLINE sdPropertyValue< T >& operator+=( sdPropertyValue< T >& lhs, const U& rhs ) {
return ( lhs = ( lhs.GetValue() + rhs ));
}
/*
============
operator-=
============
*/
template<class T, class U> ID_INLINE sdPropertyValue< T >& operator-=( sdPropertyValue< T >& lhs, const U& rhs ) {
return ( lhs = ( lhs.GetValue() - rhs ));
}
/*
============
operator*=
============
*/
template<class T, class U> ID_INLINE sdPropertyValue< T >& operator*=( sdPropertyValue< T >& lhs, const U& rhs ) {
return ( lhs = ( lhs.GetValue() * rhs ));
}
/*
============
operator/=
============
*/
template<class T, class U> ID_INLINE sdPropertyValue< T >& operator/=( sdPropertyValue< T >& lhs, const U& rhs ) {
return ( lhs = ( lhs.GetValue() / rhs ));
}
/*
============
operator++
============
*/
template<class T> ID_INLINE sdPropertyValue< T > operator++( sdPropertyValue< T >& lhs, int ) {
sdPropertyValue< T > temp = lhs;
lhs = lhs.GetValue() + 1;
return temp;
}
/*
============
operator--
============
*/
template<class T> ID_INLINE sdPropertyValue< T > operator--( sdPropertyValue< T >& lhs, int ) {
sdPropertyValue< T > temp = lhs;
lhs = lhs.GetValue() - 1;
return temp;
}
/*
============
operator++
============
*/
template<class T, class U> ID_INLINE sdPropertyValue< T >& operator++( sdPropertyValue< T >& lhs ) {
return ( lhs = ( lhs + 1 ));
}
/*
============
operator--
============
*/
template<class T, class U> ID_INLINE sdPropertyValue< T >& operator--( sdPropertyValue< T >& lhs ) {
return ( lhs = ( lhs - 1 ));
}
// convenience global operators for integer types
/*
============
sdPropertyValue< T >::operator &
============
*/
template< class T > ID_INLINE int operator&( const sdPropertyValue< T >& lhs, const int rhs ) {
return lhs.GetValue() & rhs;
}
/*
============
sdPropertyValue< T >::operator &
============
*/
template< class T > ID_INLINE int operator&( const int lhs, const sdPropertyValue< T >& rhs ) {
return lhs & rhs.GetValue();
}
/*
============
sdPropertyValue< T >::operator |
============
*/
template< class T > ID_INLINE int operator|( const sdPropertyValue< T >& lhs, const int rhs ) {
return lhs.GetValue() | rhs;
}
/*
============
sdPropertyValue< T >::operator |
============
*/
template< class T > ID_INLINE int operator|( const int lhs, const sdPropertyValue< T >& rhs ) {
return lhs | rhs.GetValue();
}
/*
============
sdPropertyValue< T >::operator ^
============
*/
template< class T > ID_INLINE int operator^( const sdPropertyValue< T >& lhs, const int rhs ) {
return lhs.GetValue() ^ rhs;
}
/*
============
sdPropertyValue< T >::operator ^
============
*/
template< class T > ID_INLINE int operator^( const int lhs, const sdPropertyValue< T >& rhs ) {
return lhs ^ rhs.GetValue();
}
/*
============
sdPropertyValue< T >::operator %
============
*/
template< class T > ID_INLINE int operator%( const sdPropertyValue< T >& lhs, const int rhs ) {
return lhs.GetValue() % rhs;
}
/*
============
sdPropertyValue< T >::operator %
============
*/
template< class T > ID_INLINE int operator%( const int lhs, const sdPropertyValue< T >& rhs ) {
return lhs % rhs.GetValue();
}
/*
============
sdPropertyValue< T >::Get
============
*/
template< class T > ID_INLINE sdPropertyValue< T >::operator typename sdPropertyValue< T >::Traits::ConstReference() const {
return value;
}
/*
============
sdPropertyValue< T >::Get
============
*/
template< class T > ID_INLINE typename sdPropertyValue< T >::Traits::ConstReference sdPropertyValue< T >::GetValue() const {
return value;
}
/*
============
sdPropertyValue< T >::AddOnChangeHandler
============
*/
template< class T >
ID_INLINE CallbackHandle sdPropertyValue< T >::AddOnChangeHandler( CallbackTarget newCallback ) {
int index = 0;
while( index < onChange.Num() && onChange[ index ].IsValid() ) {
++index;
}
if( index >= onChange.Num() ) {
index = onChange.Append( newCallback );
} else {
onChange[ index ] = newCallback;
}
assert( onChange.Num() );
return index;
}
/*
============
sdPropertyValue< T >::RemoveOnChangeHandler
============
*/
template< class T >
ID_INLINE void sdPropertyValue< T >::RemoveOnChangeHandler( CallbackHandle& handle ) {
if( handle.IsValid() && handle < onChange.Num() ) {
onChange[ handle ].Release();
} else {
assert( 0 );
}
handle.Release();
}
/*
============
sdPropertyValue< T >::AddValidator
============
*/
template< class T >
ID_INLINE CallbackHandle sdPropertyValue< T >::AddValidator( ValidatorCallbackTarget newCallback ) {
int index = 0;
while( index < onValidate.Num() && onValidate[ index ].IsValid() ) {
++index;
}
if( index >= onValidate.Num() ) {
index = onValidate.Append( newCallback );
} else {
onValidate[ index ] = newCallback;
}
assert( onValidate.Num() );
return index;
}
/*
============
sdPropertyValue< T >::RemoveValidator
============
*/
template< class T >
ID_INLINE void sdPropertyValue< T >::RemoveValidator( CallbackHandle& handle ) {
if( handle.IsValid() && handle < onValidate.Num() ) {
onValidate[ handle ].Release();
} else {
assert( 0 );
}
handle.Release();
}
/*
============
sdPropertyValue< T >::Validate
============
*/
template< class T >
ID_INLINE bool sdPropertyValue< T >::Validate( typename Traits::ConstParameter rhs ) const {
if( !IsValidationEnabled() ) {
return true;
}
for( int i = 0; i < onValidate.Num(); i++ ) {
if( onValidate[ i ].IsValid() && !onValidate[ i ]( rhs ) ) {
return false;
}
}
return true;
}
/*
============
sdPropertyHandler::Remove
============
*/
ID_INLINE void sdPropertyHandler::Remove( const char* name ) {
propertyAllocator.Free( GetProperty( name, PT_INVALID ) );
properties.Remove( name );
}
/*
============
sdPropertyHandler::Num
============
*/
ID_INLINE int sdPropertyHandler::Num() const {
return properties.Num();
}
/*
============
sdPropertyHandler::GetProperty
============
*/
ID_INLINE sdPropertyHandler::propertyPair_t sdPropertyHandler::GetProperty( int index ) const {
return *properties.FindIndex( index );
}
/*
============
sdPropertyHandler::GetProperty
============
*/
ID_INLINE sdProperty* sdPropertyHandler::GetProperty( const char* name, ePropertyType type, bool warnIfNotFound ) const {
const char* canonicalName = MakeCanonical( name );
propertyHashMap_t::ConstIterator iter = properties.Find( canonicalName );
if ( iter != properties.End() && ( type == PT_INVALID || iter->second->valueType == type ) ) {
return iter->second;
}
if( warnIfNotFound ) {
common->Warning( "Property '%s' of type '%s' not found", canonicalName, sdProperty::TypeToString( type ));
}
return NULL;
}
/*
============
sdPropertyHandler::SetCallbacksEnabled
============
*/
ID_INLINE void sdPropertyHandler::SetCallbacksEnabled( bool callbacksEnabled ) {
for ( int i = 0; i < properties.Num(); i++ ) {
propertyHashMap_t::Iterator iter = properties.FindIndex( i );
if ( iter->second->IsValid() ) {
iter->second->value.baseValue->SetCallbackEnabled( callbacksEnabled );
}
}
}
/*
============
sdPropertyHandler::SetReadOnly
============
*/
ID_INLINE void sdPropertyHandler::SetReadOnly( bool readOnly ) {
for ( int i = 0; i < properties.Num(); i++ ) {
propertyHashMap_t::Iterator iter = properties.FindIndex( i );
if( iter->second->IsValid() ) {
iter->second->value.baseValue->SetReadOnly( readOnly );
}
}
}
/*
============
sdPropertyHandler::MakeCanonical
============
*/
ID_INLINE const char* sdPropertyHandler::MakeCanonical( const char* name ) const {
canonicalName = name;
canonicalName.ToLower();
return canonicalName.c_str();
}
/*
============
CountForPropertyType
============
*/
ID_INLINE int CountForPropertyType( sdProperties::ePropertyType type ) {
switch ( type ) {
case sdProperties::PT_VEC4: /* fall through */
case sdProperties::PT_COLOR4: return 4;
case sdProperties::PT_VEC3: /* fall through */
case sdProperties::PT_ANGLES: /* fall through */
case sdProperties::PT_COLOR3: return 3;
case sdProperties::PT_VEC2: return 2;
case sdProperties::PT_FLOAT: return 1;
case sdProperties::PT_STRING: return 1;
case sdProperties::PT_WSTRING: return 1;
case sdProperties::PT_INT: return 1;
default: return -1;
}
}
}
/*
============
sdTypeFromString
============
*/
template< class Result >
class sdTypeFromString {
public:
sdTypeFromString( const char* input ) {
sdProperties::sdFromString( output, input );
}
sdTypeFromString( const wchar_t* input ) {
sdProperties::sdFromString( output, va( "%ls", input ) );
}
operator Result() {
return output;
}
private:
Result output;
};
/*
============
operator==
============
*/
template< class T > ID_INLINE bool operator==( const T& lhs, const sdProperties::sdPropertyValue< T >& rhs ) {
return rhs.GetValue() == lhs;
}
/*
============
operator!=
============
*/
template< class T > ID_INLINE bool operator!=( const T& lhs, const sdProperties::sdPropertyValue< T >& rhs ) {
return rhs.GetValue() != lhs;
}
#endif // __PROPERTIES_IMPL_H__