You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kpovmodeler/pmlight.cpp

1065 lines
32 KiB

/*
**************************************************************************
description
--------------------
copyright : (C) 2000-2002 by Andreas Zehender
email : zehender@kde.org
**************************************************************************
**************************************************************************
* *
* 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 <tdelocale.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( )
{
}
TQString PMLight::description( ) const
{
return i18n( "light" );
}
void PMLight::serialize( TQDomElement& e, TQDomDocument& 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 )
{
TQString 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( TQWidget* 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( );
}