summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2021-11-04 19:30:56 +0100
committerRegina Henschel <rb.henschel@t-online.de>2021-11-06 15:35:46 +0100
commit70a4cb766ed356bc17433ac1673e977bb0bf3d2f (patch)
tree32b12e24884cd76b404adc41f4f018ac14512f3d
parent32c01c6653b85082e2d5e03ab3095768402834eb (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>
-rw-r--r--svx/source/customshapes/EnhancedCustomShape3d.cxx70
-rw-r--r--svx/source/toolbars/extrusionbar.cxx84
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" );