diff options
author | Regina Henschel <rb.henschel@t-online.de> | 2021-11-04 19:30:56 +0100 |
---|---|---|
committer | Regina Henschel <rb.henschel@t-online.de> | 2021-11-06 15:35:46 +0100 |
commit | 70a4cb766ed356bc17433ac1673e977bb0bf3d2f (patch) | |
tree | 32b12e24884cd76b404adc41f4f018ac14512f3d /svx | |
parent | 32c01c6653b85082e2d5e03ab3095768402834eb (diff) |
tdf#140321 enable 'matte', 'metal' extrusion surface
The patch makes extrusion surface presets 'matte', 'plastic' and 'metal'
look different from another. That has been broken from the beginning of
custom shape extrusion in OOo2.
To get 'matte' ODF conform, property first-light-harsh is enable.
To keep smooth rendering set by PowerPoint, forcing shade mode 'flat'
is removed.
For more details about the change see comment in bug tdf#140321.
Change-Id: Idd1e0af19ea3f7e604da7f10330c6f9e640d08f8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124720
Tested-by: Jenkins
Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
Diffstat (limited to 'svx')
-rw-r--r-- | svx/source/customshapes/EnhancedCustomShape3d.cxx | 70 | ||||
-rw-r--r-- | svx/source/toolbars/extrusionbar.cxx | 84 |
2 files changed, 107 insertions, 47 deletions
diff --git a/svx/source/customshapes/EnhancedCustomShape3d.cxx b/svx/source/customshapes/EnhancedCustomShape3d.cxx index 05bb45f4a9cf..7b847c381835 100644 --- a/svx/source/customshapes/EnhancedCustomShape3d.cxx +++ b/svx/source/customshapes/EnhancedCustomShape3d.cxx @@ -41,6 +41,7 @@ #include <svx/scene3d.hxx> #include <com/sun/star/drawing/Position3D.hpp> #include <com/sun/star/drawing/Direction3D.hpp> +#include <com/sun/star/drawing/NormalsKind.hpp> #include <com/sun/star/drawing/ShadeMode.hpp> #include <svx/sdr/properties/properties.hxx> #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp> @@ -327,10 +328,14 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( bool bUseExtrusionColor = GetBool( rGeometryItem, "Color", false ); drawing::FillStyle eFillStyle( aSet.Get(XATTR_FILLSTYLE).GetValue() ); - pScene->GetProperties().SetObjectItem( Svx3DShadeModeItem( 0 ) ); + pScene->GetProperties().SetObjectItem( Svx3DShadeModeItem(static_cast<sal_uInt16>(eShadeMode))); aSet.Put( makeSvx3DPercentDiagonalItem( 0 ) ); aSet.Put( Svx3DTextureModeItem( 1 ) ); - aSet.Put( Svx3DNormalsKindItem( 1 ) ); + // SPECIFIC needed for ShadeMode_SMOOTH and ShadeMode_PHONG, otherwise FLAT is faster + if (eShadeMode == drawing::ShadeMode_SMOOTH || eShadeMode == drawing::ShadeMode_PHONG) + aSet.Put( Svx3DNormalsKindItem(static_cast<sal_uInt16>(drawing::NormalsKind_SPECIFIC))); + else + aSet.Put( Svx3DNormalsKindItem(static_cast<sal_uInt16>(drawing::NormalsKind_FLAT))); if ( eShadeMode == drawing::ShadeMode_DRAFT ) { @@ -656,7 +661,6 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( // light - double fAmbientIntensity = GetDouble( rGeometryItem, "Brightness", 22178.0 / 655.36 ) / 100.0; drawing::Direction3D aFirstLightDirectionDefault( 50000, 0, 10000 ); drawing::Direction3D aFirstLightDirection( GetDirection3D( rGeometryItem, "FirstLightDirection", aFirstLightDirectionDefault ) ); @@ -665,7 +669,7 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( double fLightIntensity = GetDouble( rGeometryItem, "FirstLightLevel", 43712.0 / 655.36 ) / 100.0; - /* sal_Bool bFirstLightHarsh = */ GetBool( rGeometryItem, "FirstLightHarsh", false ); + bool bFirstLightHarsh = GetBool( rGeometryItem, "FirstLightHarsh", true ); drawing::Direction3D aSecondLightDirectionDefault( -50000, 0, 10000 ); drawing::Direction3D aSecondLightDirection( GetDirection3D( rGeometryItem, "SecondLightDirection", aSecondLightDirectionDefault ) ); @@ -677,6 +681,21 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( /* sal_Bool bLight2Harsh = */ GetBool( rGeometryItem, "SecondLightHarsh", false ); /* sal_Bool bLightFace = */ GetBool( rGeometryItem, "LightFace", false ); + double fAmbientIntensity = GetDouble( rGeometryItem, "Brightness", 22178.0 / 655.36 ) / 100.0; + bool bMetal = GetBool( rGeometryItem, "Metal", false ); + + // Currently needed for import from binar MS Office. + // ToDo: Create a solution in the filters. + // MS Office adds black to diffuse and ambient color in case of metal. Use an + // approximating ersatz. + if (bMetal) + { + fAmbientIntensity -= 0.15; // Estimated value. Adapt it if necessary. + fAmbientIntensity = std::clamp(fAmbientIntensity, 0.0, 1.0); + fLight2Intensity -= 0.15; + fLight2Intensity = std::clamp(fLight2Intensity, 0.0, 1.0); + } + sal_uInt16 nAmbientColor = static_cast<sal_uInt16>( fAmbientIntensity * 255.0 ); if ( nAmbientColor > 255 ) nAmbientColor = 255; @@ -699,6 +718,9 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( pScene->GetProperties().SetObjectItem( makeSvx3DLightcolor2Item( aAmbientSpot2Color ) ); pScene->GetProperties().SetObjectItem( makeSvx3DLightDirection2Item( aSpotLight2 ) ); + // Currently needed for import from binary MS Office. + // ToDo: Create a solution in the filters. + // Binary MS Office creates brighter shapes than our 3D engine with same values. sal_uInt8 nSpotLight3 = 70; basegfx::B3DVector aSpotLight3( 0.0, 0.0, 1.0 ); pScene->GetProperties().SetObjectItem( makeSvx3DLightOnOff3Item( true ) ); @@ -706,23 +728,37 @@ SdrObject* EnhancedCustomShape3d::Create3DObject( pScene->GetProperties().SetObjectItem( makeSvx3DLightcolor3Item( aAmbientSpot3Color ) ); pScene->GetProperties().SetObjectItem( makeSvx3DLightDirection3Item( aSpotLight3 ) ); - double fSpecular = GetDouble( rGeometryItem, "Specularity", 0 ) / 100; - bool bMetal = GetBool( rGeometryItem, "Metal", false ); - - Color aSpecularCol( 225,225,225 ); + double fSpecular = GetDouble( rGeometryItem, "Specularity", 0 ); + // ODF specifies 'white', OOXML uses shape fill color in some presets + Color aSpecularCol(255, 255, 255); if ( bMetal ) { + // values as specified in ODF aSpecularCol = Color( 200, 200, 200 ); - fSpecular += 0.15; + fSpecular += 15.0; + } + sal_Int32 nIntensity = 100 - static_cast<sal_Int32>(fSpecular); + nIntensity = std::clamp<sal_Int32>(nIntensity, 0, 100); + + // specularity is an object property, not a scene property + SdrObjListIter aSceneIter( *pScene, SdrIterMode::DeepNoGroups ); + while (aSceneIter.IsMore()) + { + const SdrObject* pNext = aSceneIter.Next(); + pNext->GetProperties().SetObjectItem(makeSvx3DMaterialSpecularItem(aSpecularCol)); + pNext->GetProperties().SetObjectItem(makeSvx3DMaterialSpecularIntensityItem(static_cast<sal_uInt16>(nIntensity))); + } + + // fSpecular = 0 is used to indicate surface preset "matte". + if (!bFirstLightHarsh || basegfx::fTools::equalZero(fSpecular, 0.0001)) + { + // First light in LO 3D engine is always specular, all other lights are never specular. + // We copy light1 values to light4 and use it instead of light1 in the 3D scene. + pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff1Item(false)); + pScene->GetProperties().SetObjectItem(makeSvx3DLightOnOff4Item(true)); + pScene->GetProperties().SetObjectItem(makeSvx3DLightcolor4Item(aAmbientSpot1Color)); + pScene->GetProperties().SetObjectItem(makeSvx3DLightDirection4Item(aSpotLight1)); } - sal_Int32 nIntensity = static_cast<sal_Int32>(fSpecular) * 100; - if ( nIntensity > 100 ) - nIntensity = 100; - else if ( nIntensity < 0 ) - nIntensity = 0; - nIntensity = 100 - nIntensity; - pScene->GetProperties().SetObjectItem( makeSvx3DMaterialSpecularItem( aSpecularCol ) ); - pScene->GetProperties().SetObjectItem( makeSvx3DMaterialSpecularIntensityItem( static_cast<sal_uInt16>(nIntensity) ) ); pScene->SetLogicRect( CalculateNewSnapRect( diff --git a/svx/source/toolbars/extrusionbar.cxx b/svx/source/toolbars/extrusionbar.cxx index 90af6561d6ff..659af238d77e 100644 --- a/svx/source/toolbars/extrusionbar.cxx +++ b/svx/source/toolbars/extrusionbar.cxx @@ -40,6 +40,7 @@ #include <svx/sdasitm.hxx> #include <svl/intitem.hxx> #include <rtl/math.hxx> +#include <basegfx/numeric/ftools.hxx> #include <svx/extrusionbar.hxx> #include <extrusiondepthdialog.hxx> @@ -321,25 +322,54 @@ static void impl_execute( SfxRequest const & rReq, SdrCustomShapeGeometryItem& r { sal_Int32 nSurface = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_SURFACE)->GetValue(); - ShadeMode eShadeMode( ShadeMode_FLAT ); - bool bMetal = false; - double fSpecularity = 0; - double fDiffusion = 0; + // Set ShadeMode only when changing from or to wireframe, otherwise keep existing value. + ShadeMode eOldShadeMode(ShadeMode_FLAT); + css::uno::Any* pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"ShadeMode"); + if (pAny) + *pAny >>= eOldShadeMode; + ShadeMode eShadeMode(eOldShadeMode); + switch (nSurface) + { + case 0: // wireframe + eShadeMode = ShadeMode_DRAFT; + break; + case 1: // matte + case 2: // plastic + case 3: // metal + if (eOldShadeMode == ShadeMode_DRAFT) + eShadeMode = ShadeMode_FLAT; // ODF default + break; + } + bool bMetal = nSurface == 3; + + // ODF has no dedicated property for 'surface'. MS Office binary format uses attribute + // c3DSpecularAmt to distinguish between 'matte' (=0) and 'plastic'. + // From point of ODF, using not harsh light has similar effect. + double fOldSpecularity = 0.0; + pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"Specularity"); + if (pAny) + *pAny >>= fOldSpecularity; + double fSpecularity = fOldSpecularity; + bool bOldIsFirstLightHarsh = true; + pAny = rGeometryItem.GetPropertyValueByName(sExtrusion, u"FirstLightHarsh"); + if (pAny) + *pAny >>= bOldIsFirstLightHarsh; + bool bIsFirstLightHarsh = bOldIsFirstLightHarsh; switch( nSurface ) { case 0: // wireframe - eShadeMode = ShadeMode_DRAFT; break; case 1: // matte + fSpecularity = 0.0; + bIsFirstLightHarsh = false; break; case 2: // plastic - fSpecularity = 122.0; - break; case 3: // metal - bMetal = true; - fSpecularity = 122.0; - fDiffusion = 122.0; + if (basegfx::fTools::equalZero(fOldSpecularity, 0.0001)) + fSpecularity = 80; // estimated value, can be changed if necessary + if (!bOldIsFirstLightHarsh) + bIsFirstLightHarsh = true; break; } @@ -352,13 +382,19 @@ static void impl_execute( SfxRequest const & rReq, SdrCustomShapeGeometryItem& r aPropValue.Value <<= bMetal; rGeometryItem.SetPropertyValue( sExtrusion, aPropValue ); - aPropValue.Name = "Specularity"; - aPropValue.Value <<= fSpecularity; - rGeometryItem.SetPropertyValue( sExtrusion, aPropValue ); + if (!basegfx::fTools::equalZero(fOldSpecularity - fSpecularity, 0.0001)) + { + aPropValue.Name = "Specularity"; + aPropValue.Value <<= fSpecularity; + rGeometryItem.SetPropertyValue(sExtrusion, aPropValue); + } - aPropValue.Name = "Diffusion"; - aPropValue.Value <<= fDiffusion; - rGeometryItem.SetPropertyValue( sExtrusion, aPropValue ); + if (bOldIsFirstLightHarsh != bIsFirstLightHarsh) + { + aPropValue.Name = "FirstLightHarsh"; + aPropValue.Value <<= bIsFirstLightHarsh; + rGeometryItem.SetPropertyValue(sExtrusion, aPropValue); + } } } break; @@ -369,7 +405,6 @@ static void impl_execute( SfxRequest const & rReq, SdrCustomShapeGeometryItem& r sal_Int32 nLevel = rReq.GetArgs()->GetItem<SfxInt32Item>(SID_EXTRUSION_LIGHTING_INTENSITY)->GetValue(); double fBrightness; - bool bHarsh2 = false; double fLevel1; double fLevel2; @@ -377,19 +412,16 @@ static void impl_execute( SfxRequest const & rReq, SdrCustomShapeGeometryItem& r { case 0: // bright fBrightness = 34.0; - bHarsh2 = false; fLevel1 = 66.0; fLevel2 = 66.0; break; case 1: // normal fBrightness = 15.0; - bHarsh2 = false; fLevel1 = 67.0; fLevel2 = 37.0; break; case 2: // dim fBrightness = 6.0; - bHarsh2 = true; fLevel1 = 79.0; fLevel2 = 21.0; break; @@ -400,16 +432,8 @@ static void impl_execute( SfxRequest const & rReq, SdrCustomShapeGeometryItem& r aPropValue.Value <<= fBrightness; rGeometryItem.SetPropertyValue( sExtrusion, aPropValue ); - aPropValue.Name = "LightFace"; - aPropValue.Value <<= true; - rGeometryItem.SetPropertyValue( sExtrusion, aPropValue ); - - aPropValue.Name = "FirstLightHarsh"; - aPropValue.Value <<= true; - rGeometryItem.SetPropertyValue( sExtrusion, aPropValue ); - aPropValue.Name = "SecondLightHarsh"; - aPropValue.Value <<= bHarsh2; + aPropValue.Value <<= false; rGeometryItem.SetPropertyValue( sExtrusion, aPropValue ); aPropValue.Name = "FirstLightLevel"; @@ -849,7 +873,7 @@ static void getExtrusionSurfaceState( SdrView const * pSdrView, SfxItemSet& rSet if( pAny ) *pAny >>= eShadeMode; - if( eShadeMode == ShadeMode_FLAT ) + if (eShadeMode != ShadeMode_DRAFT) { bool bMetal = false; pAny = rGeometryItem.GetPropertyValueByName( sExtrusion, "Metal" ); |