diff options
Diffstat (limited to 'kpovmodeler/pmlight.cpp')
-rw-r--r-- | kpovmodeler/pmlight.cpp | 1064 |
1 files changed, 1064 insertions, 0 deletions
diff --git a/kpovmodeler/pmlight.cpp b/kpovmodeler/pmlight.cpp new file mode 100644 index 00000000..b715c7ee --- /dev/null +++ b/kpovmodeler/pmlight.cpp @@ -0,0 +1,1064 @@ +/* +************************************************************************** + description + -------------------- + copyright : (C) 2000-2002 by Andreas Zehender + email : [email protected] +************************************************************************** + +************************************************************************** +* * +* This program 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. * +* * +**************************************************************************/ + + +#include "pmlight.h" + +#include "pmxmlhelper.h" +#include "pmlightedit.h" +#include "pmmemento.h" +#include "pmviewstructure.h" +#include "pm3dcontrolpoint.h" +#include "pmmath.h" +#include "pmmatrix.h" +#include "pmenumproperty.h" + +#include <klocale.h> + +const PMVector locationDefault = PMVector( 0, 0, 0 ); +const PMColor colorDefault = PMColor( 1.0, 1.0, 1.0 ); +const double radiusDefault = 70.0; +const double falloffDefault = 70.0; +const double tightnessDefault = 10; +const PMVector pointAtDefault = PMVector( 0, 0, 1 ); +const bool parallelDefault = false; +const PMVector areaAxis1Default = PMVector( 1, 0, 0 ); +const PMVector areaAxis2Default = PMVector( 0, 1, 0 ); +const int areaSize1Default = 3; +const int areaSize2Default = 3; +const int adaptiveDefault = 0; +const bool orientDefault = false; +const bool jitterDefault = false; +const int fadePowerDefault = 1; +const double fadeDistanceDefault = 10.0; + +PMViewStructure* PMLight::s_pDefaultPointStructure = 0; +PMViewStructure* PMLight::s_pDefaultSpotStructure = 0; +PMViewStructure* PMLight::s_pDefaultCylindricalStructure = 0; +double PMLight::s_pointLightSize = 0.25; +int PMLight::s_nCylinderLines = 8; +int PMLight::s_nSpotLines = 8; +double PMLight::s_length = 1.0; + +PMDefinePropertyClass( PMLight, PMLightProperty ); +PMDefineEnumPropertyClass( PMLight, PMLight::PMLightType, PMTypeProperty ); +PMDefineEnumPropertyClass( PMLight, PMLight::PMAreaType, PMAreaProperty ); + +PMMetaObject* PMLight::s_pMetaObject = 0; +PMObject* createNewLight( PMPart* part ) +{ + return new PMLight( part ); +} + +PMLight::PMLight( PMPart* part ) + : Base( part ) +{ + m_location = locationDefault; + m_color = colorDefault; + m_type = PointLight; + m_radius = radiusDefault; + m_falloff = falloffDefault; + m_tightness = tightnessDefault; + m_pointAt = pointAtDefault; + m_parallel = parallelDefault; + m_bAreaLight = false; + m_areaType = Rectangular; + m_areaAxis1 = areaAxis1Default; + m_areaAxis2 = areaAxis2Default; + m_areaSize1 = areaSize1Default; + m_areaSize2 = areaSize2Default; + m_adaptive = adaptiveDefault; + m_orient = orientDefault; + m_jitter = jitterDefault; + m_bFading = false; + m_fadeDistance = fadeDistanceDefault; + m_fadePower = fadePowerDefault; + m_bMediaInteraction = true; + m_bMediaAttenuation = true; +} + +PMLight::PMLight( const PMLight& l ) + : Base( l ) +{ + m_location = l.m_location; + m_color = l.m_color; + m_type = l.m_type; + m_radius = l.m_radius; + m_falloff = l.m_falloff; + m_tightness = l.m_tightness; + m_pointAt = l.m_pointAt; + m_parallel = l.m_parallel; + m_bAreaLight = l.m_bAreaLight; + m_areaType = l.m_areaType; + m_areaAxis1 = l.m_areaAxis1; + m_areaAxis2 = l.m_areaAxis2; + m_areaSize1 = l.m_areaSize1; + m_areaSize2 = l.m_areaSize2; + m_adaptive = l.m_adaptive; + m_orient = l.m_orient; + m_jitter = l.m_jitter; + m_bFading = l.m_bFading; + m_fadeDistance = l.m_fadeDistance; + m_fadePower = l.m_fadePower; + m_bMediaInteraction = l.m_bMediaInteraction; + m_bMediaAttenuation = l.m_bMediaAttenuation; +} + +PMLight::~PMLight( ) +{ +} + +QString PMLight::description( ) const +{ + return i18n( "light" ); +} + +void PMLight::serialize( QDomElement& e, QDomDocument& doc ) const +{ + e.setAttribute( "location", m_location.serializeXML( ) ); + e.setAttribute( "color", m_color.serializeXML( ) ); + + switch( m_type ) + { + case SpotLight: + e.setAttribute( "lighttype", "spotlight" ); + break; + case CylinderLight: + e.setAttribute( "lighttype", "cylinder" ); + break; + case ShadowlessLight: + e.setAttribute( "lighttype", "shadowless" ); + break; + case PointLight: + e.setAttribute( "lighttype", "point" ); + break; + } + + if( ( m_type == SpotLight ) || ( m_type == CylinderLight ) ) + { + e.setAttribute( "radius", m_radius ); + e.setAttribute( "falloff", m_falloff ); + e.setAttribute( "tightness", m_tightness ); + e.setAttribute( "point_at", m_pointAt.serializeXML( ) ); + } + + if ( m_parallel ) + e.setAttribute( "parallel", "1" ); + else + e.setAttribute( "parallel", "0" ); + + if( m_bAreaLight ) + { + if ( m_areaType == Rectangular ) + e.setAttribute( "areatype", "rectangular" ); + else + e.setAttribute( "areatype", "circular" ); + + e.setAttribute( "area_light", "1" ); + e.setAttribute( "area_light_a", m_areaAxis1.serializeXML( ) ); + e.setAttribute( "area_light_b", m_areaAxis2.serializeXML( ) ); + e.setAttribute( "area_size_a", m_areaSize1 ); + e.setAttribute( "area_size_b", m_areaSize2 ); + e.setAttribute( "adaptive", m_adaptive ); + + if( m_orient ) + e.setAttribute( "orient", "1" ); + else + e.setAttribute( "orient", "0" ); + + if( m_jitter ) + e.setAttribute( "jitter", "1" ); + else + e.setAttribute( "jitter", "0" ); + } + else + e.setAttribute( "area_light", "0" ); + + if( m_bFading ) + { + e.setAttribute( "fading", "1" ); + e.setAttribute( "fade_distance" , m_fadeDistance ); + e.setAttribute( "fade_power", m_fadePower ); + } + else + e.setAttribute( "fading", "0" ); + + if( m_bMediaInteraction ) + e.setAttribute( "media_interaction", "1" ); + else + e.setAttribute( "media_interaction", "0" ); + + if( m_bMediaAttenuation ) + e.setAttribute( "media_attenuation", "1" ); + else + e.setAttribute( "media_attenuation", "0" ); + + Base::serialize( e, doc ); +} + +void PMLight::readAttributes( const PMXMLHelper& h ) +{ + QString str; + + m_location = h.vectorAttribute( "location", locationDefault ); + m_color = h.colorAttribute( "color", colorDefault ); + + str = h.stringAttribute( "lighttype", "point" ); + if( str == "point" ) + m_type = PointLight; + else if( str == "spotlight" ) + m_type = SpotLight; + else if( str == "cylinder" ) + m_type = CylinderLight; + else if( str == "shadowless" ) + m_type = ShadowlessLight; + else + m_type = PointLight; + + if( ( m_type == SpotLight ) || ( m_type == CylinderLight ) ) + { + m_radius = h.doubleAttribute( "radius", radiusDefault ); + m_falloff = h.doubleAttribute( "falloff", falloffDefault ); + m_tightness = h.doubleAttribute( "tightness", tightnessDefault ); + m_pointAt = h.vectorAttribute( "point_at", pointAtDefault ); + } + + m_parallel = h.boolAttribute( "parallel", parallelDefault ); + + m_bAreaLight = h.boolAttribute( "area_light", false ); + if( m_bAreaLight ) + { + str = h.stringAttribute( "areatype", "rectangular" ); + if ( str == "circular" ) + m_areaType = Circular; + else + m_areaType = Rectangular; + + m_areaAxis1 = h.vectorAttribute( "area_light_a", areaAxis1Default ); + m_areaAxis2 = h.vectorAttribute( "area_light_b", areaAxis2Default ); + m_areaSize1 = h.intAttribute( "area_size_a", areaSize1Default ); + m_areaSize2 = h.intAttribute( "area_size_b", areaSize2Default ); + m_adaptive = h.intAttribute( "adaptive", adaptiveDefault ); + m_orient = h.boolAttribute( "orient", orientDefault ); + m_jitter = h.boolAttribute( "jitter", jitterDefault ); + } + m_bFading = h.boolAttribute( "fading", false ); + if( m_bFading ) + { + m_fadeDistance = h.doubleAttribute( "fade_distance", fadeDistanceDefault ); + m_fadePower = h.intAttribute( "fade_power", m_fadePower ); + } + m_bMediaInteraction = h.boolAttribute( "media_interaction", true ); + m_bMediaAttenuation = h.boolAttribute( "media_attenuation", true ); + + Base::readAttributes( h ); +} + +PMMetaObject* PMLight::metaObject( ) const +{ + if( !s_pMetaObject ) + { + s_pMetaObject = new PMMetaObject( "Light", Base::metaObject( ), + createNewLight ); + PMTypeProperty* p = new PMTypeProperty( "lightType", &PMLight::setLightType, + &PMLight::lightType ); + p->addEnumValue( "PointLight", PointLight ); + p->addEnumValue( "SpotLight", SpotLight ); + p->addEnumValue( "CylinderLight", CylinderLight ); + p->addEnumValue( "ShadowlessLight", ShadowlessLight ); + s_pMetaObject->addProperty( p ); + + s_pMetaObject->addProperty( + new PMLightProperty( "location", &PMLight::setLocation, &PMLight::location ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "color", &PMLight::setColor, &PMLight::color ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "radius", &PMLight::setRadius, &PMLight::radius ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "falloff", &PMLight::setFalloff, &PMLight::falloff ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "tightness", &PMLight::setTightness, &PMLight::tightness ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "pointAt", &PMLight::setPointAt, &PMLight::pointAt ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "parallel", &PMLight::setParallel, &PMLight::parallel ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "areaLight", &PMLight::setAreaLight, &PMLight::isAreaLight ) ); + + PMAreaProperty* p2 = new PMAreaProperty( "areaType", &PMLight::setAreaType, + &PMLight::areaType ); + p2->addEnumValue( "Rectangular", Rectangular ); + p2->addEnumValue( "Circular", Circular ); + s_pMetaObject->addProperty( p2 ); + + s_pMetaObject->addProperty( + new PMLightProperty( "axis1", &PMLight::setAxis1, &PMLight::axis1 ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "axis2", &PMLight::setAxis2, &PMLight::axis2 ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "adaptive", &PMLight::setAdaptive, &PMLight::adaptive ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "orient", &PMLight::setOrient, &PMLight::orient ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "jitter", &PMLight::setJitter, &PMLight::jitter ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "fading", &PMLight::setFading, &PMLight::fading ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "fadeDistance", &PMLight::setFadeDistance, &PMLight::fadeDistance ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "fadePower", &PMLight::setFadePower, &PMLight::fadePower ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "mediaInteraction", &PMLight::setMediaInteraction, + &PMLight::mediaInteraction ) ); + s_pMetaObject->addProperty( + new PMLightProperty( "mediaAttenuation", &PMLight::setMediaAttenuation, + &PMLight::mediaAttenuation ) ); + } + return s_pMetaObject; +} + +void PMLight::setLocation( const PMVector& p ) +{ + if( p != m_location ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMLocationID, m_location ); + m_location = p; + m_location.resize( 3 ); + setViewStructureChanged( ); + } +} + +void PMLight::setColor( const PMColor& c ) +{ + if( c != m_color ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMColorID, m_color ); + m_color = c; + } +} + +void PMLight::setLightType( PMLightType t ) +{ + if( t != m_type ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMTypeID, m_type ); + m_type = t; + setViewStructureChanged( ); + } +} + +void PMLight::setRadius( double r ) +{ + if( !approx( r, m_radius ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius ); + m_radius = r; + setViewStructureChanged( ); + } +} + +void PMLight::setFalloff( double f ) +{ + if( !approx( f, m_falloff ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFalloffID, m_falloff ); + m_falloff = f; + setViewStructureChanged( ); + } +} + +void PMLight::setTightness( double t ) +{ + if( !approx( t, m_tightness ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMTightnessID, m_tightness ); + m_tightness = t; + } +} + +void PMLight::setPointAt( const PMVector& v ) +{ + if( !m_pointAt.approxEqual( v ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMPointAtID, m_pointAt ); + m_pointAt = v; + setViewStructureChanged( ); + } +} + +void PMLight::setParallel( bool p ) +{ + if ( p != m_parallel ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMParallelID, m_parallel ); + m_parallel = p; + } +} + +void PMLight::setAreaLight( bool yes ) +{ + if( yes != m_bAreaLight ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaLightID, m_bAreaLight ); + m_bAreaLight = yes; + setViewStructureChanged( ); + } +} + +void PMLight::setAreaType( PMAreaType at ) +{ + if ( at != m_areaType ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaTypeID, m_areaType ); + m_areaType = at; + setViewStructureChanged( ); + } +} + +void PMLight::setAxis1( const PMVector& v ) +{ + if( !m_areaAxis1.approxEqual( v ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaAxis1ID, m_areaAxis1 ); + m_areaAxis1 = v; + setViewStructureChanged( ); + } +} + +void PMLight::setAxis2( const PMVector& v ) +{ + if( !m_areaAxis2.approxEqual( v ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaAxis2ID, m_areaAxis2 ); + m_areaAxis2 = v; + setViewStructureChanged( ); + } +} + +void PMLight::setSize1( int s ) +{ + if( s != m_areaSize1 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaSize1ID, m_areaSize1 ); + m_areaSize1 = s; + setViewStructureChanged( ); + } +} + +void PMLight::setSize2( int s ) +{ + if( s != m_areaSize2 ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAreaSize2ID, m_areaSize2 ); + m_areaSize2 = s; + setViewStructureChanged( ); + } +} + +void PMLight::setAdaptive( int a ) +{ + if( a != m_adaptive ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAdaptiveID, m_adaptive ); + m_adaptive = a; + } +} + +void PMLight::setOrient( bool o ) +{ + if( o != m_orient ) + { + if ( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMOrientID, m_orient ); + m_orient = o; + setViewStructureChanged( ); + } +} + +void PMLight::setJitter( bool j ) +{ + if( j != m_jitter ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMJitterID, m_jitter ); + m_jitter = j; + } +} + +void PMLight::setFading( bool y ) +{ + if( y != m_bFading ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFadingID, m_bFading ); + m_bFading = y; + } +} + +void PMLight::setFadeDistance( double d ) +{ + if( !approx( d, m_fadeDistance ) ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFadeDistanceID, m_fadeDistance ); + m_fadeDistance = d; + } +} + +void PMLight::setFadePower( int p ) +{ + if( p != m_fadePower ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMFadePowerID, m_fadePower ); + m_fadePower = p; + } +} + +void PMLight::setMediaInteraction( bool y ) +{ + if( y != m_bMediaInteraction ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMInteractionID, m_bMediaInteraction ); + m_bMediaInteraction = y; + } +} + +void PMLight::setMediaAttenuation( bool y ) +{ + if( y != m_bMediaAttenuation ) + { + if( m_pMemento ) + m_pMemento->addData( s_pMetaObject, PMAttenuationID, m_bMediaAttenuation ); + m_bMediaAttenuation = y; + } +} + +PMDialogEditBase* PMLight::editWidget( QWidget* parent ) const +{ + return new PMLightEdit( parent ); +} + +void PMLight::restoreMemento( PMMemento* s ) +{ + PMMementoDataIterator it( s ); + PMMementoData* data; + + for( ; it.current( ); ++it ) + { + data = it.current( ); + if( data->objectType( ) == s_pMetaObject ) + { + switch( data->valueID( ) ) + { + case PMLocationID: + setLocation( data->vectorData( ) ); + break; + case PMColorID: + setColor( data->colorData( ) ); + break; + case PMTypeID: + setLightType( ( PMLightType ) ( data->intData( ) ) ); + break; + case PMRadiusID: + setRadius( data->doubleData( ) ); + break; + case PMFalloffID: + setFalloff( data->doubleData( ) ); + break; + case PMTightnessID: + setTightness( data->doubleData( ) ); + break; + case PMPointAtID: + setPointAt( data->vectorData( ) ); + break; + case PMParallelID: + setParallel( data->boolData( ) ); + break; + case PMAreaLightID: + setAreaLight( data->boolData( ) ); + break; + case PMAreaTypeID: + setAreaType( ( PMAreaType ) ( data->intData( ) ) ); + break; + case PMAreaAxis1ID: + setAxis1( data->vectorData( ) ); + break; + case PMAreaAxis2ID: + setAxis2( data->vectorData( ) ); + break; + case PMAreaSize1ID: + setSize1( data->intData( ) ); + break; + case PMAreaSize2ID: + setSize2( data->intData( ) ); + break; + case PMAdaptiveID: + setAdaptive( data->intData( ) ); + break; + case PMOrientID: + setOrient( data->boolData( ) ); + break; + case PMJitterID: + setJitter( data->boolData( ) ); + break; + case PMFadingID: + setFading( data->boolData( ) ); + break; + case PMFadeDistanceID: + setFadeDistance( data->doubleData( ) ); + break; + case PMFadePowerID: + setFadePower( data->intData( ) ); + break; + case PMInteractionID: + setMediaInteraction( data->boolData( ) ); + break; + case PMAttenuationID: + setMediaAttenuation( data->boolData( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMLight::restoreMemento\n"; + break; + } + } + } + Base::restoreMemento( s ); +} + +void PMLight::createViewStructure( ) +{ + if( ( m_type == PointLight ) || ( m_type == ShadowlessLight ) ) + { + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultPointStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + else + { + m_pViewStructure->points( ).resize( + defaultPointStructure( )->points( ).size( ) ); + m_pViewStructure->lines( ) = defaultPointStructure( )->lines( ); + } + + PMPointArray& points = m_pViewStructure->points( ); + + int i; + double c = s_pointLightSize / sqrt( 3.0 ); + for( i = 0; i < 14; i++ ) + points[i] = PMPoint( m_location ); + + points[0][0] += s_pointLightSize; + points[1][0] -= s_pointLightSize; + points[2][1] += s_pointLightSize; + points[3][1] -= s_pointLightSize; + points[4][2] += s_pointLightSize; + points[5][2] -= s_pointLightSize; + + for( i = 0; i < 4; i++ ) + { + points[6+2*i][0] += c; + points[6+2*i][1] += ( i & 1 ? c : -c ); + points[6+2*i][2] += ( i & 2 ? c : -c ); + points[7+2*i][0] -= c; + points[7+2*i][1] -= ( i & 1 ? c : -c ); + points[7+2*i][2] -= ( i & 2 ? c : -c ); + } + } + else if( m_type == SpotLight ) + { + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultSpotStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + else + { + m_pViewStructure->points( ).resize( + defaultSpotStructure( )->points( ).size( ) ); + m_pViewStructure->lines( ) = defaultSpotStructure( )->lines( ); + } + + PMPointArray& points = m_pViewStructure->points( ); + + points[0] = PMPoint( m_location ); + + PMVector pointAtVector = m_pointAt - m_location; + double pl = pointAtVector.abs( ); + if( approxZero( pl ) ) + pointAtVector = PMVector( 0.0, 0.0, 1.0 ); + else + pointAtVector /= pl; + PMVector endPoint = pointAtVector.orthogonal( ); + PMMatrix rotation = PMMatrix::rotation( pointAtVector, + 2 * M_PI / s_nSpotLines ); + double length, r1, r2, a1, a2; + length = s_length; + a1 = m_radius; + a2 = m_falloff; + if( a1 < 0 ) a1 = 0; + if( a2 < 0 ) a2 = 0; + if( a1 > a2 ) a1 = a2; + if( a1 >= 89.9 ) a1 = 89.9; + if( a2 >= 89.9 ) a2 = 89.9; + a1 *= M_PI / 180; + a2 *= M_PI / 180; + r1 = tan( a1 ) * length; + r2 = tan( a2 ) * length; + + if( r2 > length ) + { + double d = length / r2; + r1 *= d; + r2 *= d; + length *= d; + } + + endPoint *= r2; + double r; + if( approxZero( r2 ) ) + r = 1; + else + r = r1 / r2; + + PMVector circleCenter = m_location + length * pointAtVector; + points[1] = PMPoint( circleCenter + endPoint ); + points[s_nSpotLines + 1] = PMPoint( circleCenter + endPoint * r ); + + int i; + for( i = 2; i < ( s_nSpotLines + 1 ); i++ ) + { + endPoint = rotation * endPoint; + points[i] = PMPoint( circleCenter + endPoint ); + points[s_nSpotLines + i] = PMPoint( circleCenter + endPoint * r ); + } + points[s_nSpotLines*2+1] = m_pointAt; + } + else if( m_type == CylinderLight ) + { + if( !m_pViewStructure ) + { + m_pViewStructure = new PMViewStructure( defaultCylindricalStructure( ) ); + m_pViewStructure->points( ).detach( ); + } + else + { + m_pViewStructure->points( ).resize( + defaultCylindricalStructure( )->points( ).size( ) ); + m_pViewStructure->lines( ) = defaultCylindricalStructure( )->lines( ); + } + + PMPointArray& points = m_pViewStructure->points( ); + + points[s_nCylinderLines*4] = PMPoint( m_location ); + points[s_nCylinderLines*4+1] = PMPoint( m_pointAt ); + + PMVector pointAtVector = m_pointAt - m_location; + double pl = pointAtVector.abs( ); + if( approxZero( pl ) ) + pointAtVector = PMVector( 0.0, 0.0, 1.0 ); + else + pointAtVector /= pl; + PMVector endPoint = pointAtVector.orthogonal( ); + PMMatrix rotation = PMMatrix::rotation( pointAtVector, + 2 * M_PI / s_nCylinderLines ); + double r1, r2; + r1 = m_radius / 100; + r2 = m_falloff / 100; + if( r1 < 0 ) r1 = 0; + if( r2 < 0 ) r2 = 0; + if( r1 > r2 ) r1 = r2; + + endPoint *= r2; + double r; + if( approxZero( r2 ) ) + r = 1; + else + r = r1 / r2; + + PMVector circleCenter = m_location + s_length * pointAtVector; + points[0] = PMPoint( circleCenter + endPoint ); + points[s_nCylinderLines] = PMPoint( m_location + endPoint ); + points[2*s_nCylinderLines] = PMPoint( circleCenter + endPoint * r ); + points[3*s_nCylinderLines] = PMPoint( m_location + endPoint * r ); + + int i; + for( i = 1; i < s_nCylinderLines; i++ ) + { + endPoint = rotation * endPoint; + points[i] = PMPoint( circleCenter + endPoint ); + points[s_nCylinderLines + i] = PMPoint( m_location + endPoint ); + points[2*s_nCylinderLines + i] = PMPoint( circleCenter + endPoint * r ); + points[3*s_nCylinderLines + i] = PMPoint( m_location + endPoint * r ); + } + } + + if( m_bAreaLight ) + { + int s1, s2; + + s1 = m_areaSize1; + s2 = m_areaSize2; + if( s1 < 1 ) s1 = 1; + if( s2 < 1 ) s2 = 1; + + if( ( s1 > 1 ) || ( s2 > 1 ) ) + { + int x, y, h; + int ps, ls; + PMVector bp; + + PMPointArray& points = m_pViewStructure->points( ); + PMLineArray& lines = m_pViewStructure->lines( ); + points.detach( ); + lines.detach( ); + + ps = points.size( ); + ls = lines.size( ); + points.resize( ps + s1*s2 ); + lines.resize( ls + s1*(s2-1) + s2*(s1-1) ); + + if( s1 == 1 ) + { + bp = m_location - m_areaAxis2/2; + for( y = 0; y < s2; y++ ) + points[ps + y] = PMPoint( bp + m_areaAxis2 + * ( (double)y/(double)(s2-1) ) ); + for( y = 0; y < ( s2-1 ); y++ ) + lines[ls+y] = PMLine( ps + y, ps + y+1 ); + } + else if( s2 == 1 ) + { + bp = m_location - m_areaAxis1/2; + for( x = 0; x < s1; x++ ) + points[ps + x] = PMPoint( bp + m_areaAxis1 + * ( (double)x/(double)(s1-1) ) ); + for( x = 0; x < ( s1-1 ); x++ ) + lines[ls+x] = PMLine( ps + x, ps + x+1 ); + } + else + { + bp = m_location - m_areaAxis1/2 - m_areaAxis2/2; + + if ( m_areaType == Rectangular || s1 < 2 || s2 < 2 ) + { + for( x = 0; x < s1; x++ ) + for( y = 0; y < s2; y++ ) + points[ps + y*s1 + x] = + PMPoint( bp + m_areaAxis1 * ( (double)x/(double)(s1-1) ) + + m_areaAxis2 * ( (double)y/(double)(s2-1) ) ); + } + else + { + double stepX = ( 2.0 / (double)(s1-1) ); + double stepY = ( 2.0 / (double)(s2-1) ); + double doubleX, doubleY, xSqr, scaleFactor; + + for ( x = 0; x < s1; ++x ) + { + doubleX = ( (double)x * stepX ) - 1.0; + xSqr = doubleX * doubleX; + for ( y = 0; y < s2; ++y ) + { + doubleY = ( (double)y * stepY ) - 1.0; + + if ( doubleX == 0.0 && doubleY == 0.0 ) + scaleFactor = 1.0; + else + { + if ( fabs( doubleX ) > fabs( doubleY ) ) + scaleFactor = fabs( doubleX ); + else + scaleFactor = fabs( doubleY ); + scaleFactor /= sqrt( xSqr + doubleY * doubleY ); + } + + points[ps + y*s1 + x] = + PMPoint( bp + m_areaAxis1 * + ( ( ( doubleX * scaleFactor ) / 2.0 ) + 0.5 ) + + m_areaAxis2 * + ( ( ( doubleY * scaleFactor ) / 2.0 ) + 0.5 ) ); + } + } + } + + for( x = 0; x < s1; x++ ) + { + for( y = 0; y < (s2-1); y++ ) + { + h = ps + x + s1*y; + lines[ls + x*(s2-1) + y] = PMLine( h, h+s1 ); + } + } + + ls += s1*(s2-1); + for( y = 0; y < s2; y++ ) + { + for( x = 0; x < (s1-1); x++ ) + { + h = ps + x + s1*y; + lines[ls + y*(s1-1) + x] = PMLine( h, h+1 ); + } + } + } + } + } +} + +PMViewStructure* PMLight::defaultPointStructure( ) const +{ + if( !s_pDefaultPointStructure ) + { + s_pDefaultPointStructure = new PMViewStructure( 14, 7 ); +// PMPointArray& points = s_pDefaultPointStructure->points( ); + PMLineArray& lines = s_pDefaultPointStructure->lines( ); + + lines[0] = PMLine( 0, 1 ); + lines[1] = PMLine( 2, 3 ); + lines[2] = PMLine( 4, 5 ); + lines[3] = PMLine( 6, 7 ); + lines[4] = PMLine( 8, 9 ); + lines[5] = PMLine( 10, 11 ); + lines[6] = PMLine( 12, 13 ); + } + return s_pDefaultPointStructure; +} + +PMViewStructure* PMLight::defaultSpotStructure( ) const +{ + if( !s_pDefaultSpotStructure ) + { + s_pDefaultSpotStructure = new PMViewStructure( s_nSpotLines * 2 + 2, s_nSpotLines * 3 + 1 ); +// PMPointArray& points = s_pDefaultSpotStructure->points( ); + PMLineArray& lines = s_pDefaultSpotStructure->lines( ); + + int i; + for( i = 0; i < s_nSpotLines; i++ ) + { + lines[i] = PMLine( 0, i+1 ); + lines[s_nSpotLines + i] = PMLine( i+1, i+2 ); + lines[2*s_nSpotLines + i] = PMLine( s_nSpotLines + i+1, + s_nSpotLines + i+2 ); + } + // fix for the last line + lines[2*s_nSpotLines - 1] = PMLine( 1, s_nSpotLines ); + lines[3*s_nSpotLines - 1] = PMLine( s_nSpotLines + 1, s_nSpotLines*2 ); + lines[3*s_nSpotLines] = PMLine( 0, s_nSpotLines*2 + 1 ); + } + return s_pDefaultSpotStructure; +} + +PMViewStructure* PMLight::defaultCylindricalStructure( ) const +{ + if( !s_pDefaultCylindricalStructure ) + { + s_pDefaultCylindricalStructure = new PMViewStructure( s_nCylinderLines * 4 + 2, s_nCylinderLines * 5 + 1 ); +// PMPointArray& points = s_pDefaultCylindricalStructure->points( ); + PMLineArray& lines = s_pDefaultCylindricalStructure->lines( ); + + int i; + for( i = 0; i < s_nCylinderLines; i++ ) + { + lines[i] = PMLine( i, i+1 ); + lines[s_nCylinderLines + i] = PMLine( i + s_nCylinderLines, + i + s_nCylinderLines + 1 ); + lines[2*s_nCylinderLines + i] = PMLine( i + 2*s_nCylinderLines, + i + 2*s_nCylinderLines + 1 ); + lines[3*s_nCylinderLines + i] = PMLine( i + 3*s_nCylinderLines, + i + 3*s_nCylinderLines + 1 ); + lines[4*s_nCylinderLines + i] = PMLine( i, i + s_nCylinderLines ); + } + // fix for some lines + lines[s_nCylinderLines-1] = PMLine( 0, s_nCylinderLines - 1 ); + lines[2*s_nCylinderLines-1] = PMLine( s_nCylinderLines, + 2*s_nCylinderLines - 1 ); + lines[3*s_nCylinderLines-1] = PMLine( 2*s_nCylinderLines, + 3*s_nCylinderLines - 1 ); + lines[4*s_nCylinderLines-1] = PMLine( 3*s_nCylinderLines, + 4*s_nCylinderLines - 1 ); + lines[5*s_nCylinderLines] = PMLine( 4*s_nCylinderLines, + 4*s_nCylinderLines + 1 ); + } + return s_pDefaultCylindricalStructure; +} + +void PMLight::controlPoints( PMControlPointList& list ) +{ + list.append( new PM3DControlPoint( m_location, PMLocationID, i18n( "Location" ) ) ); + if( ( m_type == SpotLight ) || ( m_type == CylinderLight ) ) + list.append( new PM3DControlPoint( m_pointAt, PMPointAtID, i18n( "Point at" ) ) ); +} + +void PMLight::controlPointsChanged( PMControlPointList& list ) +{ + PMControlPoint* p; + + for( p = list.first( ); p; p = list.next( ) ) + { + if( p->changed( ) ) + { + switch( p->id( ) ) + { + case PMLocationID: + setLocation( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + case PMPointAtID: + setPointAt( ( ( PM3DControlPoint* ) p )->point( ) ); + break; + default: + kdError( PMArea ) << "Wrong ID in PMLight::controlPointsChanged\n"; + break; + } + } + } +} + +void PMLight::cleanUp( ) const +{ + if( s_pDefaultPointStructure ) + delete s_pDefaultPointStructure; + s_pDefaultPointStructure = 0; + if( s_pDefaultSpotStructure ) + delete s_pDefaultSpotStructure; + s_pDefaultSpotStructure = 0; + if( s_pDefaultCylindricalStructure ) + delete s_pDefaultCylindricalStructure; + s_pDefaultCylindricalStructure = 0; + if( s_pMetaObject ) + { + delete s_pMetaObject; + s_pMetaObject = 0; + } + Base::cleanUp( ); +} |