Salome HOME
949d7d2b0a131b60048ca59bba95c705579702f6
[modules/geom.git] / src / Material / Material_Model.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library 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 GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File   : Material_Model.cxx
21 // Author : Margarita KARPUNINA, Open CASCADE S.A.S. (margarita.karpunina@opencascade.com)
22 //
23
24 #include "Material_Model.h"
25 #include "GEOM_VTKPropertyMaterial.hxx"
26 #include "Material_ResourceMgr.h"
27
28 #include <QMutexLocker>
29
30 /*!
31   \brief Constructor
32
33   Create new SALOME material model with default properties.
34 */
35 Material_Model::Material_Model()
36 {
37   myReflection  = ReflectionList(4);
38   init(); // set default properties
39 }
40
41 /*!
42   \brief Destructor
43 */
44 Material_Model::~Material_Model()
45 {
46 }
47
48 /*!
49   \brief Initialize material data from the given properties list
50   \param props material properties
51   \sa toProperties()
52 */
53 void Material_Model::fromProperties( const QString& props )
54 {
55   // reset to default values
56   init();
57
58   // parse material properties
59   QStringList propList = props.split( ":", QString::SkipEmptyParts );
60   foreach ( QString prop, propList ) 
61   {
62     QStringList pdata = prop.split( "=" );
63     if ( pdata.count() < 2 ) continue;
64     QString key   = pdata[0].trimmed().toLower();
65     QString data  = pdata[1].trimmed().toLower();
66     bool dblOk, boolOk;
67     double dblValue  = data.toDouble( &dblOk );
68     bool   boolValue = (bool)( data.toInt( &boolOk ) );
69     QColor colorValue;
70     
71     if      ( key == "ambientcolor" && Qtx::stringToColor( data, colorValue ) ) {
72       setColor( Ambient, colorValue );
73     }
74     else if ( key == "diffusecolor" && Qtx::stringToColor( data, colorValue ) ) {
75       setColor( Diffuse, colorValue );
76     }
77     else if ( key == "specularcolor" && Qtx::stringToColor( data, colorValue ) ) {
78       setColor( Specular, colorValue );
79     }
80     else if ( key == "emissivecolor" && Qtx::stringToColor( data, colorValue ) ) {
81       setColor( Emissive, colorValue );
82     }
83     else if ( key == "frontambientcoefficient" && dblOk ) {
84       setReflection( Ambient, dblValue );
85     }
86     else if ( key == "backambientcoefficient" && dblOk ) {
87       setReflection( Ambient, dblValue, false );
88     }
89     else if ( key == "frontdiffusecoefficient" && dblOk ) {
90       setReflection( Diffuse, dblValue );
91     }
92     else if ( key == "backdiffusecoefficient" && dblOk ) {
93       setReflection( Diffuse, dblValue, false );
94     }
95     else if ( key == "frontspecularcoefficient" && dblOk ) {
96       setReflection( Specular, dblValue );
97     }
98     else if ( key == "backspecularcoefficient" && dblOk ) {
99       setReflection( Specular, dblValue, false );
100     }
101     else if ( key == "frontemissivecoefficient" && dblOk ) {
102       setReflection( Emissive, dblValue );
103     }
104     else if ( key == "backemissivecoefficient" && dblOk ) {
105       setReflection( Emissive, dblValue, false );
106     }
107     else if ( key == "frontshininess" && dblOk ) {
108       setShininess( dblValue );
109     }
110     else if ( key == "backshininess" && dblOk ) {
111       setShininess( dblValue, false );
112     }
113     else if ( key == "transparency" && dblOk ) {
114       setTransparency( dblValue );
115     }
116     else if ( key == "physical" && boolOk ) {
117       setPhysical( boolValue );
118     }
119     else if ( key == "ambient" && boolOk ) {
120       setReflection( Ambient, boolValue );
121     }
122     else if ( key == "diffuse" && boolOk ) {
123       setReflection( Diffuse, boolValue );
124     }
125     else if ( key == "specular" && boolOk ) {
126       setReflection( Specular, boolValue );
127     }
128     else if ( key == "emissive" && boolOk ) {
129       setReflection( Emissive, boolValue );
130     }
131   }
132 }
133
134 /*!
135   \brief Get material properties string representation
136   \return string representing of material properties
137   \sa fromProperties()
138 */
139 QString Material_Model::toProperties()
140 {
141   QStringList props;
142   QString fmt = "%1=%2";
143
144   // physical
145   props << fmt.arg( "Physical" ).arg( isPhysical() );
146
147   // shininess
148   props << fmt.arg( "FrontShininess" ).arg( QString::number ( shininess( true ), 'g', 4 ) ) << fmt.arg( "BackShininess" ).arg( QString::number ( shininess( false ), 'g', 4 ) );
149
150   //transparency
151   props << fmt.arg( "Transparency" ).arg( transparency() );
152
153   // ambient reflection
154   props << fmt.arg( "Ambient" ).arg( hasReflection( Ambient ) );
155   if ( color( Ambient ).isValid() )
156     props << fmt.arg( "AmbientColor" ).arg( Qtx::colorToString( color( Ambient ) ) );
157   props << fmt.arg( "FrontAmbientCoefficient" ).arg( QString::number ( reflection( Ambient, true ), 'g', 4 ) ) << fmt.arg( "BackAmbientCoefficient" ).arg( QString::number ( reflection( Ambient, false ), 'g', 4 ) );
158
159   // diffuse reflection
160   props << fmt.arg( "Diffuse" ).arg( hasReflection( Diffuse ) );
161   if ( color( Diffuse ).isValid() )
162     props << fmt.arg( "DiffuseColor" ).arg( Qtx::colorToString( color( Diffuse ) ) );
163   props << fmt.arg( "FrontDiffuseCoefficient" ).arg( QString::number ( reflection( Diffuse, true ), 'g', 4 ) ) << fmt.arg( "BackDiffuseCoefficient" ).arg( QString::number ( reflection( Diffuse, false ), 'g', 4 ) );
164
165   // specular reflection
166   props << fmt.arg( "Specular" ).arg( hasReflection( Specular ) );
167   if ( color( Specular ).isValid() )
168     props << fmt.arg( "SpecularColor" ).arg( Qtx::colorToString( color( Specular ) ) );
169   props << fmt.arg( "FrontSpecularCoefficient" ).arg( QString::number ( reflection( Specular, true ), 'g', 4 ) ) << fmt.arg( "BackSpecularCoefficient" ).arg( QString::number ( reflection( Specular, false ), 'g', 4 ) );
170
171   // emissive reflection
172   props << fmt.arg( "Emissive" ).arg( hasReflection( Emissive ) );
173   if ( color( Emissive ).isValid() )
174     props << fmt.arg( "EmissiveColor" ).arg( Qtx::colorToString( color( Emissive ) ) );
175   props << fmt.arg( "FrontEmissiveCoefficient" ).arg( QString::number ( reflection( Emissive, true ), 'g', 4 ) ) << fmt.arg( "BackEmissiveCoefficient" ).arg( QString::number ( reflection( Emissive, false ), 'g', 4 ) );
176
177   return props.join( ":" );
178 }
179
180 /*!
181   \brief Initialize material model from the resources
182
183   This function can be used to retrieve material properties from the resource file.
184
185   \param material material name (if not specified, model is initialized by default material)
186   \param resMgr resource manager (if not specified, new resources manager is created)
187   \sa toResources()
188 */
189 void Material_Model::fromResources( const QString& material, Material_ResourceMgr* resMgr )
190 {
191   static QString common = "[common]";
192   
193   // reset to default values
194   init();
195
196   // material name is not specified: use default values
197   if ( material.isEmpty() ) return;
198
199   if ( !resMgr )
200     resMgr = Material_ResourceMgr::resourceMgr();
201
202   // lock resources manager
203   QMutexLocker lock( &resMgr->myMutex );
204
205   // read common section
206   if ( material != common && resMgr->hasSection( common ) )
207     read( common, resMgr );
208
209   // read material section
210   read( material, resMgr );
211 }
212
213 void Material_Model::read( const QString& material, Material_ResourceMgr* resMgr )
214 {
215   // physical
216   if ( resMgr->hasValue( material, "physical" ) ) {
217     setPhysical( resMgr->booleanValue( material, "physical" ) );
218   }
219
220   // shininess
221   if ( resMgr->hasValue( material, "front_shininess" ) ) {
222     setShininess( resMgr->doubleValue( material, "front_shininess" ) );
223   }
224   if ( resMgr->hasValue( material, "back_shininess" ) ) {
225     setShininess( resMgr->doubleValue( material, "back_shininess" ), false );
226   }
227
228   // transparency
229   if ( resMgr->hasValue( material, "transparency" ) ) {
230     setTransparency( resMgr->doubleValue( material, "transparency" ) );
231   }
232
233   // ambient reflection
234   if ( resMgr->hasValue( material, "ambient-color" ) ) {
235     setColor( Ambient, resMgr->colorValue( material, "ambient-color" ) );
236   }
237   if ( resMgr->hasValue( material, "front_ambient-coefficient" ) ) {
238     setReflection( Ambient, resMgr->doubleValue( material, "front_ambient-coefficient" ) );
239   }
240   if ( resMgr->hasValue( material, "back_ambient-coefficient" ) ) {
241     setReflection( Ambient, resMgr->doubleValue( material, "back_ambient-coefficient" ), false );
242   }
243   if ( resMgr->hasValue( material, "ambient" ) ) {
244     setReflection( Ambient, resMgr->booleanValue( material, "ambient" ) );
245   }
246
247   // diffuse reflection
248   if ( resMgr->hasValue( material, "diffuse-color" ) ) {
249     setColor( Diffuse, resMgr->colorValue( material, "diffuse-color" ) );
250   }
251   if ( resMgr->hasValue( material, "front_diffuse-coefficient" ) ) {
252     setReflection( Diffuse, resMgr->doubleValue( material, "front_diffuse-coefficient" ) );
253   }
254   if ( resMgr->hasValue( material, "back_diffuse-coefficient" ) ) {
255     setReflection( Diffuse, resMgr->doubleValue( material, "back_diffuse-coefficient" ), false );
256   }
257   if ( resMgr->hasValue( material, "diffuse" ) ) {
258     setReflection( Diffuse, resMgr->booleanValue( material, "diffuse" ) );
259   }
260
261   // specular reflection
262   if ( resMgr->hasValue( material, "specular-color" ) ) {
263     setColor( Specular, resMgr->colorValue( material, "specular-color" ) );
264   }
265   if ( resMgr->hasValue( material, "front_specular-coefficient" ) ) {
266     setReflection( Specular, resMgr->doubleValue( material, "front_specular-coefficient" ) );
267   }
268   if ( resMgr->hasValue( material, "back_specular-coefficient" ) ) {
269     setReflection( Specular, resMgr->doubleValue( material, "back_specular-coefficient" ), false );
270   }
271   if ( resMgr->hasValue( material, "specular" ) ) {
272     setReflection( Specular, resMgr->booleanValue( material, "specular" ) );
273   }
274
275   // emissive reflection
276   if ( resMgr->hasValue( material, "emissive-color" ) ) {
277     setColor( Emissive, resMgr->colorValue( material, "emissive-color" ) );
278   }
279   if ( resMgr->hasValue( material, "front_emissive-coefficient" ) ) {
280     setReflection( Emissive, resMgr->doubleValue( material, "front_emissive-coefficient" ) );
281   }
282   if ( resMgr->hasValue( material, "back_emissive-coefficient" ) ) {
283     setReflection( Emissive, resMgr->doubleValue( material, "back_emissive-coefficient" ), false );
284   }
285   if ( resMgr->hasValue( material, "emissive" ) ) {
286     setReflection( Emissive, resMgr->booleanValue( material, "emissive" ) );
287   }
288 }
289
290 /*!
291   \brief Save material properties to the resource file.
292   \param material material name
293   \param resMgr resource manager
294   \sa fromResources()
295 */
296 void Material_Model::toResources( const QString& material, Material_ResourceMgr* resMgr )
297 {
298   if ( resMgr && !material.isEmpty() ) {
299     // lock resources manager
300     QMutexLocker lock( &resMgr->myMutex );
301   
302     // remove resources section (to clean-up all previous properties)
303     resMgr->remove( material );
304
305     // physical
306     resMgr->setValue( material, "physical", isPhysical() );
307
308     // shininess
309     resMgr->setValue( material, "front_shininess", shininess( true) );
310     resMgr->setValue( material, "back_shininess", shininess( false ) );
311
312     // transparency
313     resMgr->setValue( material, "transparency", transparency() );
314
315     // ambient reflection
316     if ( color( Ambient ).isValid() )
317       resMgr->setValue( material, "ambient-color", color( Ambient ) );
318     resMgr->setValue( material, "front_ambient-coefficient", reflection( Ambient ) );
319     resMgr->setValue( material, "back_ambient-coefficient", reflection( Ambient, false ) );
320     resMgr->setValue( material, "ambient", hasReflection( Ambient ) );
321
322     // diffuse reflection
323     if ( color( Diffuse ).isValid() )
324       resMgr->setValue( material, "diffuse-color", color( Diffuse ) );
325     resMgr->setValue( material, "front_diffuse-coefficient", reflection( Diffuse ) );
326     resMgr->setValue( material, "back_diffuse-coefficient", reflection( Diffuse, false ) );
327     resMgr->setValue( material, "diffuse", hasReflection( Diffuse ) );
328
329     // Specular reflection
330     if ( color( Specular ).isValid() )
331       resMgr->setValue( material, "specular-color", color( Specular ) );
332     resMgr->setValue( material, "front_specular-coefficient", reflection( Specular ) );
333     resMgr->setValue( material, "back_specular-coefficient", reflection( Specular, false ) );
334     resMgr->setValue( material, "specular", hasReflection( Specular ) );
335
336     // Emissive reflection
337     if ( color( Emissive ).isValid() )
338       resMgr->setValue( material, "emissive-color", color( Emissive ) );
339     resMgr->setValue( material, "front_emissive-coefficient", reflection( Emissive ) );
340     resMgr->setValue( material, "back_emissive-coefficient", reflection( Emissive, false ) );
341     resMgr->setValue( material, "emissive", hasReflection( Emissive ) );
342   }
343 }
344
345 /*!
346   \brief Get material type
347   \return \c true if material is physical or \c false otherwise
348   \sa setPhysical()
349 */
350 bool Material_Model::isPhysical() const
351 {
352   return myIsPhysical;
353 }
354
355 /*!
356   \brief Set material type
357   \param value \c true if material is physical or \c false otherwise
358   \sa isPhysical()
359 */
360 void Material_Model::setPhysical( bool value )
361 {
362   myIsPhysical = value;
363 }
364
365 /*!
366   \brief Check if given reflection is enabled
367   \param type reflection type
368   \return \c true if specified reflection type is enabled or \c false otherwise
369   \sa setReflection(ReflectionType, bool)
370 */
371 bool Material_Model::hasReflection( ReflectionType type ) const
372 {
373   bool value = false;
374   if ( type >= 0 && type < 4 )
375     value = myReflection[ type ].enabled;
376   return value;
377 }
378
379 /*!
380   \brief Enable/disable given reflection type
381   \param type reflection type
382   \param value boolean flag
383   \sa hasReflection()
384 */
385 void Material_Model::setReflection( ReflectionType type, bool value )
386 {
387   if ( type >= 0 && type < 4 )
388     myReflection[ type ].enabled = value;
389 }
390
391 /*!
392   \brief Get color value for the given reflection type
393   \param type reflection type
394   \return color associated with the specified reflection type
395   \sa setColor()
396 */
397 QColor Material_Model::color( ReflectionType type ) const
398 {
399   QColor value;
400   if ( type >= 0 && type < 4 )
401     value = myReflection[ type ].color;
402   return value;
403 }
404
405 /*!
406   \brief Set color value for the given reflection type
407   \param type reflection type
408   \param value color to be used for specified reflection type
409   \sa color()
410 */
411 void Material_Model::setColor( ReflectionType type, const QColor& value )
412 {
413   if ( type >= 0 && type < 4 )
414     myReflection[ type ].color = value;
415 }
416
417 /*!
418   \brief Get coefficient value for the given reflection type
419   \param type reflection type
420   \param theIsFront boolean flag for choosing side
421   \return coefficient value for the specified reflection type
422   \sa setReflection(ReflectionType, double, bool = true)
423 */
424 double Material_Model::reflection( ReflectionType type, bool theIsFront ) const
425 {
426   double value = 0.0;
427   if ( type >= 0 && type < 4 )
428     if ( theIsFront )
429       value = myReflection[ type ].front_coef;
430     else
431       value = myReflection[ type ].back_coef;
432   return value;
433 }
434
435 /*!
436   \brief Set coefficient value for the given reflection type
437   \param type reflection type
438   \param value coefficient to be used by the given reflection type
439   \param theIsFront boolean flag for choosing side
440   \sa reflection( bool = true)
441 */
442 void Material_Model::setReflection( ReflectionType type, double value, bool theIsFront )
443 {
444   if ( type >= 0 && type < 4 )
445     if ( theIsFront )
446       myReflection[ type ].front_coef = value;
447     else
448       myReflection[ type ].back_coef = value;
449 }
450
451 /*!
452   \brief Get shininess value
453   \param theIsFront boolean flag for choosing side
454   \return shininess value of the material
455   \sa setShininess( double, bool = true )
456 */
457 double Material_Model::shininess( bool theIsFront ) const
458 {
459   if ( theIsFront )
460     return myFrontShininess;
461   else
462     return myBackShininess;
463 }
464
465 /*!
466   \brief Set shininess value
467   \param value new shininess value
468   \param theIsFront boolean flag for choosing side
469   \sa shininess( bool = true )
470 */
471 void Material_Model::setShininess( double value, bool theIsFront )
472 {
473   if ( theIsFront )
474     myFrontShininess = value;
475   else
476     myBackShininess = value;
477 }
478
479 /*!
480   \brief Get transparency value
481   \return transparency value of the material
482   \sa setTransparency()
483 */
484 double Material_Model::transparency() const
485 {
486   return myTransparency;
487 }
488
489 /*!
490   \brief Set transparency value
491   \param value new transparency value
492   \sa transparency()
493 */
494 void Material_Model::setTransparency( double value )
495 {
496   myTransparency = value;
497 }
498
499 /*!
500   \brief Initialize material model with default values
501 */
502 void Material_Model::init()
503 {  
504   QColor c;
505
506   // non-physical by default
507   setPhysical( false );
508   // shininess
509   setShininess( 0.039 );
510   setShininess( 0.039, false );
511   // transparency
512   setTransparency( 0.0 );
513
514   // ambient reflection (enabled by default)
515   Qtx::stringToColor( "#333333", c );
516   setColor( Ambient, c );
517   setReflection( Ambient, 0.3, true );
518   setReflection( Ambient, 0.3, false );
519   setReflection( Ambient, true );
520
521   // diffuse reflection (enabled by default)
522   Qtx::stringToColor( "#000000", c );
523   setColor( Diffuse, c );
524   setReflection( Diffuse, 0.65 );
525   setReflection( Diffuse, 0.65, false );
526   setReflection( Diffuse, true );
527
528   // specular reflection (enabled by default)
529   Qtx::stringToColor( "#ffffff", c );
530   setColor( Specular, c );
531   setReflection( Specular, 0.0 );
532   setReflection( Specular, 0.0, false );
533   setReflection( Specular, true );
534
535   // emissive reflection (disabled by default)
536   Qtx::stringToColor( "#000000", c );
537   setColor( Emissive, c );
538   setReflection( Emissive, 0.0 );
539   setReflection( Emissive, 0.0, false );
540   setReflection( Emissive, false );
541 }
542
543 /*!
544   \brief Construct OCCT material aspect from material model
545   \param theIsFront boolean flag for choosing side
546   \return material aspect object with corresponding properties
547 */
548 Graphic3d_MaterialAspect Material_Model::getMaterialOCCAspect( bool theIsFront )
549 {
550   // Get material aspect from the current model
551   Graphic3d_MaterialAspect aspect;
552
553   QColor c;
554   
555   // ambient reflection
556   if ( color( Ambient ).isValid() ) {
557     c = color( Ambient );
558     aspect.SetAmbientColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
559   }
560   aspect.SetAmbient( reflection( Ambient, theIsFront ));
561   if ( hasReflection( Ambient ) )
562     aspect.SetReflectionModeOn( Graphic3d_TOR_AMBIENT );
563   else
564     aspect.SetReflectionModeOff( Graphic3d_TOR_AMBIENT );
565   
566   // diffuse reflection
567   if ( color( Diffuse ).isValid() ) {
568     c = color( Diffuse );
569     aspect.SetDiffuseColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
570   }
571   aspect.SetDiffuse( reflection( Diffuse, theIsFront ));
572   if ( hasReflection( Diffuse ) )
573     aspect.SetReflectionModeOn( Graphic3d_TOR_DIFFUSE );
574   else
575     aspect.SetReflectionModeOff( Graphic3d_TOR_DIFFUSE );
576
577   // specular reflection
578   if ( color( Specular ).isValid() ) {
579     c = color( Specular );
580     aspect.SetSpecularColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
581   }
582   aspect.SetSpecular( reflection( Specular, theIsFront ));
583   if ( hasReflection( Specular ) )
584     aspect.SetReflectionModeOn( Graphic3d_TOR_SPECULAR );
585   else
586     aspect.SetReflectionModeOff( Graphic3d_TOR_SPECULAR );
587
588   // emissive reflection
589   if ( color( Emissive ).isValid() ) {
590     c = color( Emissive );
591     aspect.SetEmissiveColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
592   }
593   aspect.SetEmissive( reflection( Emissive, theIsFront ));
594   if ( hasReflection( Emissive ) )
595     aspect.SetReflectionModeOn( Graphic3d_TOR_EMISSION );
596   else
597     aspect.SetReflectionModeOff( Graphic3d_TOR_EMISSION );
598   
599   // shininess
600   aspect.SetShininess( shininess( theIsFront ) );
601
602   // transparency
603   aspect.SetTransparency( transparency() );
604
605   // material type
606   aspect.SetMaterialType( isPhysical() ? Graphic3d_MATERIAL_PHYSIC : Graphic3d_MATERIAL_ASPECT );
607
608   return aspect;
609 }
610
611 /*!
612   \brief Construct VTK property from material model
613   \param theIsFront boolean flag for choosing side
614   \return VTK property with correspondent material properties
615 */
616 GEOM_VTKPropertyMaterial* Material_Model::getMaterialVTKProperty( bool theIsFront )
617 {
618   // NOTE: In VTK it's impossible to switch on/off specific reflection type
619   // NOTE: In VTK emissive reflection type is not supported
620   // NOTE: In VTK shininess is specified via SpecularPower attribute
621   // NOTE: In VTK transparency is specified via Opacity attribute
622
623   // Get material properties from the current model
624   GEOM_VTKPropertyMaterial* prop = GEOM_VTKPropertyMaterial::New();
625
626   QColor c;
627
628   // ambient reflection
629   if ( color( Ambient ).isValid() && hasReflection( Ambient ) ) {
630     c = color( Ambient );
631     prop->SetAmbientColor( c.redF(), c.greenF(), c.blueF() );
632     prop->SetAmbient( reflection( Ambient, theIsFront ) );
633   }
634
635   // diffuse reflection
636   if ( color( Diffuse ).isValid() && hasReflection( Diffuse ) ) {
637     c = color( Diffuse );
638     prop->SetDiffuseColor( c.redF(), c.greenF(), c.blueF() );
639     prop->SetDiffuse( reflection( Diffuse, theIsFront ) );
640   }
641
642   // specular reflection
643   if ( color( Specular ).isValid() && hasReflection( Specular ) ) {
644     c = color( Specular );
645     prop->SetSpecularColor( c.redF(), c.greenF(), c.blueF() );
646     prop->SetSpecular( reflection( Specular, theIsFront ) );
647   }
648
649   // shininess
650   prop->SetSpecularPower( shininess( theIsFront )*100.0 );
651
652   // transparency
653   prop->SetOpacity( 1 - transparency() );
654
655   // material type
656   prop->SetPhysical( isPhysical() );
657
658   return prop;
659 }
660