Update suitable examples and tests to use blank mode
[shapes.git] / source / lighttypes.cc
blobb70aa6782b2bef05a3f792e487c97d811211b498
1 /* This file is part of Shapes.
3 * Shapes is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * any later version.
8 * Shapes is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright 2008 Henrik Tidefelt
19 #include <cmath>
21 #include "lighttypes.h"
22 #include "astclass.h"
23 #include "globals.h"
24 #include "constructorrepresentation.h"
26 using namespace Shapes;
29 Lang::SpecularReflection::SpecularReflection( )
30 { }
32 Lang::SpecularReflection::~SpecularReflection( )
33 { }
35 DISPATCHIMPL( SpecularReflection );
37 RefCountPtr< const Lang::Class > Lang::SpecularReflection::TypeID( new Lang::SystemFinalClass( strrefdup( "SpecularReflection" ) ) );
38 TYPEINFOIMPL( SpecularReflection );
40 void
41 Lang::SpecularReflection::gcMark( Kernel::GCMarkedSet & marked )
42 { }
44 Lang::SpecularReflectionTerm::SpecularReflectionTerm( double weight, double exponent )
45 : weight_( weight ), exponent_( exponent )
46 { }
48 Lang::SpecularReflectionTerm::~SpecularReflectionTerm( )
49 { }
51 double
52 Lang::SpecularReflectionTerm::weight( ) const
54 return weight_;
57 RefCountPtr< const Lang::SpecularReflection >
58 Lang::SpecularReflectionTerm::multiply( double scalar ) const
60 return RefCountPtr< const Lang::SpecularReflection >( new Lang::SpecularReflectionTerm( scalar * weight_, exponent_ ) );
64 Concrete::Gray
65 Lang::SpecularReflectionTerm::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::GrayLight & light ) const
67 return light.illuminateGray( point, eyez, unitNormal, *this );
70 Concrete::RGB
71 Lang::SpecularReflectionTerm::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::RGBLight & light ) const
73 return light.illuminateRGB( point, eyez, unitNormal, *this );
76 Concrete::Gray
77 Lang::SpecularReflectionTerm::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Concrete::Gray & autoIntensity ) const
79 // According to my calculations, the autoIntensity seen by the eye does not change with the distance to the object;
80 // one the size of the object changes, which will make the received power decrease with distance.
81 return Concrete::Gray( weight_ * pow( fabs( Concrete::inner( unitNormal, ( Concrete::Coords3D( 0, 0, eyez ) - point ).direction( ) ) ), exponent_ ) * autoIntensity.gr_ );
84 Concrete::RGB
85 Lang::SpecularReflectionTerm::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Concrete::RGB & autoIntensity ) const
87 // According to my calculations, the autoIntensity seen by the eye does not change with the distance to the object;
88 // one the size of the object changes, which will make the received power decrease with distance.
89 double a = weight_ * pow( fabs( Concrete::inner( unitNormal, ( Concrete::Coords3D( 0, 0, eyez ) - point ).direction( ) ) ), exponent_ );
90 return Concrete::RGB( a * autoIntensity.r_, a * autoIntensity.g_, a * autoIntensity.b_ );
93 double
94 Lang::SpecularReflectionTerm::exponent( ) const
96 return exponent_;
100 Lang::SpecularReflectionNull::SpecularReflectionNull( )
103 Lang::SpecularReflectionNull::~SpecularReflectionNull( )
106 double
107 Lang::SpecularReflectionNull::weight( ) const
109 return 0.;
112 RefCountPtr< const Lang::SpecularReflection >
113 Lang::SpecularReflectionNull::multiply( double scalar ) const
115 return Lang::THE_SPECULARREFLECTION_NULL;
118 Concrete::Gray
119 Lang::SpecularReflectionNull::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::GrayLight & light ) const
121 return Concrete::Gray( 0. );
124 Concrete::RGB
125 Lang::SpecularReflectionNull::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::RGBLight & light ) const
127 return Concrete::RGB( 0., 0., 0. );
130 Concrete::Gray
131 Lang::SpecularReflectionNull::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Concrete::Gray & autoIntensity ) const
133 return Concrete::Gray( 0. );
136 Concrete::RGB
137 Lang::SpecularReflectionNull::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Concrete::RGB & autoIntensity ) const
139 return Concrete::RGB( 0., 0., 0. );
143 Lang::SpecularReflectionPair::SpecularReflectionPair( const RefCountPtr< const Lang::SpecularReflection > & car, const RefCountPtr< const Lang::SpecularReflection > & cdr )
144 : car_( car ), cdr_( cdr )
147 Lang::SpecularReflectionPair::~SpecularReflectionPair( )
150 double
151 Lang::SpecularReflectionPair::weight( ) const
153 return car_->weight( ) + cdr_->weight( );
156 RefCountPtr< const Lang::SpecularReflection >
157 Lang::SpecularReflectionPair::multiply( double scalar ) const
159 return RefCountPtr< const Lang::SpecularReflection >
160 ( new Lang::SpecularReflectionPair( car_->multiply( scalar ), cdr_->multiply( scalar ) ) );
164 Concrete::Gray
165 Lang::SpecularReflectionPair::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::GrayLight & light ) const
167 return car_->illuminate( point, eyez, unitNormal, light ).addNoCheck( cdr_->illuminate( point, eyez, unitNormal, light ) );
170 Concrete::RGB
171 Lang::SpecularReflectionPair::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::RGBLight & light ) const
173 return car_->illuminate( point, eyez, unitNormal, light ).addNoCheck( cdr_->illuminate( point, eyez, unitNormal, light ) );
176 Concrete::Gray
177 Lang::SpecularReflectionPair::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Concrete::Gray & autoIntensity ) const
179 return car_->illuminate( point, eyez, unitNormal, autoIntensity ).addNoCheck( cdr_->illuminate( point, eyez, unitNormal, autoIntensity ) );
182 Concrete::RGB
183 Lang::SpecularReflectionPair::illuminate( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Concrete::RGB & autoIntensity ) const
185 return car_->illuminate( point, eyez, unitNormal, autoIntensity ).addNoCheck( cdr_->illuminate( point, eyez, unitNormal, autoIntensity ) );
189 Lang::LightSource::LightSource( bool shadows )
190 : shadows_( shadows )
193 DISPATCHIMPL( LightSource );
195 RefCountPtr< const Lang::Class > Lang::LightSource::TypeID( new Lang::SystemFinalClass( strrefdup( "LightSource" ) ) );
196 TYPEINFOIMPL( LightSource );
198 Lang::LightSource::~LightSource( )
201 RefCountPtr< const Lang::Geometric3D >
202 Lang::LightSource::transformed( const Lang::Transform3D & tf, const RefCountPtr< const Lang::Geometric3D > & self ) const
204 return typed_transformed( tf );
207 RefCountPtr< const Lang::Geometric2D >
208 Lang::LightSource::to2D( const Kernel::PassedDyn & dyn, const RefCountPtr< const Lang::Geometric3D > & self ) const
210 throw Exceptions::MiscellaneousRequirement( "A LightSource cannot be viewed in 2D." );
213 void
214 Lang::LightSource::gcMark( Kernel::GCMarkedSet & marked )
218 Lang::GrayLight::GrayLight( bool shadows )
219 : Lang::LightSource( shadows )
222 Lang::GrayLight::~GrayLight( )
226 Lang::RGBLight::RGBLight( bool shadows )
227 : Lang::LightSource( shadows )
230 Lang::RGBLight::~RGBLight( )
234 Lang::AmbientLightGray::AmbientLightGray( const Concrete::Gray & intensity )
235 : Lang::GrayLight( false ), intensity_( intensity )
238 Lang::AmbientLightGray::~AmbientLightGray( )
241 RefCountPtr< const Lang::LightSource >
242 Lang::AmbientLightGray::typed_transformed( const Lang::Transform3D & tf ) const
244 // It's sad that we don't have access to the self reference, so that it could be returned instead of a new object with is just a copy of ourselves.
245 return RefCountPtr< const Lang::LightSource >( new Lang::AmbientLightGray( intensity_ ) );
248 Concrete::RGB
249 Lang::AmbientLightGray::illuminateRGB( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::SpecularReflectionTerm & refl ) const
251 double a = intensity_.gr_ * refl.weight( );
252 return Concrete::RGB( a, a, a );
255 Concrete::Gray
256 Lang::AmbientLightGray::illuminateGray( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::SpecularReflectionTerm & refl ) const
258 return Concrete::Gray( intensity_.gr_ * refl.weight( ) );
261 Lang::AmbientLightRGB::AmbientLightRGB( const Concrete::RGB & intensity )
262 : Lang::RGBLight( false ), intensity_( intensity )
265 Lang::AmbientLightRGB::~AmbientLightRGB( )
268 RefCountPtr< const Lang::LightSource >
269 Lang::AmbientLightRGB::typed_transformed( const Lang::Transform3D & tf ) const
271 return RefCountPtr< const Lang::LightSource >( new Lang::AmbientLightRGB( intensity_ ) );
274 Concrete::RGB
275 Lang::AmbientLightRGB::illuminateRGB( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::SpecularReflectionTerm & refl ) const
277 const double w = refl.weight( );
278 return Concrete::RGB( intensity_.r_ * w, intensity_.g_ * w, intensity_.b_ * w );
281 Lang::SpecularLightGray::SpecularLightGray( const Concrete::Coords3D & p, const Concrete::Gray & intensity, Concrete::Length intensityRadius, bool shadows )
282 : Lang::GrayLight( shadows ), p_( p ), intensity_( intensity ), intensityRadius_( intensityRadius )
285 Lang::SpecularLightGray::~SpecularLightGray( )
288 RefCountPtr< const Lang::LightSource >
289 Lang::SpecularLightGray::typed_transformed( const Lang::Transform3D & tf ) const
291 return RefCountPtr< const Lang::LightSource >( new Lang::SpecularLightGray( p_.transformed( tf ), intensity_, intensityRadius_, shadows_ ) );
294 Concrete::RGB
295 Lang::SpecularLightGray::illuminateRGB( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::SpecularReflectionTerm & refl ) const
297 // Refer to SpecularLightGray::illuminateGray for comments regarding this code.
298 // This function shall be analogous to that function.
300 Concrete::Coords3D rLight = p_ - point;
301 Concrete::Coords3D rEye = Concrete::Coords3D( Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH, eyez ) - point;
302 Concrete::Length dLight = rLight.norm( );
303 Concrete::Length dEye = rEye.norm( );
304 Concrete::UnitFloatTriple rHatLight = rLight.direction( dLight );
305 Concrete::UnitFloatTriple rHatEye = rEye.direction( dEye );
306 Concrete::Length dTot = dLight + dEye;
308 Concrete::UnitFloatTriple rHatReflection = unitNormal.reflect( rHatLight );
310 // This breaks the Phong model, but I want reflection in all directions!
311 // ... as long as the light and the eye are on the same side of the surface!
312 if( ( Concrete::inner( unitNormal, rHatEye ) > 0 ) != ( Concrete::inner( unitNormal, rHatLight ) > 0 ) )
314 return Concrete::RGB( 0, 0, 0 );
316 const double cPhong2 = cos( 0.5 * acos( Concrete::inner( rHatReflection, rHatEye ) ) );
318 // Just in case numeric errors make c negative anyway...
319 if( cPhong2 <= 0 )
321 return Concrete::RGB( 0, 0, 0 );
324 // Further, I want something that becomes ambient when refl.exponent == 0.
326 double cAmb = 1;
327 if( refl.exponent( ) < 1 )
329 cAmb = pow( fabs( Concrete::inner( unitNormal, rHatLight ) ), 1 - refl.exponent( ) );
332 double rRel = 1;
333 if( intensityRadius_ < Concrete::HUGE_LENGTH )
335 rRel = intensityRadius_ / dTot;
338 double a = intensity_.mulNoCheck( refl.weight( ) * pow( cPhong2, refl.exponent( ) ) * cAmb * rRel * rRel ).gr_;
339 return Concrete::RGB( a, a, a );
342 Concrete::Gray
343 Lang::SpecularLightGray::illuminateGray( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::SpecularReflectionTerm & refl ) const
345 Concrete::Coords3D rLight = p_ - point;
346 Concrete::Coords3D rEye = Concrete::Coords3D( Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH, eyez ) - point;
347 Concrete::Length dLight = rLight.norm( );
348 Concrete::Length dEye = rEye.norm( );
349 Concrete::UnitFloatTriple rHatLight = rLight.direction( dLight );
350 Concrete::UnitFloatTriple rHatEye = rEye.direction( dEye );
351 Concrete::Length dTot = dLight + dEye;
353 Concrete::UnitFloatTriple rHatReflection = unitNormal.reflect( rHatLight );
355 // std::cerr << "Point: " << Helpers::shapesFormat( point ) << std::endl ;
356 // std::cerr << "rLight: " << Helpers::shapesFormat( rLight ) << std::endl ;
357 // std::cerr << "Surface normal: " << Helpers::shapesFormat( unitNormal ) << std::endl ;
358 // std::cerr << "rHatReflection: " << Helpers::shapesFormat( rHatReflection ) << std::endl ;
359 // std::cerr << "rEye: " << Helpers::shapesFormat( rEye ) << std::endl ;
360 // std::cerr << "rHatEye: " << Helpers::shapesFormat( rHatEye ) << std::endl ;
361 // std::cerr << "Phong's angle: " << acos( Concrete::inner( rHatReflection, rHatEye ) ) << std::endl ;
363 // This breaks the Phong model, but I want reflection in all directions!
364 // ... as long as the light and the eye are on the same side of the surface!
365 if( ( Concrete::inner( unitNormal, rHatEye ) > 0 ) != ( Concrete::inner( unitNormal, rHatLight ) > 0 ) )
367 return Concrete::Gray( 0 );
369 const double cPhong2 = cos( 0.5 * acos( Concrete::inner( rHatReflection, rHatEye ) ) );
371 // Just in case numeric errors make c negative anyway...
372 if( cPhong2 <= 0 )
374 return Concrete::Gray( 0 );
377 // Further, I want something that becomes ambient when refl.exponent == 0.
379 double cAmb = 1;
380 if( refl.exponent( ) < 1 )
382 cAmb = pow( fabs( Concrete::inner( unitNormal, rHatLight ) ), 1 - refl.exponent( ) );
385 double rRel = 1;
386 if( intensityRadius_ < Concrete::HUGE_LENGTH )
388 rRel = intensityRadius_ / dTot;
391 // std::cerr << " Intensity: " << intensity_.gr_ << std::endl ;
392 // std::cerr << " Phong2: " << pow( cPhong2, refl.exponent( ) ) << std::endl ;
393 // std::cerr << " Amb2: " << pow( cIn, 1 / ( 1 + 10 * refl.exponent( ) ) ) << std::endl ;
394 // std::cerr << " Distance factor: " << rRel * rRel << std::endl ;
395 // std::cerr << " Total: " << refl.weight( ) * pow( c, refl.exponent( ) ) * rRel * rRel * intensity_.gr_ << std::endl ;
397 return intensity_.mulNoCheck( refl.weight( ) * pow( cPhong2, refl.exponent( ) ) * cAmb * rRel * rRel );
400 Lang::SpecularLightRGB::SpecularLightRGB( const Concrete::Coords3D & p, const Concrete::RGB & intensity, Concrete::Length intensityRadius, bool shadows )
401 : Lang::RGBLight( shadows ), p_( p ), intensity_( intensity ), intensityRadius_( intensityRadius )
404 Lang::SpecularLightRGB::~SpecularLightRGB( )
407 RefCountPtr< const Lang::LightSource >
408 Lang::SpecularLightRGB::typed_transformed( const Lang::Transform3D & tf ) const
410 return RefCountPtr< const Lang::LightSource >( new Lang::SpecularLightRGB( p_.transformed( tf ), intensity_, intensityRadius_, shadows_ ) );
413 Concrete::RGB
414 Lang::SpecularLightRGB::illuminateRGB( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::SpecularReflectionTerm & refl ) const
416 // Refer to SpecularLightGray::illuminateGray for comments regarding this code.
417 // This function shall be analogous to that function.
419 Concrete::Coords3D rLight = p_ - point;
420 Concrete::Coords3D rEye = Concrete::Coords3D( Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH, eyez ) - point;
421 Concrete::Length dLight = rLight.norm( );
422 Concrete::Length dEye = rEye.norm( );
423 Concrete::UnitFloatTriple rHatLight = rLight.direction( dLight );
424 Concrete::UnitFloatTriple rHatEye = rEye.direction( dEye );
425 Concrete::Length dTot = dLight + dEye;
427 Concrete::UnitFloatTriple rHatReflection = unitNormal.reflect( rHatLight );
429 // This breaks the Phong model, but I want reflection in all directions!
430 const double cPhong2 = cos( 0.5 * acos( Concrete::inner( rHatReflection, rHatEye ) ) );
432 // Just in case numeric errors make c negative anyway...
433 if( cPhong2 <= 0 )
435 return Concrete::RGB( 0, 0, 0 );
438 // Further, I want something that becomes ambient when refl.exponent == 0.
440 double cAmb = 1;
441 if( refl.exponent( ) < 1 )
443 cAmb = pow( fabs( Concrete::inner( unitNormal, rHatLight ) ), 1 - refl.exponent( ) );
446 double rRel = 1;
447 if( intensityRadius_ < Concrete::HUGE_LENGTH )
449 rRel = intensityRadius_ / dTot;
452 return intensity_.mulNoCheck( refl.weight( ) * pow( cPhong2, refl.exponent( ) ) * cAmb * rRel * rRel );
455 Lang::DistantLightGray::DistantLightGray( const Concrete::UnitFloatTriple & rHatLight, const Concrete::Gray & intensity, bool shadows )
456 : Lang::GrayLight( shadows ), rHatLight_( rHatLight ), intensity_( intensity )
459 Lang::DistantLightGray::~DistantLightGray( )
462 RefCountPtr< const Lang::LightSource >
463 Lang::DistantLightGray::typed_transformed( const Lang::Transform3D & tf ) const
465 return RefCountPtr< const Lang::LightSource >( new Lang::DistantLightGray( tf.transformPlaneUnitNormal( rHatLight_ ), intensity_, shadows_ ) );
468 Concrete::RGB
469 Lang::DistantLightGray::illuminateRGB( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::SpecularReflectionTerm & refl ) const
471 // Compare SpecularLightGray::illuminateGray.
473 Concrete::Coords3D rEye = Concrete::Coords3D( Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH, eyez ) - point;
474 Concrete::Length dEye = rEye.norm( );
475 Concrete::UnitFloatTriple rHatEye = rEye.direction( dEye );
477 Concrete::UnitFloatTriple rHatReflection = unitNormal.reflect( rHatLight_ );
479 // This breaks the Phong model, but I want reflection in all directions!
480 const double cPhong2 = cos( 0.5 * acos( Concrete::inner( rHatReflection, rHatEye ) ) );
482 // Just in case numeric errors make c negative anyway...
483 if( cPhong2 <= 0 )
485 return Concrete::RGB( 0, 0, 0 );
488 // Further, I want something that becomes ambient when refl.exponent == 0.
490 double cAmb = 1;
491 if( refl.exponent( ) < 1 )
493 cAmb = pow( fabs( Concrete::inner( unitNormal, rHatLight_ ) ), 1 - refl.exponent( ) );
496 double a = intensity_.mulNoCheck( refl.weight( ) * pow( cPhong2, refl.exponent( ) ) * cAmb ).gr_;
497 return Concrete::RGB( a, a, a );
500 Concrete::Gray
501 Lang::DistantLightGray::illuminateGray( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & unitNormal, const Lang::SpecularReflectionTerm & refl ) const
503 // Compare SpecularLightGray::illuminateGray.
505 Concrete::Coords3D rEye = Concrete::Coords3D( Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH, eyez ) - point;
506 Concrete::Length dEye = rEye.norm( );
507 Concrete::UnitFloatTriple rHatEye = rEye.direction( dEye );
509 Concrete::UnitFloatTriple rHatReflection = unitNormal.reflect( rHatLight_ );
511 // This breaks the Phong model, but I want reflection in all directions!
512 const double cPhong2 = cos( 0.5 * acos( Concrete::inner( rHatReflection, rHatEye ) ) );
514 // Just in case numeric errors make c negative anyway...
515 if( cPhong2 <= 0 )
517 return Concrete::Gray( 0 );
520 // Further, I want something that becomes ambient when refl.exponent == 0.
522 double cAmb = 1;
523 if( refl.exponent( ) < 1 )
525 cAmb = pow( fabs( Concrete::inner( unitNormal, rHatLight_ ) ), 1 - refl.exponent( ) );
528 return intensity_.mulNoCheck( refl.weight( ) * pow( cPhong2, refl.exponent( ) ) * cAmb );
532 Lang::DistantLightRGB::DistantLightRGB( const Concrete::UnitFloatTriple & rHatLight, const Concrete::RGB & intensity, bool shadows )
533 : Lang::RGBLight( shadows ), rHatLight_( rHatLight ), intensity_( intensity )
536 Lang::DistantLightRGB::~DistantLightRGB( )
539 RefCountPtr< const Lang::LightSource >
540 Lang::DistantLightRGB::typed_transformed( const Lang::Transform3D & tf ) const
542 return RefCountPtr< const Lang::LightSource >( new Lang::DistantLightRGB( tf.transformPlaneUnitNormal( rHatLight_ ), intensity_, shadows_ ) );
545 Concrete::RGB
546 Lang::DistantLightRGB::illuminateRGB( const Concrete::Coords3D & point, const Concrete::Length eyez, const Concrete::UnitFloatTriple & rHatLight, const Lang::SpecularReflectionTerm & refl ) const
548 // Compare SpecularLightGray::illuminateGray.
550 Concrete::Coords3D rEye = Concrete::Coords3D( Concrete::ZERO_LENGTH, Concrete::ZERO_LENGTH, eyez ) - point;
551 Concrete::Length dEye = rEye.norm( );
552 Concrete::UnitFloatTriple rHatEye = rEye.direction( dEye );
554 Concrete::UnitFloatTriple rHatReflection = rHatLight_.reflect( rHatLight_ );
556 // This breaks the Phong model, but I want reflection in all directions!
557 const double cPhong2 = cos( 0.5 * acos( Concrete::inner( rHatReflection, rHatEye ) ) );
559 // Just in case numeric errors make c negative anyway...
560 if( cPhong2 <= 0 )
562 return Concrete::RGB( 0, 0, 0 );
565 // Further, I want something that becomes ambient when refl.exponent == 0.
567 double cAmb = 1;
568 if( refl.exponent( ) < 1 )
570 cAmb = pow( fabs( Concrete::inner( rHatLight_, rHatLight_ ) ), 1 - refl.exponent( ) );
573 return intensity_.mulNoCheck( refl.weight( ) * pow( cPhong2, refl.exponent( ) ) * cAmb );
576 Lang::LightGroup::LightGroup( )
579 DISPATCHIMPL( LightGroup );
581 RefCountPtr< const Lang::Class > Lang::LightGroup::TypeID( new Lang::SystemFinalClass( strrefdup( "LightGroup" ) ) );
582 TYPEINFOIMPL( LightGroup );
584 Lang::LightGroup::~LightGroup( )
587 RefCountPtr< const Lang::Geometric3D >
588 Lang::LightGroup::transformed( const Lang::Transform3D & tf, const RefCountPtr< const Lang::Geometric3D > & self ) const
590 return typed_transformed( tf, self.down_cast< const Lang::LightGroup >( ) );
593 RefCountPtr< const Lang::Geometric2D >
594 Lang::LightGroup::to2D( const Kernel::PassedDyn & dyn, const RefCountPtr< const Lang::Geometric3D > & self ) const
596 throw Exceptions::MiscellaneousRequirement( "Lights cannot exist in 2D." );
600 Lang::LightNull::LightNull( )
603 Lang::LightNull::~LightNull( )
606 RefCountPtr< const Lang::LightGroup >
607 Lang::LightNull::typed_transformed( const Lang::Transform3D & tf, const RefCountPtr< const Lang::LightGroup > & self ) const
609 return self;
612 bool
613 Lang::LightNull::isNull( ) const
615 return true;
618 bool
619 Lang::LightNull::containsRGB( ) const
621 return false;
624 void
625 Lang::LightNull::gcMark( Kernel::GCMarkedSet & marked )
629 Lang::LightPair::LightPair( const RefCountPtr< const Lang::LightSource > & car, const RefCountPtr< const Lang::LightGroup > & cdr )
630 : car_( car ), cdr_( cdr )
633 Lang::LightPair::~LightPair( )
636 RefCountPtr< const Lang::LightSource >
637 Lang::LightPair::car( ) const
639 return car_;
642 RefCountPtr< const Lang::LightGroup >
643 Lang::LightPair::cdr( ) const
645 return cdr_;
648 RefCountPtr< const Lang::LightGroup >
649 Lang::LightPair::typed_transformed( const Lang::Transform3D & tf, const RefCountPtr< const Lang::LightGroup > & self ) const
651 return RefCountPtr< const Lang::LightGroup >( new Lang::LightPair( car_->typed_transformed( tf ), cdr_->typed_transformed( tf, cdr_ ) ) );
654 bool
655 Lang::LightPair::isNull( ) const
657 return false;
660 bool
661 Lang::LightPair::containsRGB( ) const
663 return ( ! car_->isGray( ) ) || cdr_->containsRGB( );
666 void
667 Lang::LightPair::gcMark( Kernel::GCMarkedSet & marked )
669 const_cast< Lang::LightSource * >( car_.getPtr( ) )->gcMark( marked );
670 const_cast< Lang::LightGroup * >( cdr_.getPtr( ) )->gcMark( marked );