Salome HOME
Update copyright information
[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 "Material_ResourceMgr.h"
26
27 #include <GEOM_Constants.h>
28
29 #include <QtxResourceMgr.h>
30 #include <SUIT_ResourceMgr.h>
31 #include <SUIT_Session.h>
32
33 // OCCT Includes
34 #include <Graphic3d_AspectFillArea3d.hxx>
35
36 // VTK includes
37 #include <vtkProperty.h> 
38
39 /*!
40   \brief Constructor
41
42   Create new SALOME material model with default properties.
43 */
44 Material_Model::Material_Model()
45   : myResourceMgr( 0 )
46 {
47   myShininess = 0.0;
48 }
49
50 /*!
51   \brief Destructor
52 */
53 Material_Model::~Material_Model()
54 {
55 }
56
57 /*!
58   \brief Construct material model according to the given list of
59   material properties
60   
61   \param theProps the list of material properties
62   \return material model object with correspondent properties
63   \sa getMaterialProperty()
64 */
65 Material_Model* Material_Model::getMaterialModel( QStringList theProps )
66 {
67   Material_Model* aModel = new Material_Model();
68
69   foreach ( QString aProp, theProps ) {
70     if ( aProp.isNull() ) continue;
71     
72     // Set current ambient color
73     aModel->setColor( aProp, "AmbientColor=", Material_Model::Ambient );
74     // Set current ambient coefficient
75     aModel->setCoefficient( aProp, "AmbientCoefficient=", Material_Model::Ambient );
76     
77     // Set current diffuse color
78     aModel->setColor( aProp, "DiffuseColor=", Material_Model::Diffuse );
79     // Set current diffuse coefficient
80     aModel->setCoefficient( aProp, "DiffuseCoefficient=", Material_Model::Diffuse );
81     
82     // Set current specular color
83     aModel->setColor( aProp, "SpecularColor=", Material_Model::Specular );
84     // Set current specular coefficient
85     aModel->setCoefficient( aProp, "SpecularCoefficient=", Material_Model::Specular );
86     
87     // Set current emission color
88     aModel->setColor( aProp, "EmissionColor=", Material_Model::Emission );
89     // Set current emission coefficient
90     aModel->setCoefficient( aProp, "EmissionCoefficient=", Material_Model::Emission );
91     
92     // Set current shininess
93     QString aPropName = "Shininess=";
94     int anId = aProp.indexOf(aPropName);
95     if ( anId != -1 ) {
96       bool ok;
97       double aCoef = aProp.right( aProp.length() - (anId+aPropName.length()) ).toDouble(&ok);
98       if ( ok )
99         aModel->setShininess( aCoef );
100     }    
101   }
102
103   return aModel;
104 }
105
106 /*!
107   \brief Construct string of material properties for this model object
108   
109   \return a string representing a set of material properties
110   \sa getMaterialModel()
111 */
112 QString Material_Model::getMaterialProperty()
113 {
114   // Parse material properties of the current model and form a string for persistent purpose
115   QString aMaterial;
116
117   bool isReflectionTypeActive;  
118   QColor c;
119   double coef;
120
121   // Ambient reflection
122   isReflectionTypeActive = hasAmbientReflection();
123   if ( isReflectionTypeActive ) {
124     c = color( Material_Model::Ambient );
125     coef = coefficient(Material_Model::Ambient);
126     // Insert properties into persistent string
127     aMaterial = "AmbientColor=%1%2AmbientCoefficient=%3";
128     aMaterial = aMaterial.arg( Qtx::colorToString(c) );
129     aMaterial = aMaterial.arg( DIGIT_SEPARATOR );
130     aMaterial = aMaterial.arg( coef );
131   }
132   // Diffuse reflection
133   isReflectionTypeActive = hasDiffuseReflection();
134   if ( isReflectionTypeActive ) {
135     c = color( Material_Model::Diffuse );
136     coef = coefficient(Material_Model::Diffuse);
137     // Insert properties into persistent string
138     aMaterial += "%1DiffuseColor=%2%3DiffuseCoefficient=%4";
139     aMaterial = aMaterial.arg( DIGIT_SEPARATOR );
140     aMaterial = aMaterial.arg( Qtx::colorToString(c) );
141     aMaterial = aMaterial.arg( DIGIT_SEPARATOR );
142     aMaterial = aMaterial.arg( coef );
143   }
144   // Specular reflection
145   isReflectionTypeActive = hasSpecularReflection();
146   if ( isReflectionTypeActive ) {
147     c = color( Material_Model::Specular );
148     coef = coefficient(Material_Model::Specular);
149     // Insert properties into persistent string
150     aMaterial += "%1SpecularColor=%2%3SpecularCoefficient=%4";
151     aMaterial = aMaterial.arg( DIGIT_SEPARATOR );
152     aMaterial = aMaterial.arg( Qtx::colorToString(c) );
153     aMaterial = aMaterial.arg( DIGIT_SEPARATOR );
154     aMaterial = aMaterial.arg( coef );
155   }
156   // Emission reflection
157   isReflectionTypeActive = hasEmissionReflection();
158   if ( isReflectionTypeActive ) {
159     c = color( Material_Model::Emission );
160     coef = coefficient(Material_Model::Emission);
161     // Insert properties into persistent string
162     aMaterial += "%1EmissionColor=%2%3EmissionCoefficient=%4";
163     aMaterial = aMaterial.arg( DIGIT_SEPARATOR );
164     aMaterial = aMaterial.arg( Qtx::colorToString(c) );
165     aMaterial = aMaterial.arg( DIGIT_SEPARATOR );
166     aMaterial = aMaterial.arg( coef );
167   }
168   if ( !aMaterial.isEmpty() ) {
169     // Shininess
170     // Insert properties into persistent string
171     aMaterial += "%1Shininess=%2";
172     aMaterial = aMaterial.arg( DIGIT_SEPARATOR );
173     aMaterial = aMaterial.arg( shininess() );
174   }
175
176   return aMaterial;
177 }
178
179 /*!
180   \brief Construct OCCT material aspect object based on the current model
181   
182   \return material aspect object with correspondent properties
183 */
184 Graphic3d_MaterialAspect Material_Model::getMaterialOCCAspect()
185 {
186   // Get material aspect from the current model
187   Graphic3d_MaterialAspect aMat;
188
189   bool isReflectionTypeActive;
190   QColor c;
191   double coef;
192
193   // Ambient reflection
194   isReflectionTypeActive = hasAmbientReflection();
195   if ( isReflectionTypeActive ) {
196     aMat.SetReflectionModeOn( Graphic3d_TOR_AMBIENT );
197     c = color( Material_Model::Ambient );
198     aMat.SetAmbientColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
199     coef = coefficient( Material_Model::Ambient );
200     aMat.SetAmbient( coef );
201   }
202   // Diffuse reflection
203   isReflectionTypeActive = hasDiffuseReflection();
204   if ( isReflectionTypeActive ) {
205     aMat.SetReflectionModeOn( Graphic3d_TOR_DIFFUSE );
206     c = color( Material_Model::Diffuse );
207     aMat.SetDiffuseColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
208     coef = coefficient( Material_Model::Diffuse );
209     aMat.SetDiffuse( coef );      
210   }
211   // Specular reflection
212   isReflectionTypeActive = hasSpecularReflection();
213   if ( isReflectionTypeActive ) {
214     aMat.SetReflectionModeOn( Graphic3d_TOR_SPECULAR );
215     c = color( Material_Model::Specular );
216     aMat.SetSpecularColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
217     coef = coefficient( Material_Model::Specular );
218     aMat.SetSpecular( coef );
219   }
220   // Emission reflection
221   isReflectionTypeActive = hasEmissionReflection();
222   if ( isReflectionTypeActive ) {
223     aMat.SetReflectionModeOn( Graphic3d_TOR_EMISSION );
224     c = color( Material_Model::Emission );
225     aMat.SetEmissiveColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
226     coef = coefficient( Material_Model::Emission );
227     aMat.SetEmissive( coef );
228   }
229   // Shininess
230   aMat.SetShininess( shininess() );
231
232   return aMat;
233 }
234
235 /*!
236   \brief Construct VTK property with properties of material based on the current model
237   
238   \return VTK property with correspondent material properties
239 */
240 vtkProperty* Material_Model::getMaterialVTKProperty()
241 {
242   // Get material properties from the current model
243   vtkProperty* aProperty = vtkProperty::New();
244   
245   bool isReflectionTypeActive;
246   QColor c;
247   double coef;
248
249   // Ambient reflection
250   isReflectionTypeActive = hasAmbientReflection();
251   if ( isReflectionTypeActive ) {
252     c = color( Material_Model::Ambient );
253     aProperty->SetAmbientColor( c.redF(), c.greenF(), c.blueF() ); //SalomeApp_Tools::color( c )
254     coef = coefficient( Material_Model::Ambient );
255     aProperty->SetAmbient( coef );
256   }
257   // Diffuse reflection
258   isReflectionTypeActive = hasDiffuseReflection();
259   if ( isReflectionTypeActive ) {
260     c = color( Material_Model::Diffuse );
261     aProperty->SetDiffuseColor( c.redF(), c.greenF(), c.blueF() );
262     coef = coefficient( Material_Model::Diffuse );
263     aProperty->SetDiffuse( coef );       
264   }
265   // Specular reflection
266   isReflectionTypeActive = hasSpecularReflection();
267   if ( isReflectionTypeActive ) {
268     c = color( Material_Model::Specular );
269     aProperty->SetSpecularColor( c.redF(), c.greenF(), c.blueF() );
270     coef = coefficient( Material_Model::Specular );
271     aProperty->SetSpecular( coef );
272   }
273   // Shininess
274   aProperty->SetSpecularPower( shininess()*100.0 );
275
276   return aProperty;
277 }
278
279 /*!
280   \brief Initialize material model with default values
281 */
282 void Material_Model::initDefaults()
283 {  
284   // Set default ambient color
285   setColor( Ambient, "#333333" );
286   // Set default ambient coefficient
287   setCoefficient( Ambient, 0.3 );
288
289   // Set default diffuse color
290   setColor( Diffuse, "#000000" );
291   // Set default diffuse coefficient
292   setCoefficient( Diffuse, 0.65 );
293
294   // Set default specular color
295   setColor( Specular, "#ffffff" );
296   // Set default specular coefficient
297   setCoefficient( Specular, 0.0 );
298   
299   // Set default shininess
300   setShininess( 0.039 );
301 }
302
303 /*!
304   \brief Clear current content of this material model
305 */
306 void Material_Model::clearModel()
307 {
308   myColors.clear();
309   myCoefficients.clear();
310   myShininess = 0.0;
311 }
312
313 /*!
314   \brief Initialize material model from the resources
315
316   This function can be used to retrieve material properties from the resource file(s).
317   Note, that paremeters \a theResMgr and \a theResSection are stored by the model to be used
318   later with save() method.
319
320   \param theResMgr resources manager
321   \param theResSection resources section name
322   \param theIsFront if True, it is front material, else it is back material
323   \sa save()
324 */
325 void Material_Model::fromResources( QtxResourceMgr* theResMgr,
326                                     const QString& theResSection,
327                                     bool theIsFront )
328 {
329   // Clear current content of the model
330   // before setting properties from resources
331   clearModel();
332
333   myResourceMgr     = theResMgr;
334   myResourceSection = theResSection;
335
336   // init from resource manager
337   if ( !resourceMgr() )
338     return;
339
340   if ( theResSection.compare( "Geometry" ) == 0 ) {
341     if ( theIsFront ) {
342       myResourceSection = theResMgr->stringValue("Geometry", "front_material", "Gold");
343     }
344     else {
345       myResourceSection = theResMgr->stringValue("Geometry", "back_material", "");
346       if ( myResourceSection.isEmpty() )
347         myResourceSection = theResMgr->stringValue("Geometry", "front_material", "Gold");
348     }
349       
350     myResourceMgr = new Material_ResourceMgr();
351   }
352   
353   QString section = resourceSection( theIsFront );
354
355   // If there is no material preference in XML files,
356   // use the default material hardcoded in material model
357   if ( section.isEmpty() ) {
358     initDefaults();
359     return;
360   }
361
362   // Set ambient color
363   if ( resourceMgr()->hasValue( section, "ambient-color" ) ) {
364     setColor( Ambient, resourceMgr()->colorValue( section, "ambient-color" ) );
365   }
366   // Set ambient coefficient
367   if ( resourceMgr()->hasValue( section, "ambient-coefficient" ) ) {
368     setCoefficient( Ambient, resourceMgr()->doubleValue( section, "ambient-coefficient" ) );
369   }
370
371   // Set diffuse color
372   if ( resourceMgr()->hasValue( section, "diffuse-color" ) ) {
373     setColor( Diffuse, resourceMgr()->colorValue( section, "diffuse-color" ) );
374   }
375   // Set diffuse coefficient
376   if ( resourceMgr()->hasValue( section, "diffuse-coefficient" ) ) {
377     setCoefficient( Diffuse, resourceMgr()->doubleValue( section, "diffuse-coefficient" ) );
378   }
379
380   // Set specular color
381   if ( resourceMgr()->hasValue( section, "specular-color" ) ) {
382     setColor( Specular, resourceMgr()->colorValue( section, "specular-color" ) );
383   }
384   // Set specular coefficient
385   if ( resourceMgr()->hasValue( section, "specular-coefficient" ) ) {
386     setCoefficient( Specular, resourceMgr()->doubleValue( section, "specular-coefficient" ) );
387   }
388
389   // Set emission color
390   if ( resourceMgr()->hasValue( section, "emission-color" ) ) {
391     setColor( Emission, resourceMgr()->colorValue( section, "emission-color" ) );
392   }
393   // Set emission coefficient
394   if ( resourceMgr()->hasValue( section, "emission-coefficient" ) ) {
395     setCoefficient( Emission, resourceMgr()->doubleValue( section, "emission-coefficient" ) );
396   }
397
398   // Set shininess
399   if ( resourceMgr()->hasValue( section, "shininess" ) ) {
400     setShininess( resourceMgr()->doubleValue( section, "shininess" ) );
401   }
402 }
403
404 /*!
405   \brief Save material properties to the resource file.
406   
407   If paremeters \a theResMgr and \a theResSection are not specified, default ones
408   (those passed to the fromResources() function) are used instead.
409
410   \param theResMgr resources manager
411   \param theResSection resources section name
412   \param theIsFront if True, it is front material, else it is back material
413   \sa fromResources()
414 */
415 void Material_Model::save( QtxResourceMgr* theResMgr,
416                            const QString& theResSection,
417                            bool theIsFront )
418 {
419   if ( !theResMgr )
420     theResMgr = resourceMgr();
421   if ( !theResMgr )
422     return;
423
424   QString section = theResSection.isEmpty() ? resourceSection( theIsFront ) : theResSection;
425   myResourceSection = section;
426
427   if ( hasAmbientReflection() ) {
428     // Save ambient color
429     theResMgr->setValue( section, "ambient-color", color( Ambient ) );
430     // Save ambient coefficient
431     theResMgr->setValue( section, "ambient-coefficient", coefficient( Ambient ) );
432   }
433   else {
434     // Remove ambient color
435     theResMgr->remove( section, "ambient-color" );
436     // Remove ambient coefficient
437     theResMgr->remove( section, "ambient-coefficient" );
438   }
439
440   if ( hasDiffuseReflection() ) {
441     // Save diffuse color
442     theResMgr->setValue( section, "diffuse-color", color( Diffuse ) );
443     // Save diffuse coefficient
444     theResMgr->setValue( section, "diffuse-coefficient", coefficient( Diffuse ) );
445   }
446   else {
447     // Remove diffuse color
448     theResMgr->remove( section, "diffuse-color" );
449     // Remove diffuse coefficient
450     theResMgr->remove( section, "diffuse-coefficient" );
451   }
452
453   if ( hasSpecularReflection() ) {
454     // Save specular color
455     theResMgr->setValue( section, "specular-color", color( Specular ) );
456     // Save specular coefficient
457     theResMgr->setValue( section, "specular-coefficient", coefficient( Specular ) );
458   }
459   else {
460     // Remove specular color
461     theResMgr->remove( section, "specular-color" );
462     // Remove specular coefficient
463     theResMgr->remove( section, "specular-coefficient" );
464   }
465
466   if ( hasEmissionReflection() ) {
467     // Save emission color
468     theResMgr->setValue( section, "emission-color", color( Emission ) );
469     // Save emission coefficient
470     theResMgr->setValue( section, "emission-coefficient", coefficient( Emission ) );
471   }
472   else {
473     // Remove emission color
474     theResMgr->remove( section, "emission-color" );
475     // Remove emission coefficient
476     theResMgr->remove( section, "emission-coefficient" );
477   }
478
479   // Save shininess
480   theResMgr->setValue( section, "shininess", shininess() );
481 }
482
483 /*!
484   \brief Get resource manager used by this material model.
485
486   \return pointer to the resource manager passed previously to the fromResources() method
487   \sa fromResources(), resourceSection()
488 */
489 QtxResourceMgr* Material_Model::resourceMgr() const
490 {
491   return myResourceMgr;
492 }
493
494 /*!
495   \brief Get resources section name
496
497   If section name is empty, default material name from "Geometry" section
498   is returned ("front_material" or "back_material" is used depending on
499   the parameter value)
500
501   \param theIsFront the flag indicating that section of front or back material
502   is required
503   \return resource section name passed previously to the fromResources() method
504   \sa fromResources(), resourceMgr()
505 */
506 QString Material_Model::resourceSection( bool theIsFront ) const
507 {
508   return !myResourceSection.isEmpty() ? myResourceSection : 
509     SUIT_Session::session()->resourceMgr()->stringValue("Geometry", 
510                                                         ( theIsFront ? "front_material" : "back_material" ),
511                                                         "Gold");
512 }
513
514 /*!
515   \brief Check if ambient reflection type is defined for this material
516
517   \return true if ambient reflection type is defined for this material,
518   false - otherwise
519 */
520 bool Material_Model::hasAmbientReflection()
521 {
522   return ( !myColors.isEmpty() && myColors.contains(Ambient) || !myCoefficients.isEmpty() && myCoefficients.contains(Ambient) );
523 }
524
525 /*!
526   \brief Check if diffuse reflection type is defined for this material
527
528   \return true if diffuse reflection type is defined for this material,
529   false - otherwise
530 */
531 bool Material_Model::hasDiffuseReflection()
532 {
533   return ( !myColors.isEmpty() && myColors.contains(Diffuse) || !myCoefficients.isEmpty() && myCoefficients.contains(Diffuse) );
534 }
535
536 /*!
537   \brief Check if specular reflection type is defined for this material
538
539   \return true if specular reflection type is defined for this material,
540   false - otherwise
541 */
542 bool Material_Model::hasSpecularReflection()
543 {
544   return ( !myColors.isEmpty() && myColors.contains(Specular) || !myCoefficients.isEmpty() && myCoefficients.contains(Specular) );
545 }
546
547 /*!
548   \brief Check if emission reflection type is defined for this material
549
550   \return true if emission reflection type is defined for this material,
551   false - otherwise
552 */
553 bool Material_Model::hasEmissionReflection()
554 {
555   return ( !myColors.isEmpty() && myColors.contains(Emission) || !myCoefficients.isEmpty() && myCoefficients.contains(Emission) );
556 }
557
558 /*!
559   \brief Get color value for the given reflection type
560   \param theReflectionType reflection type
561   \return a color which should be used by the given reflection type
562   \sa setColor()
563 */
564 QColor Material_Model::color( ReflectionType theReflectionType ) const
565 {
566   return myColors[ theReflectionType ];
567 }
568
569 /*!
570   \brief Set color value for the given reflection type
571
572   \param theReflectionType reflection type
573   \param theColor a color to be used by the given reflection type
574   \sa color()
575 */
576 void Material_Model::setColor( ReflectionType theReflectionType,
577                                const QColor& theColor )
578 {
579   myColors[ theReflectionType ] = theColor;
580 }
581
582 /*!
583   \brief Set color of the current material from the given string
584   \param theProp the considered property
585   \param theColorName the name of the color property
586   \param theReflectionType the type of reflection
587 */
588 void Material_Model::setColor( QString theProp,
589                                QString theColorName,
590                                ReflectionType theReflectionType )
591 {
592   int anId = theProp.indexOf( theColorName );
593   if ( anId != -1 ) {
594     QColor c;
595     if ( Qtx::stringToColor( theProp.right( theProp.length() - ( anId + theColorName.length() ) ), c ) )
596       setColor( theReflectionType, c );
597   }
598 }
599
600 /*!
601   \brief Remove color value for the given reflection type
602
603   \param theReflectionType reflection type
604   \sa color(), setColor()
605 */
606 void Material_Model::removeColor( ReflectionType theReflectionType )
607 {
608   myColors.remove( theReflectionType );
609 }
610
611 /*!
612   \brief Get coefficient value for the given reflection type
613   \param theReflectionType reflection type
614   \return a coefficient which should be used by the given reflection type
615   \sa setCoefficient()
616 */
617 double Material_Model::coefficient( ReflectionType theReflectionType ) const
618 {
619   return myCoefficients[ theReflectionType ];
620 }
621
622 /*!
623   \brief Set coefficient value for the given reflection type
624
625   \param theReflectionType reflection type
626   \param theCoefficient a coefficient to be used by the given reflection type
627   \sa coefficient()
628 */
629 void Material_Model::setCoefficient( ReflectionType theReflectionType,
630                                      double theCoefficient )
631 {
632   myCoefficients[ theReflectionType ] = theCoefficient;
633 }
634
635 /*!
636   \brief Set coefficient of the current material from the given string
637   \param theProp the considered property
638   \param theCoefName the name of the color property
639   \param theReflectionType the type of reflection
640 */
641 void Material_Model::setCoefficient( QString theProp,
642                                      QString theCoefName,
643                                      ReflectionType theReflectionType )
644 {
645   int anId = theProp.indexOf( theCoefName );
646   if ( anId != -1 ) {
647     bool ok;
648     double aCoef = theProp.right( theProp.length() - ( anId + theCoefName.length() ) ).toDouble( &ok );
649     if ( ok )
650       setCoefficient( theReflectionType, aCoef );
651   }
652 }
653
654 /*!
655   \brief Remove coefficient value for the given reflection type
656
657   \param theReflectionType reflection type
658   \sa coefficient(), setCoefficient()
659 */
660 void Material_Model::removeCoefficient( ReflectionType theReflectionType )
661 {
662   myCoefficients.remove( theReflectionType );
663 }
664
665 /*!
666   \brief Get shininess value
667   \return a shininess value of this material
668   \sa setShininess()
669 */
670 double Material_Model::shininess() const
671 {
672   return myShininess;
673 }
674
675 /*!
676   \brief Set shininess value
677
678   \param theShininess a shininess value of this material
679   \sa shininess()
680 */
681 void Material_Model::setShininess( double theShininess)
682 {
683   myShininess = theShininess;
684 }