1 // Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
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, or (at your option) any later version.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // File : Material_Model.cxx
21 // Author : Margarita KARPUNINA, Open CASCADE S.A.S. (margarita.karpunina@opencascade.com)
24 #include "Material_Model.h"
25 #include "GEOM_VTKPropertyMaterial.hxx"
26 #include "Material_ResourceMgr.h"
28 #include <QMutexLocker>
30 #include <Basics_OCCTVersion.hxx>
35 Create new SALOME material model with default properties.
37 Material_Model::Material_Model()
39 myReflection = ReflectionList(4);
40 init(); // set default properties
46 Material_Model::~Material_Model()
51 \brief Initialize material data from the given properties list
52 \param props material properties
55 void Material_Model::fromProperties( const QString& props )
57 // reset to default values
60 // parse material properties
61 QStringList propList = props.split( ":", QString::SkipEmptyParts );
62 foreach ( QString prop, propList )
64 QStringList pdata = prop.split( "=" );
65 if ( pdata.count() < 2 ) continue;
66 QString key = pdata[0].trimmed().toLower();
67 QString data = pdata[1].trimmed().toLower();
69 double dblValue = data.toDouble( &dblOk );
70 bool boolValue = (bool)( data.toInt( &boolOk ) );
73 if ( key == "ambientcolor" && Qtx::stringToColor( data, colorValue ) ) {
74 setColor( Ambient, colorValue );
76 else if ( key == "diffusecolor" && Qtx::stringToColor( data, colorValue ) ) {
77 setColor( Diffuse, colorValue );
79 else if ( key == "specularcolor" && Qtx::stringToColor( data, colorValue ) ) {
80 setColor( Specular, colorValue );
82 else if ( key == "emissivecolor" && Qtx::stringToColor( data, colorValue ) ) {
83 setColor( Emissive, colorValue );
85 else if ( key == "frontambientcoefficient" && dblOk ) {
86 setReflection( Ambient, dblValue );
88 else if ( key == "backambientcoefficient" && dblOk ) {
89 setReflection( Ambient, dblValue, false );
91 else if ( key == "frontdiffusecoefficient" && dblOk ) {
92 setReflection( Diffuse, dblValue );
94 else if ( key == "backdiffusecoefficient" && dblOk ) {
95 setReflection( Diffuse, dblValue, false );
97 else if ( key == "frontspecularcoefficient" && dblOk ) {
98 setReflection( Specular, dblValue );
100 else if ( key == "backspecularcoefficient" && dblOk ) {
101 setReflection( Specular, dblValue, false );
103 else if ( key == "frontemissivecoefficient" && dblOk ) {
104 setReflection( Emissive, dblValue );
106 else if ( key == "backemissivecoefficient" && dblOk ) {
107 setReflection( Emissive, dblValue, false );
109 else if ( key == "frontshininess" && dblOk ) {
110 setShininess( dblValue );
112 else if ( key == "backshininess" && dblOk ) {
113 setShininess( dblValue, false );
115 else if ( key == "transparency" && dblOk ) {
116 setTransparency( dblValue );
118 else if ( key == "physical" && boolOk ) {
119 setPhysical( boolValue );
121 else if ( key == "ambient" && boolOk ) {
122 setReflection( Ambient, boolValue );
124 else if ( key == "diffuse" && boolOk ) {
125 setReflection( Diffuse, boolValue );
127 else if ( key == "specular" && boolOk ) {
128 setReflection( Specular, boolValue );
130 else if ( key == "emissive" && boolOk ) {
131 setReflection( Emissive, boolValue );
137 \brief Get material properties string representation
138 \return string representing of material properties
141 QString Material_Model::toProperties()
144 QString fmt = "%1=%2";
147 props << fmt.arg( "Physical" ).arg( isPhysical() );
150 props << fmt.arg( "FrontShininess" ).arg( QString::number ( shininess( true ), 'g', 4 ) ) << fmt.arg( "BackShininess" ).arg( QString::number ( shininess( false ), 'g', 4 ) );
153 props << fmt.arg( "Transparency" ).arg( transparency() );
155 // ambient reflection
156 props << fmt.arg( "Ambient" ).arg( hasReflection( Ambient ) );
157 if ( color( Ambient ).isValid() )
158 props << fmt.arg( "AmbientColor" ).arg( Qtx::colorToString( color( Ambient ) ) );
159 props << fmt.arg( "FrontAmbientCoefficient" ).arg( QString::number ( reflection( Ambient, true ), 'g', 4 ) ) << fmt.arg( "BackAmbientCoefficient" ).arg( QString::number ( reflection( Ambient, false ), 'g', 4 ) );
161 // diffuse reflection
162 props << fmt.arg( "Diffuse" ).arg( hasReflection( Diffuse ) );
163 if ( color( Diffuse ).isValid() )
164 props << fmt.arg( "DiffuseColor" ).arg( Qtx::colorToString( color( Diffuse ) ) );
165 props << fmt.arg( "FrontDiffuseCoefficient" ).arg( QString::number ( reflection( Diffuse, true ), 'g', 4 ) ) << fmt.arg( "BackDiffuseCoefficient" ).arg( QString::number ( reflection( Diffuse, false ), 'g', 4 ) );
167 // specular reflection
168 props << fmt.arg( "Specular" ).arg( hasReflection( Specular ) );
169 if ( color( Specular ).isValid() )
170 props << fmt.arg( "SpecularColor" ).arg( Qtx::colorToString( color( Specular ) ) );
171 props << fmt.arg( "FrontSpecularCoefficient" ).arg( QString::number ( reflection( Specular, true ), 'g', 4 ) ) << fmt.arg( "BackSpecularCoefficient" ).arg( QString::number ( reflection( Specular, false ), 'g', 4 ) );
173 // emissive reflection
174 props << fmt.arg( "Emissive" ).arg( hasReflection( Emissive ) );
175 if ( color( Emissive ).isValid() )
176 props << fmt.arg( "EmissiveColor" ).arg( Qtx::colorToString( color( Emissive ) ) );
177 props << fmt.arg( "FrontEmissiveCoefficient" ).arg( QString::number ( reflection( Emissive, true ), 'g', 4 ) ) << fmt.arg( "BackEmissiveCoefficient" ).arg( QString::number ( reflection( Emissive, false ), 'g', 4 ) );
179 return props.join( ":" );
183 \brief Initialize material model from the resources
185 This function can be used to retrieve material properties from the resource file.
187 \param material material name (if not specified, model is initialized by default material)
188 \param resMgr resource manager (if not specified, new resources manager is created)
191 void Material_Model::fromResources( const QString& material, Material_ResourceMgr* resMgr )
193 static QString common = "[common]";
195 // reset to default values
198 // material name is not specified: use default values
199 if ( material.isEmpty() ) return;
202 resMgr = Material_ResourceMgr::resourceMgr();
204 // lock resources manager
205 QMutexLocker lock( &resMgr->myMutex );
207 // read common section
208 if ( material != common && resMgr->hasSection( common ) )
209 read( common, resMgr );
211 // read material section
212 read( material, resMgr );
215 void Material_Model::read( const QString& material, Material_ResourceMgr* resMgr )
218 if ( resMgr->hasValue( material, "physical" ) ) {
219 setPhysical( resMgr->booleanValue( material, "physical" ) );
223 if ( resMgr->hasValue( material, "front_shininess" ) ) {
224 setShininess( resMgr->doubleValue( material, "front_shininess" ) );
226 if ( resMgr->hasValue( material, "back_shininess" ) ) {
227 setShininess( resMgr->doubleValue( material, "back_shininess" ), false );
231 if ( resMgr->hasValue( material, "transparency" ) ) {
232 setTransparency( resMgr->doubleValue( material, "transparency" ) );
235 // ambient reflection
236 if ( resMgr->hasValue( material, "ambient-color" ) ) {
237 setColor( Ambient, resMgr->colorValue( material, "ambient-color" ) );
239 if ( resMgr->hasValue( material, "front_ambient-coefficient" ) ) {
240 setReflection( Ambient, resMgr->doubleValue( material, "front_ambient-coefficient" ) );
242 if ( resMgr->hasValue( material, "back_ambient-coefficient" ) ) {
243 setReflection( Ambient, resMgr->doubleValue( material, "back_ambient-coefficient" ), false );
245 if ( resMgr->hasValue( material, "ambient" ) ) {
246 setReflection( Ambient, resMgr->booleanValue( material, "ambient" ) );
249 // diffuse reflection
250 if ( resMgr->hasValue( material, "diffuse-color" ) ) {
251 setColor( Diffuse, resMgr->colorValue( material, "diffuse-color" ) );
253 if ( resMgr->hasValue( material, "front_diffuse-coefficient" ) ) {
254 setReflection( Diffuse, resMgr->doubleValue( material, "front_diffuse-coefficient" ) );
256 if ( resMgr->hasValue( material, "back_diffuse-coefficient" ) ) {
257 setReflection( Diffuse, resMgr->doubleValue( material, "back_diffuse-coefficient" ), false );
259 if ( resMgr->hasValue( material, "diffuse" ) ) {
260 setReflection( Diffuse, resMgr->booleanValue( material, "diffuse" ) );
263 // specular reflection
264 if ( resMgr->hasValue( material, "specular-color" ) ) {
265 setColor( Specular, resMgr->colorValue( material, "specular-color" ) );
267 if ( resMgr->hasValue( material, "front_specular-coefficient" ) ) {
268 setReflection( Specular, resMgr->doubleValue( material, "front_specular-coefficient" ) );
270 if ( resMgr->hasValue( material, "back_specular-coefficient" ) ) {
271 setReflection( Specular, resMgr->doubleValue( material, "back_specular-coefficient" ), false );
273 if ( resMgr->hasValue( material, "specular" ) ) {
274 setReflection( Specular, resMgr->booleanValue( material, "specular" ) );
277 // emissive reflection
278 if ( resMgr->hasValue( material, "emissive-color" ) ) {
279 setColor( Emissive, resMgr->colorValue( material, "emissive-color" ) );
281 if ( resMgr->hasValue( material, "front_emissive-coefficient" ) ) {
282 setReflection( Emissive, resMgr->doubleValue( material, "front_emissive-coefficient" ) );
284 if ( resMgr->hasValue( material, "back_emissive-coefficient" ) ) {
285 setReflection( Emissive, resMgr->doubleValue( material, "back_emissive-coefficient" ), false );
287 if ( resMgr->hasValue( material, "emissive" ) ) {
288 setReflection( Emissive, resMgr->booleanValue( material, "emissive" ) );
293 \brief Save material properties to the resource file.
294 \param material material name
295 \param resMgr resource manager
298 void Material_Model::toResources( const QString& material, Material_ResourceMgr* resMgr )
300 if ( resMgr && !material.isEmpty() ) {
301 // lock resources manager
302 QMutexLocker lock( &resMgr->myMutex );
304 // remove resources section (to clean-up all previous properties)
305 resMgr->remove( material );
308 resMgr->setValue( material, "physical", isPhysical() );
311 resMgr->setValue( material, "front_shininess", shininess( true) );
312 resMgr->setValue( material, "back_shininess", shininess( false ) );
315 resMgr->setValue( material, "transparency", transparency() );
317 // ambient reflection
318 if ( color( Ambient ).isValid() )
319 resMgr->setValue( material, "ambient-color", color( Ambient ) );
320 resMgr->setValue( material, "front_ambient-coefficient", reflection( Ambient ) );
321 resMgr->setValue( material, "back_ambient-coefficient", reflection( Ambient, false ) );
322 resMgr->setValue( material, "ambient", hasReflection( Ambient ) );
324 // diffuse reflection
325 if ( color( Diffuse ).isValid() )
326 resMgr->setValue( material, "diffuse-color", color( Diffuse ) );
327 resMgr->setValue( material, "front_diffuse-coefficient", reflection( Diffuse ) );
328 resMgr->setValue( material, "back_diffuse-coefficient", reflection( Diffuse, false ) );
329 resMgr->setValue( material, "diffuse", hasReflection( Diffuse ) );
331 // Specular reflection
332 if ( color( Specular ).isValid() )
333 resMgr->setValue( material, "specular-color", color( Specular ) );
334 resMgr->setValue( material, "front_specular-coefficient", reflection( Specular ) );
335 resMgr->setValue( material, "back_specular-coefficient", reflection( Specular, false ) );
336 resMgr->setValue( material, "specular", hasReflection( Specular ) );
338 // Emissive reflection
339 if ( color( Emissive ).isValid() )
340 resMgr->setValue( material, "emissive-color", color( Emissive ) );
341 resMgr->setValue( material, "front_emissive-coefficient", reflection( Emissive ) );
342 resMgr->setValue( material, "back_emissive-coefficient", reflection( Emissive, false ) );
343 resMgr->setValue( material, "emissive", hasReflection( Emissive ) );
348 \brief Get material type
349 \return \c true if material is physical or \c false otherwise
352 bool Material_Model::isPhysical() const
358 \brief Set material type
359 \param value \c true if material is physical or \c false otherwise
362 void Material_Model::setPhysical( bool value )
364 myIsPhysical = value;
368 \brief Check if given reflection is enabled
369 \param type reflection type
370 \return \c true if specified reflection type is enabled or \c false otherwise
371 \sa setReflection(ReflectionType, bool)
373 bool Material_Model::hasReflection( ReflectionType type ) const
376 if ( type >= 0 && type < 4 )
377 value = myReflection[ type ].enabled;
382 \brief Enable/disable given reflection type
383 \param type reflection type
384 \param value boolean flag
387 void Material_Model::setReflection( ReflectionType type, bool value )
389 if ( type >= 0 && type < 4 )
390 myReflection[ type ].enabled = value;
394 \brief Get color value for the given reflection type
395 \param type reflection type
396 \return color associated with the specified reflection type
399 QColor Material_Model::color( ReflectionType type ) const
402 if ( type >= 0 && type < 4 )
403 value = myReflection[ type ].color;
404 #if OCC_VERSION_LARGE >= 0x07040000
405 // Compatibility with previous OCCT versions, set for non-physical materials always white color
413 \brief Set color value for the given reflection type
414 \param type reflection type
415 \param value color to be used for specified reflection type
418 void Material_Model::setColor( ReflectionType type, const QColor& value )
420 if ( type >= 0 && type < 4 )
421 myReflection[ type ].color = value;
425 \brief Get coefficient value for the given reflection type
426 \param type reflection type
427 \param theIsFront boolean flag for choosing side
428 \return coefficient value for the specified reflection type
429 \sa setReflection(ReflectionType, double, bool = true)
431 double Material_Model::reflection( ReflectionType type, bool theIsFront ) const
434 if ( type >= 0 && type < 4 )
437 value = myReflection[ type ].front_coef;
439 value = myReflection[ type ].back_coef;
445 \brief Set coefficient value for the given reflection type
446 \param type reflection type
447 \param value coefficient to be used by the given reflection type
448 \param theIsFront boolean flag for choosing side
449 \sa reflection( bool = true)
451 void Material_Model::setReflection( ReflectionType type, double value, bool theIsFront )
453 if ( type >= 0 && type < 4 )
456 myReflection[ type ].front_coef = value;
458 myReflection[ type ].back_coef = value;
463 \brief Get shininess value
464 \param theIsFront boolean flag for choosing side
465 \return shininess value of the material
466 \sa setShininess( double, bool = true )
468 double Material_Model::shininess( bool theIsFront ) const
471 return myFrontShininess;
473 return myBackShininess;
477 \brief Set shininess value
478 \param value new shininess value
479 \param theIsFront boolean flag for choosing side
480 \sa shininess( bool = true )
482 void Material_Model::setShininess( double value, bool theIsFront )
485 myFrontShininess = value;
487 myBackShininess = value;
491 \brief Get transparency value
492 \return transparency value of the material
493 \sa setTransparency()
495 double Material_Model::transparency() const
497 return myTransparency;
501 \brief Set transparency value
502 \param value new transparency value
505 void Material_Model::setTransparency( double value )
507 myTransparency = value;
511 \brief Initialize material model with default values
513 void Material_Model::init()
517 // non-physical by default
518 setPhysical( false );
520 setShininess( 0.039 );
521 setShininess( 0.039, false );
523 setTransparency( 0.0 );
525 // ambient reflection (enabled by default)
526 Qtx::stringToColor( "#333333", c );
527 setColor( Ambient, c );
528 setReflection( Ambient, 0.3, true );
529 setReflection( Ambient, 0.3, false );
530 setReflection( Ambient, true );
532 // diffuse reflection (enabled by default)
533 Qtx::stringToColor( "#000000", c );
534 setColor( Diffuse, c );
535 setReflection( Diffuse, 0.65 );
536 setReflection( Diffuse, 0.65, false );
537 setReflection( Diffuse, true );
539 // specular reflection (enabled by default)
540 Qtx::stringToColor( "#ffffff", c );
541 setColor( Specular, c );
542 setReflection( Specular, 0.0 );
543 setReflection( Specular, 0.0, false );
544 setReflection( Specular, true );
546 // emissive reflection (disabled by default)
547 Qtx::stringToColor( "#000000", c );
548 setColor( Emissive, c );
549 setReflection( Emissive, 0.0 );
550 setReflection( Emissive, 0.0, false );
551 setReflection( Emissive, false );
555 \brief Construct OCCT material aspect from material model
556 \param theIsFront boolean flag for choosing side
557 \return material aspect object with corresponding properties
559 Graphic3d_MaterialAspect Material_Model::getMaterialOCCAspect( bool theIsFront )
561 // Get material aspect from the current model
562 Graphic3d_MaterialAspect aspect;
566 // ambient reflection
567 #if OCC_VERSION_LARGE >= 0x07040000
568 if ( color( Ambient ).isValid() ) {
569 c = color( Ambient );
570 aspect.SetAmbientColor( Quantity_Color( Graphic3d_Vec3( c.redF(), c.greenF(), c.blueF() ) * reflection( Ambient, theIsFront ) ) );
572 if ( !hasReflection( Ambient ) )
573 aspect.SetAmbientColor( Quantity_NOC_BLACK );
575 if ( color( Ambient ).isValid() ) {
576 c = color( Ambient );
577 aspect.SetAmbientColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
579 aspect.SetAmbient( reflection( Ambient, theIsFront ));
580 if ( hasReflection( Ambient ) )
581 aspect.SetReflectionModeOn( Graphic3d_TOR_AMBIENT );
583 aspect.SetReflectionModeOff( Graphic3d_TOR_AMBIENT );
586 // diffuse reflection
587 #if OCC_VERSION_LARGE >= 0x07040000
588 if ( color( Diffuse ).isValid() ) {
589 c = color( Diffuse );
590 aspect.SetDiffuseColor( Quantity_Color( Graphic3d_Vec3( c.redF(), c.greenF(), c.blueF() ) * reflection( Diffuse, theIsFront ) ) );
592 if ( !hasReflection( Diffuse ) )
593 aspect.SetDiffuseColor( Quantity_NOC_BLACK );
595 if ( color( Diffuse ).isValid() ) {
596 c = color( Diffuse );
597 aspect.SetDiffuseColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
599 aspect.SetDiffuse( reflection( Diffuse, theIsFront ));
600 if ( hasReflection( Diffuse ) )
601 aspect.SetReflectionModeOn( Graphic3d_TOR_DIFFUSE );
603 aspect.SetReflectionModeOff( Graphic3d_TOR_DIFFUSE );
606 // specular reflection
607 #if OCC_VERSION_LARGE >= 0x07040000
608 if ( color( Specular ).isValid() ) {
609 c = color( Specular );
610 aspect.SetSpecularColor( Quantity_Color( Graphic3d_Vec3( c.redF(), c.greenF(), c.blueF() ) * reflection( Specular, theIsFront ) ) );
612 if ( !hasReflection( Specular ) )
613 aspect.SetSpecularColor( Quantity_NOC_BLACK );
615 if ( color( Specular ).isValid() ) {
616 c = color( Specular );
617 aspect.SetSpecularColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
619 aspect.SetSpecular( reflection( Specular, theIsFront ));
620 if ( hasReflection( Specular ) )
621 aspect.SetReflectionModeOn( Graphic3d_TOR_SPECULAR );
623 aspect.SetReflectionModeOff( Graphic3d_TOR_SPECULAR );
626 // emissive reflection
627 #if OCC_VERSION_LARGE >= 0x07040000
628 if ( color( Emissive ).isValid() ) {
629 c = color( Emissive );
630 aspect.SetEmissiveColor( Quantity_Color( Graphic3d_Vec3( c.redF(), c.greenF(), c.blueF() ) * reflection( Emissive, theIsFront ) ) );
632 if ( !hasReflection( Emissive ) )
633 aspect.SetEmissiveColor( Quantity_NOC_BLACK );
635 if ( color( Emissive ).isValid() ) {
636 c = color( Emissive );
637 aspect.SetEmissiveColor( Quantity_Color( c.redF(), c.greenF(), c.blueF(), Quantity_TOC_RGB ) );
639 aspect.SetEmissive( reflection( Emissive, theIsFront ));
640 if ( hasReflection( Emissive ) )
641 aspect.SetReflectionModeOn( Graphic3d_TOR_EMISSION );
643 aspect.SetReflectionModeOff( Graphic3d_TOR_EMISSION );
647 aspect.SetShininess( shininess( theIsFront ) );
650 aspect.SetTransparency( transparency() );
653 aspect.SetMaterialType( isPhysical() ? Graphic3d_MATERIAL_PHYSIC : Graphic3d_MATERIAL_ASPECT );
659 \brief Construct VTK property from material model
660 \param theIsFront boolean flag for choosing side
661 \return VTK property with correspondent material properties
663 GEOM_VTKPropertyMaterial* Material_Model::getMaterialVTKProperty( bool theIsFront )
665 // NOTE: In VTK it's impossible to switch on/off specific reflection type
666 // NOTE: In VTK emissive reflection type is not supported
667 // NOTE: In VTK shininess is specified via SpecularPower attribute
668 // NOTE: In VTK transparency is specified via Opacity attribute
670 // Get material properties from the current model
671 GEOM_VTKPropertyMaterial* prop = GEOM_VTKPropertyMaterial::New();
675 // ambient reflection
676 if ( color( Ambient ).isValid() && hasReflection( Ambient ) ) {
677 c = color( Ambient );
678 prop->SetAmbientColor( c.redF(), c.greenF(), c.blueF() );
679 prop->SetAmbient( reflection( Ambient, theIsFront ) );
682 // diffuse reflection
683 if ( color( Diffuse ).isValid() && hasReflection( Diffuse ) ) {
684 c = color( Diffuse );
685 prop->SetDiffuseColor( c.redF(), c.greenF(), c.blueF() );
686 prop->SetDiffuse( reflection( Diffuse, theIsFront ) );
689 // specular reflection
690 if ( color( Specular ).isValid() && hasReflection( Specular ) ) {
691 c = color( Specular );
692 prop->SetSpecularColor( c.redF(), c.greenF(), c.blueF() );
693 prop->SetSpecular( reflection( Specular, theIsFront ) );
697 prop->SetSpecularPower( shininess( theIsFront )*100.0 );
700 prop->SetOpacity( 1 - transparency() );
703 prop->SetPhysical( isPhysical() );