summaryrefslogtreecommitdiffstats
path: root/svx/source/engine3d
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--svx/source/engine3d/camera3d.cxx180
-rw-r--r--svx/source/engine3d/cube3d.cxx157
-rw-r--r--svx/source/engine3d/deflt3d.cxx56
-rw-r--r--svx/source/engine3d/dragmt3d.cxx732
-rw-r--r--svx/source/engine3d/e3dsceneupdater.cxx111
-rw-r--r--svx/source/engine3d/e3dundo.cxx91
-rw-r--r--svx/source/engine3d/extrud3d.cxx223
-rw-r--r--svx/source/engine3d/float3d.cxx2949
-rw-r--r--svx/source/engine3d/helperhittest3d.cxx277
-rw-r--r--svx/source/engine3d/helperminimaldepth3d.cxx201
-rw-r--r--svx/source/engine3d/helperminimaldepth3d.hxx48
-rw-r--r--svx/source/engine3d/lathe3d.cxx205
-rw-r--r--svx/source/engine3d/obj3d.cxx625
-rw-r--r--svx/source/engine3d/objfac3d.cxx73
-rw-r--r--svx/source/engine3d/polygn3d.cxx248
-rw-r--r--svx/source/engine3d/scene3d.cxx909
-rw-r--r--svx/source/engine3d/sphere3d.cxx153
-rw-r--r--svx/source/engine3d/svx3ditems.cxx266
-rw-r--r--svx/source/engine3d/view3d.cxx1599
-rw-r--r--svx/source/engine3d/view3d1.cxx177
-rw-r--r--svx/source/engine3d/viewpt3d2.cxx153
21 files changed, 9433 insertions, 0 deletions
diff --git a/svx/source/engine3d/camera3d.cxx b/svx/source/engine3d/camera3d.cxx
new file mode 100644
index 000000000..abb7b3991
--- /dev/null
+++ b/svx/source/engine3d/camera3d.cxx
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/camera3d.hxx>
+
+Camera3D::Camera3D(const basegfx::B3DPoint& rPos, const basegfx::B3DPoint& rLookAt,
+ double fFocalLen) :
+ fBankAngle(0),
+ bAutoAdjustProjection(true)
+{
+ SetPosition(rPos);
+ SetLookAt(rLookAt);
+ SetFocalLength(fFocalLen);
+}
+
+Camera3D::Camera3D()
+ : fFocalLength(35.0)
+ , fBankAngle(0.0)
+ , bAutoAdjustProjection(false)
+{
+}
+
+// Set ViewWindow and adjust PRP
+
+void Camera3D::SetViewWindow(double fX, double fY, double fW, double fH)
+{
+ Viewport3D::SetViewWindow(fX, fY, fW, fH);
+ if ( bAutoAdjustProjection )
+ SetFocalLength(fFocalLength);
+}
+
+void Camera3D::SetPosition(const basegfx::B3DPoint& rNewPos)
+{
+ if ( rNewPos != aPosition )
+ {
+ aPosition = rNewPos;
+ SetVRP(aPosition);
+ SetVPN(aPosition - aLookAt);
+ SetBankAngle(fBankAngle);
+ }
+}
+
+void Camera3D::SetLookAt(const basegfx::B3DPoint& rNewLookAt)
+{
+ if ( rNewLookAt != aLookAt )
+ {
+ aLookAt = rNewLookAt;
+ SetVPN(aPosition - aLookAt);
+ SetBankAngle(fBankAngle);
+ }
+}
+
+void Camera3D::SetPosAndLookAt(const basegfx::B3DPoint& rNewPos,
+ const basegfx::B3DPoint& rNewLookAt)
+{
+ if ( rNewPos != aPosition || rNewLookAt != aLookAt )
+ {
+ aPosition = rNewPos;
+ aLookAt = rNewLookAt;
+
+ SetVRP(aPosition);
+ SetVPN(aPosition - aLookAt);
+ SetBankAngle(fBankAngle);
+ }
+}
+
+void Camera3D::SetBankAngle(double fAngle)
+{
+ basegfx::B3DVector aDiff(aPosition - aLookAt);
+ basegfx::B3DVector aPrj(aDiff);
+ fBankAngle = fAngle;
+
+ if ( aDiff.getY() == 0 )
+ {
+ aPrj.setY(-1.0);
+ }
+ else
+ { // aPrj = Projection from aDiff on the XZ-plane
+ aPrj.setY(0.0);
+
+ if ( aDiff.getY() < 0.0 )
+ {
+ aPrj = -aPrj;
+ }
+ }
+
+ // Calculate from aDiff to upwards pointing View-Up-Vector
+ // duplicated line is intentional!
+ aPrj = aPrj.getPerpendicular(aDiff);
+ aPrj = aPrj.getPerpendicular(aDiff);
+ aDiff.normalize();
+
+ // Rotate on Z axis, to rotate the BankAngle and back
+ basegfx::B3DHomMatrix aTf;
+ const double fV(sqrt(aDiff.getY() * aDiff.getY() + aDiff.getZ() * aDiff.getZ()));
+
+ if ( fV != 0.0 )
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(aDiff.getY() / fV);
+ const double fCos(aDiff.getZ() / fV);
+
+ aTemp.set(1, 1, fCos);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(2, 1, fSin);
+ aTemp.set(1, 2, -fSin);
+
+ aTf *= aTemp;
+ }
+
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(-aDiff.getX());
+ const double fCos(fV);
+
+ aTemp.set(0, 0, fCos);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(0, 2, fSin);
+ aTemp.set(2, 0, -fSin);
+
+ aTf *= aTemp;
+ }
+
+ aTf.rotate(0.0, 0.0, fBankAngle);
+
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(aDiff.getX());
+ const double fCos(fV);
+
+ aTemp.set(0, 0, fCos);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(0, 2, fSin);
+ aTemp.set(2, 0, -fSin);
+
+ aTf *= aTemp;
+ }
+
+ if ( fV != 0.0 )
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(-aDiff.getY() / fV);
+ const double fCos(aDiff.getZ() / fV);
+
+ aTemp.set(1, 1, fCos);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(2, 1, fSin);
+ aTemp.set(1, 2, -fSin);
+
+ aTf *= aTemp;
+ }
+
+ SetVUV(aTf * aPrj);
+}
+
+void Camera3D::SetFocalLength(double fLen)
+{
+ if ( fLen < 5 )
+ fLen = 5;
+ SetPRP(basegfx::B3DPoint(0.0, 0.0, fLen / 35.0 * aViewWin.W));
+ fFocalLength = fLen;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/cube3d.cxx b/svx/source/engine3d/cube3d.cxx
new file mode 100644
index 000000000..401e1b085
--- /dev/null
+++ b/svx/source/engine3d/cube3d.cxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/strings.hrc>
+#include <svx/deflt3d.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/cube3d.hxx>
+#include <svx/globl3d.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <sdr/contact/viewcontactofe3dcube.hxx>
+#include <rtl/ustrbuf.hxx>
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> E3dCubeObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dCube>(*this);
+}
+
+
+E3dCubeObj::E3dCubeObj(
+ SdrModel& rSdrModel,
+ const E3dDefaultAttributes& rDefault,
+ const basegfx::B3DPoint& aPos,
+ const basegfx::B3DVector& r3DSize)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set Defaults
+ SetDefaultAttributes(rDefault);
+
+ // position centre or left, bottom, back (dependent on bPosIsCenter)
+ aCubePos = aPos;
+ aCubeSize = r3DSize;
+}
+
+E3dCubeObj::E3dCubeObj(SdrModel& rSdrModel)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set Defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+}
+
+E3dCubeObj::~E3dCubeObj()
+{
+}
+
+void E3dCubeObj::SetDefaultAttributes(const E3dDefaultAttributes& rDefault)
+{
+ aCubePos = rDefault.GetDefaultCubePos();
+ aCubeSize = rDefault.GetDefaultCubeSize();
+ bPosIsCenter = rDefault.GetDefaultCubePosIsCenter();
+}
+
+sal_uInt16 E3dCubeObj::GetObjIdentifier() const
+{
+ return E3D_CUBEOBJ_ID;
+}
+
+// Convert the object into a group object consisting of 6 polygons
+
+SdrObjectUniquePtr E3dCubeObj::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
+{
+ return nullptr;
+}
+
+E3dCubeObj* E3dCubeObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return CloneHelper< E3dCubeObj >(rTargetModel);
+}
+
+E3dCubeObj& E3dCubeObj::operator=(const E3dCubeObj& rObj)
+{
+ if( this == &rObj )
+ return *this;
+ E3dCompoundObject::operator=(rObj);
+
+ aCubePos = rObj.aCubePos;
+ aCubeSize = rObj.aCubeSize;
+ bPosIsCenter = rObj.bPosIsCenter;
+
+ return *this;
+}
+
+// Set local parameters with geometry re-creating
+
+void E3dCubeObj::SetCubePos(const basegfx::B3DPoint& rNew)
+{
+ if(aCubePos != rNew)
+ {
+ aCubePos = rNew;
+ ActionChanged();
+ }
+}
+
+void E3dCubeObj::SetCubeSize(const basegfx::B3DVector& rNew)
+{
+ if(aCubeSize != rNew)
+ {
+ aCubeSize = rNew;
+ ActionChanged();
+ }
+}
+
+void E3dCubeObj::SetPosIsCenter(bool bNew)
+{
+ if(bPosIsCenter != bNew)
+ {
+ bPosIsCenter = bNew;
+ ActionChanged();
+ }
+}
+
+// Get the name of the object (singular)
+
+OUString E3dCubeObj::TakeObjNameSingul() const
+{
+ OUStringBuffer sName(SvxResId(STR_ObjNameSingulCube3d));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName.append(' ');
+ sName.append('\'');
+ sName.append(aName);
+ sName.append('\'');
+ }
+ return sName.makeStringAndClear();
+}
+
+// Get the name of the object (plural)
+
+OUString E3dCubeObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralCube3d);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/deflt3d.cxx b/svx/source/engine3d/deflt3d.cxx
new file mode 100644
index 000000000..76589032b
--- /dev/null
+++ b/svx/source/engine3d/deflt3d.cxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/deflt3d.hxx>
+
+// Class to manage the 3D default attributes
+
+E3dDefaultAttributes::E3dDefaultAttributes()
+{
+ Reset();
+}
+
+void E3dDefaultAttributes::Reset()
+{
+ // Cube object
+ aDefaultCubePos = basegfx::B3DPoint(-500.0, -500.0, -500.0);
+ aDefaultCubeSize = basegfx::B3DVector(1000.0, 1000.0, 1000.0);
+ bDefaultCubePosIsCenter = false;
+
+ // Sphere object
+ aDefaultSphereCenter = basegfx::B3DPoint(0.0, 0.0, 0.0);
+ aDefaultSphereSize = basegfx::B3DPoint(1000.0, 1000.0, 1000.0);
+
+ // Lathe object
+ bDefaultLatheSmoothed = true;
+ bDefaultLatheSmoothFrontBack = false;
+ bDefaultLatheCharacterMode = false;
+ bDefaultLatheCloseFront = true;
+ bDefaultLatheCloseBack = true;
+
+ // Extrude object
+ bDefaultExtrudeSmoothed = true;
+ bDefaultExtrudeSmoothFrontBack = false;
+ bDefaultExtrudeCharacterMode = false;
+ bDefaultExtrudeCloseFront = true;
+ bDefaultExtrudeCloseBack = true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/dragmt3d.cxx b/svx/source/engine3d/dragmt3d.cxx
new file mode 100644
index 000000000..231305eea
--- /dev/null
+++ b/svx/source/engine3d/dragmt3d.cxx
@@ -0,0 +1,732 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <dragmt3d.hxx>
+#include <o3tl/numeric.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svddrgmt.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/e3dundo.hxx>
+#include <svx/strings.hrc>
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+#include <svx/e3dsceneupdater.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <comphelper/lok.hxx>
+
+
+E3dDragMethod::E3dDragMethod (
+ SdrDragView &_rView,
+ const SdrMarkList& rMark,
+ E3dDragConstraint eConstr,
+ bool bFull)
+: SdrDragMethod(_rView),
+ meConstraint(eConstr),
+ mbMoveFull(bFull),
+ mbMovedAtAll(false)
+{
+ // Create a unit for all the 3D objects present in the selection
+ const size_t nCnt(rMark.GetMarkCount());
+
+ if(mbMoveFull)
+ {
+ // for non-visible 3D objects fallback to wireframe interaction
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ E3dObject* pE3dObj = dynamic_cast< E3dObject* >(rMark.GetMark(nObjs)->GetMarkedSdrObj());
+
+ if(pE3dObj)
+ {
+ if(!pE3dObj->HasFillStyle() && !pE3dObj->HasLineStyle())
+ {
+ mbMoveFull = false;
+ break;
+ }
+ }
+ }
+ }
+
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ E3dObject* pE3dObj = dynamic_cast< E3dObject* >(rMark.GetMark(nObjs)->GetMarkedSdrObj());
+
+ if(pE3dObj)
+ {
+ // fill new interaction unit
+ E3dDragMethodUnit aNewUnit(*pE3dObj);
+
+ // get transformations
+ aNewUnit.maInitTransform = aNewUnit.maTransform = pE3dObj->GetTransform();
+
+ if(nullptr != pE3dObj->getParentE3dSceneFromE3dObject())
+ {
+ // get transform between object and world, normally scene transform
+ aNewUnit.maInvDisplayTransform = aNewUnit.maDisplayTransform = pE3dObj->getParentE3dSceneFromE3dObject()->GetFullTransform();
+ aNewUnit.maInvDisplayTransform.invert();
+ }
+
+ if(!mbMoveFull)
+ {
+ // create wireframe visualisation for parent coordinate system
+ aNewUnit.maWireframePoly.clear();
+ aNewUnit.maWireframePoly = pE3dObj->CreateWireframe();
+ aNewUnit.maWireframePoly.transform(aNewUnit.maTransform);
+ }
+
+ // Determine FullBound
+ maFullBound.Union(pE3dObj->GetSnapRect());
+
+ // Insert Unit
+ maGrp.push_back(aNewUnit);
+ }
+ }
+}
+
+OUString E3dDragMethod::GetSdrDragComment() const
+{
+ return OUString();
+}
+
+// Create the wireframe model for all actions
+
+bool E3dDragMethod::BeginSdrDrag()
+{
+ if(E3dDragConstraint::Z == meConstraint)
+ {
+ const sal_uInt32 nCnt(maGrp.size());
+ DragStat().SetRef1( maFullBound.Center() );
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ rCandidate.mnStartAngle = GetAngle(DragStat().GetStart() - DragStat().GetRef1());
+ rCandidate.mnLastAngle = 0;
+ }
+ }
+ else
+ {
+ maLastPos = DragStat().GetStart();
+ }
+
+ if(!mbMoveFull)
+ {
+ Show();
+ }
+
+ return true;
+}
+
+bool E3dDragMethod::EndSdrDrag(bool /*bCopy*/)
+{
+ const sal_uInt32 nCnt(maGrp.size());
+
+ if(!mbMoveFull)
+ {
+ // Hide wireframe
+ Hide();
+ }
+
+ // Apply all transformations and create undo's
+ if(mbMovedAtAll)
+ {
+ const bool bUndo = getSdrDragView().IsUndoEnabled();
+ if( bUndo )
+ getSdrDragView().BegUndo(SvxResId(RID_SVX_3D_UNDO_ROTATE));
+ sal_uInt32 nOb(0);
+
+ for(nOb=0;nOb<nCnt;nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
+ rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
+ if( bUndo )
+ {
+ getSdrDragView().AddUndo(
+ std::make_unique<E3dRotateUndoAction>(
+ rCandidate.mr3DObj,
+ rCandidate.maInitTransform,
+ rCandidate.maTransform));
+ }
+ }
+ if( bUndo )
+ getSdrDragView().EndUndo();
+ }
+
+ return true;
+}
+
+void E3dDragMethod::CancelSdrDrag()
+{
+ if(mbMoveFull)
+ {
+ if(mbMovedAtAll)
+ {
+ const sal_uInt32 nCnt(maGrp.size());
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ // Restore transformation
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
+ rCandidate.mr3DObj.SetTransform(rCandidate.maInitTransform);
+ }
+ }
+ }
+ else
+ {
+ // Hide WireFrame
+ Hide();
+ }
+}
+
+// Common MoveSdrDrag()
+
+void E3dDragMethod::MoveSdrDrag(const Point& /*rPnt*/)
+{
+ mbMovedAtAll = true;
+}
+
+// Draw the wire frame model
+
+// for migration from XOR to overlay
+void E3dDragMethod::CreateOverlayGeometry(
+ sdr::overlay::OverlayManager& rOverlayManager,
+ const sdr::contact::ObjectContact& rObjectContact)
+{
+ // We do client-side object manipulation with the Kit API
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+
+ const sal_uInt32 nCnt(maGrp.size());
+ basegfx::B2DPolyPolygon aResult;
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ SdrPageView* pPV = getSdrDragView().GetSdrPageView();
+
+ if(pPV && pPV->HasMarkedObjPageView())
+ {
+ const basegfx::B3DPolyPolygon aCandidate(rCandidate.maWireframePoly);
+ const sal_uInt32 nPlyCnt(aCandidate.count());
+
+ if(nPlyCnt)
+ {
+ const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ const basegfx::B3DHomMatrix aWorldToView(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection() * aViewInfo3D.getOrientation());
+ const basegfx::B3DHomMatrix aTransform(aWorldToView * rCandidate.maDisplayTransform);
+
+ // transform to relative scene coordinates
+ basegfx::B2DPolyPolygon aPolyPolygon(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aCandidate, aTransform));
+
+ // transform to 2D view coordinates
+ aPolyPolygon.transform(rVCScene.getObjectTransformation());
+
+ aResult.append(aPolyPolygon);
+ }
+ }
+ }
+ }
+
+ if(aResult.count())
+ {
+ std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(
+ new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
+ aResult));
+
+ insertNewlyCreatedOverlayObjectForSdrDragMethod(
+ std::move(pNew),
+ rObjectContact,
+ rOverlayManager);
+ }
+}
+
+
+E3dDragRotate::E3dDragRotate(SdrDragView &_rView,
+ const SdrMarkList& rMark,
+ E3dDragConstraint eConstr,
+ bool bFull)
+: E3dDragMethod(_rView, rMark, eConstr, bFull)
+{
+ // Get center of all selected objects in eye coordinates
+ const sal_uInt32 nCnt(maGrp.size());
+
+ if(nCnt)
+ {
+ const E3dScene* pScene(maGrp[0].mr3DObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ basegfx::B3DPoint aObjCenter = rCandidate.mr3DObj.GetBoundVolume().getCenter();
+ const basegfx::B3DHomMatrix aTransform(aViewInfo3D.getOrientation() * rCandidate.maDisplayTransform * rCandidate.maInitTransform);
+
+ aObjCenter = aTransform * aObjCenter;
+ maGlobalCenter += aObjCenter;
+ }
+
+ // Divide by the number
+ if(nCnt > 1)
+ {
+ maGlobalCenter /= static_cast<double>(nCnt);
+ }
+
+ // get rotate center and transform to 3D eye coordinates
+ basegfx::B2DPoint aRotCenter2D(Ref1().X(), Ref1().Y());
+
+ // from world to relative scene using inverse getObjectTransformation()
+ basegfx::B2DHomMatrix aInverseObjectTransform(rVCScene.getObjectTransformation());
+ aInverseObjectTransform.invert();
+ aRotCenter2D = aInverseObjectTransform * aRotCenter2D;
+
+ // from 3D view to 3D eye
+ basegfx::B3DPoint aRotCenter3D(aRotCenter2D.getX(), aRotCenter2D.getY(), 0.0);
+ basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
+ aInverseViewToEye.invert();
+ aRotCenter3D = aInverseViewToEye * aRotCenter3D;
+
+ // Use X,Y of the RotCenter and depth of the common object centre
+ // as rotation point in the space
+ maGlobalCenter.setX(aRotCenter3D.getX());
+ maGlobalCenter.setY(aRotCenter3D.getY());
+ }
+ }
+}
+
+
+//The object is moved, determine the angle
+
+void E3dDragRotate::MoveSdrDrag(const Point& rPnt)
+{
+ // call parent
+ E3dDragMethod::MoveSdrDrag(rPnt);
+
+ if(DragStat().CheckMinMoved(rPnt))
+ {
+ // Get modifier
+ sal_uInt16 nModifier = 0;
+ if(dynamic_cast<const E3dView*>(&getSdrDragView()))
+ {
+ const MouseEvent& rLastMouse = static_cast<E3dView&>(getSdrDragView()).GetMouseEvent();
+ nModifier = rLastMouse.GetModifier();
+ }
+
+ // Rotate all objects
+ const sal_uInt32 nCnt(maGrp.size());
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ // Determine rotation angle
+ double fWAngle, fHAngle;
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+
+ if(E3dDragConstraint::Z == meConstraint)
+ {
+ fWAngle = NormAngle36000(GetAngle(rPnt - DragStat().GetRef1()) -
+ rCandidate.mnStartAngle) - rCandidate.mnLastAngle;
+ rCandidate.mnLastAngle = static_cast<long>(fWAngle) + rCandidate.mnLastAngle;
+ fWAngle /= 100.0;
+ fHAngle = 0.0;
+ }
+ else
+ {
+ if ((maFullBound.GetWidth() == 0) || (maFullBound.GetHeight() == 0))
+ throw o3tl::divide_by_zero();
+ fWAngle = 90.0 * static_cast<double>(rPnt.X() - maLastPos.X())
+ / static_cast<double>(maFullBound.GetWidth());
+ fHAngle = 90.0 * static_cast<double>(rPnt.Y() - maLastPos.Y())
+ / static_cast<double>(maFullBound.GetHeight());
+ }
+ long nSnap = 0;
+
+ if(!getSdrDragView().IsRotateAllowed())
+ nSnap = 90;
+
+ if(nSnap != 0)
+ {
+ fWAngle = static_cast<double>((static_cast<long>(fWAngle) + nSnap/2) / nSnap * nSnap);
+ fHAngle = static_cast<double>((static_cast<long>(fHAngle) + nSnap/2) / nSnap * nSnap);
+ }
+
+ // to radians
+ fWAngle = basegfx::deg2rad(fWAngle);
+ fHAngle = basegfx::deg2rad(fHAngle);
+
+ // Determine transformation
+ basegfx::B3DHomMatrix aRotMat;
+ if(E3dDragConstraint::Y & meConstraint)
+ {
+ if(nModifier & KEY_MOD2)
+ aRotMat.rotate(0.0, 0.0, fWAngle);
+ else
+ aRotMat.rotate(0.0, fWAngle, 0.0);
+ }
+ else if(E3dDragConstraint::Z & meConstraint)
+ {
+ if(nModifier & KEY_MOD2)
+ aRotMat.rotate(0.0, fWAngle, 0.0);
+ else
+ aRotMat.rotate(0.0, 0.0, fWAngle);
+ }
+ if(E3dDragConstraint::X & meConstraint)
+ {
+ aRotMat.rotate(fHAngle, 0.0, 0.0);
+ }
+
+ const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ // Transformation in eye coordinates, there rotate then and back
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
+ aInverseOrientation.invert();
+
+ basegfx::B3DHomMatrix aTransMat(rCandidate.maDisplayTransform);
+ aTransMat *= aViewInfo3D.getOrientation();
+ aTransMat.translate(-maGlobalCenter.getX(), -maGlobalCenter.getY(), -maGlobalCenter.getZ());
+ aTransMat *= aRotMat;
+ aTransMat.translate(maGlobalCenter.getX(), maGlobalCenter.getY(), maGlobalCenter.getZ());
+ aTransMat *= aInverseOrientation;
+ aTransMat *= rCandidate.maInvDisplayTransform;
+
+ // ...and apply
+ rCandidate.maTransform *= aTransMat;
+
+ if(mbMoveFull)
+ {
+ E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
+ rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
+ }
+ else
+ {
+ Hide();
+ rCandidate.maWireframePoly.transform(aTransMat);
+ Show();
+ }
+ }
+ }
+ maLastPos = rPnt;
+ DragStat().NextMove(rPnt);
+ }
+}
+
+PointerStyle E3dDragRotate::GetSdrDragPointer() const
+{
+ return PointerStyle::Rotate;
+}
+
+// E3dDragMove. This drag method is only required for translations inside
+// 3D scenes. If a 3D-scene itself moved, then this drag method will drag
+// not be used.
+
+
+E3dDragMove::E3dDragMove(SdrDragView &_rView,
+ const SdrMarkList& rMark,
+ SdrHdlKind eDrgHdl,
+ E3dDragConstraint eConstr,
+ bool bFull)
+: E3dDragMethod(_rView, rMark, eConstr, bFull),
+ meWhatDragHdl(eDrgHdl)
+{
+ switch(meWhatDragHdl)
+ {
+ case SdrHdlKind::Left:
+ maScaleFixPos = maFullBound.RightCenter();
+ break;
+ case SdrHdlKind::Right:
+ maScaleFixPos = maFullBound.LeftCenter();
+ break;
+ case SdrHdlKind::Upper:
+ maScaleFixPos = maFullBound.BottomCenter();
+ break;
+ case SdrHdlKind::Lower:
+ maScaleFixPos = maFullBound.TopCenter();
+ break;
+ case SdrHdlKind::UpperLeft:
+ maScaleFixPos = maFullBound.BottomRight();
+ break;
+ case SdrHdlKind::UpperRight:
+ maScaleFixPos = maFullBound.BottomLeft();
+ break;
+ case SdrHdlKind::LowerLeft:
+ maScaleFixPos = maFullBound.TopRight();
+ break;
+ case SdrHdlKind::LowerRight:
+ maScaleFixPos = maFullBound.TopLeft();
+ break;
+ default:
+ // Moving the object, SdrHdlKind::Move
+ break;
+ }
+
+ // Override when IsResizeAtCenter()
+ if(getSdrDragView().IsResizeAtCenter())
+ {
+ meWhatDragHdl = SdrHdlKind::User;
+ maScaleFixPos = maFullBound.Center();
+ }
+}
+
+// The object is moved, determine the translations
+
+void E3dDragMove::MoveSdrDrag(const Point& rPnt)
+{
+ // call parent
+ E3dDragMethod::MoveSdrDrag(rPnt);
+
+ if(DragStat().CheckMinMoved(rPnt))
+ {
+ if(SdrHdlKind::Move == meWhatDragHdl)
+ {
+ // Translation
+ // Determine the motion vector
+ const sal_uInt32 nCnt(maGrp.size());
+
+ // Get modifier
+ sal_uInt16 nModifier(0);
+
+ if(dynamic_cast<const E3dView*>(&getSdrDragView()))
+ {
+ const MouseEvent& rLastMouse = static_cast<E3dView&>(getSdrDragView()).GetMouseEvent();
+ nModifier = rLastMouse.GetModifier();
+ }
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+
+ // move coor from 2d world to 3d Eye
+ basegfx::B2DPoint aGlobalMoveHead2D(static_cast<double>(rPnt.X() - maLastPos.X()), static_cast<double>(rPnt.Y() - maLastPos.Y()));
+ basegfx::B2DPoint aGlobalMoveTail2D(0.0, 0.0);
+ basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
+
+ aInverseSceneTransform.invert();
+ aGlobalMoveHead2D = aInverseSceneTransform * aGlobalMoveHead2D;
+ aGlobalMoveTail2D = aInverseSceneTransform * aGlobalMoveTail2D;
+
+ basegfx::B3DPoint aMoveHead3D(aGlobalMoveHead2D.getX(), aGlobalMoveHead2D.getY(), 0.5);
+ basegfx::B3DPoint aMoveTail3D(aGlobalMoveTail2D.getX(), aGlobalMoveTail2D.getY(), 0.5);
+ basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
+ aInverseViewToEye.invert();
+
+ aMoveHead3D = aInverseViewToEye * aMoveHead3D;
+ aMoveTail3D = aInverseViewToEye * aMoveTail3D;
+
+ // eventually switch movement from XY to XZ plane
+ if(nModifier & KEY_MOD2)
+ {
+ double fZwi = aMoveHead3D.getY();
+ aMoveHead3D.setY(aMoveHead3D.getZ());
+ aMoveHead3D.setZ(fZwi);
+
+ fZwi = aMoveTail3D.getY();
+ aMoveTail3D.setY(aMoveTail3D.getZ());
+ aMoveTail3D.setZ(fZwi);
+ }
+
+ // Motion vector from eye coordinates to parent coordinates
+ basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
+ aInverseOrientation.invert();
+ basegfx::B3DHomMatrix aCompleteTrans(rCandidate.maInvDisplayTransform * aInverseOrientation);
+
+ aMoveHead3D = aCompleteTrans * aMoveHead3D;
+ aMoveTail3D = aCompleteTrans* aMoveTail3D;
+
+ // build transformation
+ basegfx::B3DHomMatrix aTransMat;
+ basegfx::B3DPoint aTranslate(aMoveHead3D - aMoveTail3D);
+ aTransMat.translate(aTranslate.getX(), aTranslate.getY(), aTranslate.getZ());
+
+ // ...and apply
+ rCandidate.maTransform *= aTransMat;
+
+ if(mbMoveFull)
+ {
+ E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
+ rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
+ }
+ else
+ {
+ Hide();
+ rCandidate.maWireframePoly.transform(aTransMat);
+ Show();
+ }
+ }
+ }
+ }
+ else
+ {
+ // Scaling
+ // Determine scaling vector
+ Point aStartPos = DragStat().GetStart();
+ const sal_uInt32 nCnt(maGrp.size());
+
+ for(sal_uInt32 nOb(0); nOb < nCnt; nOb++)
+ {
+ E3dDragMethodUnit& rCandidate = maGrp[nOb];
+ const basegfx::B3DPoint aObjectCenter(rCandidate.mr3DObj.GetBoundVolume().getCenter());
+ const E3dScene* pScene(rCandidate.mr3DObj.getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ // transform from 2D world view to 3D eye
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+
+ basegfx::B2DPoint aGlobalScaleStart2D(static_cast<double>(aStartPos.X()), static_cast<double>(aStartPos.Y()));
+ basegfx::B2DPoint aGlobalScaleNext2D(static_cast<double>(rPnt.X()), static_cast<double>(rPnt.Y()));
+ basegfx::B2DPoint aGlobalScaleFixPos2D(static_cast<double>(maScaleFixPos.X()), static_cast<double>(maScaleFixPos.Y()));
+ basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
+
+ aInverseSceneTransform.invert();
+ aGlobalScaleStart2D = aInverseSceneTransform * aGlobalScaleStart2D;
+ aGlobalScaleNext2D = aInverseSceneTransform * aGlobalScaleNext2D;
+ aGlobalScaleFixPos2D = aInverseSceneTransform * aGlobalScaleFixPos2D;
+
+ basegfx::B3DPoint aGlobalScaleStart3D(aGlobalScaleStart2D.getX(), aGlobalScaleStart2D.getY(), aObjectCenter.getZ());
+ basegfx::B3DPoint aGlobalScaleNext3D(aGlobalScaleNext2D.getX(), aGlobalScaleNext2D.getY(), aObjectCenter.getZ());
+ basegfx::B3DPoint aGlobalScaleFixPos3D(aGlobalScaleFixPos2D.getX(), aGlobalScaleFixPos2D.getY(), aObjectCenter.getZ());
+ basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
+
+ aInverseViewToEye.invert();
+ basegfx::B3DPoint aScStart(aInverseViewToEye * aGlobalScaleStart3D);
+ basegfx::B3DPoint aScNext(aInverseViewToEye * aGlobalScaleNext3D);
+ basegfx::B3DPoint aScFixPos(aInverseViewToEye * aGlobalScaleFixPos3D);
+
+ // constraints?
+ switch(meWhatDragHdl)
+ {
+ case SdrHdlKind::Left:
+ case SdrHdlKind::Right:
+ // to constrain on X -> Y equal
+ aScNext.setY(aScFixPos.getY());
+ break;
+ case SdrHdlKind::Upper:
+ case SdrHdlKind::Lower:
+ // constrain to Y -> X equal
+ aScNext.setX(aScFixPos.getX());
+ break;
+ default:
+ break;
+ }
+
+ // get scale vector in eye coordinates
+ basegfx::B3DPoint aScaleVec(aScStart - aScFixPos);
+ aScaleVec.setZ(1.0);
+
+ if(aScaleVec.getX() != 0.0)
+ {
+ aScaleVec.setX((aScNext.getX() - aScFixPos.getX()) / aScaleVec.getX());
+ }
+ else
+ {
+ aScaleVec.setX(1.0);
+ }
+
+ if(aScaleVec.getY() != 0.0)
+ {
+ aScaleVec.setY((aScNext.getY() - aScFixPos.getY()) / aScaleVec.getY());
+ }
+ else
+ {
+ aScaleVec.setY(1.0);
+ }
+
+ // SHIFT-key used?
+ if(getSdrDragView().IsOrtho())
+ {
+ if(fabs(aScaleVec.getX()) > fabs(aScaleVec.getY()))
+ {
+ // X is biggest
+ aScaleVec.setY(aScaleVec.getX());
+ }
+ else
+ {
+ // Y is biggest
+ aScaleVec.setX(aScaleVec.getY());
+ }
+ }
+
+ // build transformation
+ basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
+ aInverseOrientation.invert();
+
+ basegfx::B3DHomMatrix aNewTrans = rCandidate.maInitTransform;
+ aNewTrans *= rCandidate.maDisplayTransform;
+ aNewTrans *= aViewInfo3D.getOrientation();
+ aNewTrans.translate(-aScFixPos.getX(), -aScFixPos.getY(), -aScFixPos.getZ());
+ aNewTrans.scale(aScaleVec.getX(), aScaleVec.getY(), aScaleVec.getZ());
+ aNewTrans.translate(aScFixPos.getX(), aScFixPos.getY(), aScFixPos.getZ());
+ aNewTrans *= aInverseOrientation;
+ aNewTrans *= rCandidate.maInvDisplayTransform;
+
+ // ...and apply
+ rCandidate.maTransform = aNewTrans;
+
+ if(mbMoveFull)
+ {
+ E3DModifySceneSnapRectUpdater aUpdater(&rCandidate.mr3DObj);
+ rCandidate.mr3DObj.SetTransform(rCandidate.maTransform);
+ }
+ else
+ {
+ Hide();
+ rCandidate.maWireframePoly.clear();
+ rCandidate.maWireframePoly = rCandidate.mr3DObj.CreateWireframe();
+ rCandidate.maWireframePoly.transform(rCandidate.maTransform);
+ Show();
+ }
+ }
+ }
+ }
+ maLastPos = rPnt;
+ DragStat().NextMove(rPnt);
+ }
+}
+
+PointerStyle E3dDragMove::GetSdrDragPointer() const
+{
+ return PointerStyle::Move;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/e3dsceneupdater.cxx b/svx/source/engine3d/e3dsceneupdater.cxx
new file mode 100644
index 000000000..07df1af05
--- /dev/null
+++ b/svx/source/engine3d/e3dsceneupdater.cxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/e3dsceneupdater.hxx>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+
+
+E3DModifySceneSnapRectUpdater::E3DModifySceneSnapRectUpdater(const SdrObject* pObject)
+: mpScene(nullptr)
+{
+ // Secure old 3D transformation stack before modification
+ if(const E3dObject* pE3dObject = dynamic_cast< const E3dObject* >(pObject))
+ {
+ mpScene = pE3dObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != mpScene && mpScene->getRootE3dSceneFromE3dObject() == mpScene)
+ {
+ // if there is a scene and it's the outmost scene, get current 3D range
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(mpScene->GetViewContact());
+ const basegfx::B3DRange aAllContentRange(rVCScene.getAllContentRange3D());
+
+ if(aAllContentRange.isEmpty())
+ {
+ // no content, nothing to do
+ mpScene = nullptr;
+ }
+ else
+ {
+ // secure current 3D transformation stack
+ mpViewInformation3D.reset(
+ new drawinglayer::geometry::ViewInformation3D(
+ rVCScene.getViewInformation3D(aAllContentRange)));
+ }
+ }
+ }
+}
+
+E3DModifySceneSnapRectUpdater::~E3DModifySceneSnapRectUpdater()
+{
+ if(mpScene && mpViewInformation3D)
+ {
+ // after changing parts of the scene, use the secured last 3d transformation stack and the new content
+ // range to calculate a new, eventually expanded or shrunk, 2D geometry for the scene and apply it.
+ // Get new content range
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(mpScene->GetViewContact());
+ basegfx::B3DRange aAllContentRange(rVCScene.getAllContentRange3D());
+
+ // only change when there is still content; else let scene stay at old SnapRect
+ if(!aAllContentRange.isEmpty())
+ {
+ // check if object transform of scene has changed
+ if(mpViewInformation3D->getObjectTransformation() != mpScene->GetTransform())
+ {
+ // If Yes, it needs to be updated since it's - for historical reasons -
+ // part of the basic 3d transformation stack of the scene
+ drawinglayer::geometry::ViewInformation3D* pNew = new drawinglayer::geometry::ViewInformation3D(
+ mpScene->GetTransform(), // replace object transformation with new local transform
+ mpViewInformation3D->getOrientation(),
+ mpViewInformation3D->getProjection(),
+ mpViewInformation3D->getDeviceToView(),
+ mpViewInformation3D->getViewTime(),
+ mpViewInformation3D->getExtendedInformationSequence());
+ mpViewInformation3D.reset(pNew);
+ }
+
+ // transform content range to scene-relative coordinates using old 3d transformation stack
+ aAllContentRange.transform(mpViewInformation3D->getObjectToView());
+
+ // build 2d relative content range
+ basegfx::B2DRange aSnapRange(
+ aAllContentRange.getMinX(), aAllContentRange.getMinY(),
+ aAllContentRange.getMaxX(), aAllContentRange.getMaxY());
+
+ // transform to 2D world coordinates using scene's 2D transformation
+ aSnapRange.transform(rVCScene.getObjectTransformation());
+
+ // snap to (old) integer
+ const tools::Rectangle aNewSnapRect(
+ sal_Int32(floor(aSnapRange.getMinX())), sal_Int32(floor(aSnapRange.getMinY())),
+ sal_Int32(ceil(aSnapRange.getMaxX())), sal_Int32(ceil(aSnapRange.getMaxY())));
+
+ // set as new SnapRect and invalidate bound volume
+ if(mpScene->GetSnapRect() != aNewSnapRect)
+ {
+ mpScene->SetSnapRect(aNewSnapRect);
+ mpScene->InvalidateBoundVolume();
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/e3dundo.cxx b/svx/source/engine3d/e3dundo.cxx
new file mode 100644
index 000000000..b1d99ddfd
--- /dev/null
+++ b/svx/source/engine3d/e3dundo.cxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/e3dundo.hxx>
+#include <svx/e3dsceneupdater.hxx>
+
+
+E3dUndoAction::~E3dUndoAction ()
+{
+}
+
+// Repeat does not exist
+
+bool E3dUndoAction::CanRepeat(SfxRepeatTarget&) const
+{
+ return false;
+}
+
+
+// Undo destructor for 3D-Rotation
+E3dRotateUndoAction::~E3dRotateUndoAction()
+{
+}
+
+// Undo for 3D-Rotation on the Rotation matrix
+void E3dRotateUndoAction::Undo()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(&mrMy3DObj);
+ mrMy3DObj.SetTransform(maMyOldRotation);
+}
+
+// Redo for 3D-Rotation on the Rotation matrix
+void E3dRotateUndoAction::Redo()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(&mrMy3DObj);
+ mrMy3DObj.SetTransform(maMyNewRotation);
+}
+
+E3dAttributesUndoAction::E3dAttributesUndoAction(
+ E3dObject& rInObject,
+ const SfxItemSet& rNewSet,
+ const SfxItemSet& rOldSet)
+: SdrUndoAction(rInObject.getSdrModelFromSdrObject())
+ ,mrObject(rInObject)
+ ,maNewSet(rNewSet)
+ ,maOldSet(rOldSet)
+{
+}
+
+E3dAttributesUndoAction::~E3dAttributesUndoAction()
+{
+}
+
+// Undo() implemented through Set3DAttributes() to only maintain the attributes
+// in one place
+
+void E3dAttributesUndoAction::Undo()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(&mrObject);
+ mrObject.SetMergedItemSetAndBroadcast(maOldSet);
+}
+
+void E3dAttributesUndoAction::Redo()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(&mrObject);
+ mrObject.SetMergedItemSetAndBroadcast(maNewSet);
+}
+
+// Multiple Undo is not possible
+bool E3dAttributesUndoAction::CanRepeat(SfxRepeatTarget& /*rView*/) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/extrud3d.cxx b/svx/source/engine3d/extrud3d.cxx
new file mode 100644
index 000000000..d4aa1f024
--- /dev/null
+++ b/svx/source/engine3d/extrud3d.cxx
@@ -0,0 +1,223 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/strings.hrc>
+#include <svx/deflt3d.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/globl3d.hxx>
+#include <extrud3d.hxx>
+
+#include <svx/svdopath.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svx3ditems.hxx>
+#include <svx/xlineit0.hxx>
+#include <sdr/properties/e3dextrudeproperties.hxx>
+#include <sdr/contact/viewcontactofe3dextrude.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b3dpolypolygontools.hxx>
+#include <rtl/ustrbuf.hxx>
+
+
+// DrawContact section
+std::unique_ptr<sdr::contact::ViewContact> E3dExtrudeObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dExtrude>(*this);
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dExtrudeObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dExtrudeProperties>(*this);
+}
+
+// Constructor creates a two cover surface tools::PolyPolygon and (point-count 1) side
+// surfaces rectangles from the passed PolyPolygon
+E3dExtrudeObj::E3dExtrudeObj(
+ SdrModel& rSdrModel,
+ const E3dDefaultAttributes& rDefault,
+ const basegfx::B2DPolyPolygon& rPP,
+ double fDepth)
+: E3dCompoundObject(rSdrModel),
+ maExtrudePolygon(rPP)
+{
+ // since the old class PolyPolygon3D did mirror the given PolyPolygons in Y, do the same here
+ basegfx::B2DHomMatrix aMirrorY;
+ aMirrorY.scale(1.0, -1.0);
+ maExtrudePolygon.transform(aMirrorY);
+
+ // Set Defaults
+ SetDefaultAttributes(rDefault);
+
+ // set extrude depth
+ GetProperties().SetObjectItemDirect(makeSvx3DDepthItem(static_cast<sal_uInt32>(fDepth + 0.5)));
+}
+
+E3dExtrudeObj::E3dExtrudeObj(SdrModel& rSdrModel)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set Defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+}
+
+E3dExtrudeObj::~E3dExtrudeObj()
+{
+}
+
+void E3dExtrudeObj::SetDefaultAttributes(const E3dDefaultAttributes& rDefault)
+{
+ GetProperties().SetObjectItemDirect(Svx3DSmoothNormalsItem(rDefault.GetDefaultExtrudeSmoothed()));
+ GetProperties().SetObjectItemDirect(Svx3DSmoothLidsItem(rDefault.GetDefaultExtrudeSmoothFrontBack()));
+ GetProperties().SetObjectItemDirect(Svx3DCharacterModeItem(rDefault.GetDefaultExtrudeCharacterMode()));
+ GetProperties().SetObjectItemDirect(Svx3DCloseFrontItem(rDefault.GetDefaultExtrudeCloseFront()));
+ GetProperties().SetObjectItemDirect(Svx3DCloseBackItem(rDefault.GetDefaultExtrudeCloseBack()));
+
+ // For extrudes use StdTexture in X and Y by default
+ GetProperties().SetObjectItemDirect(Svx3DTextureProjectionXItem(1));
+ GetProperties().SetObjectItemDirect(Svx3DTextureProjectionYItem(1));
+}
+
+sal_uInt16 E3dExtrudeObj::GetObjIdentifier() const
+{
+ return E3D_EXTRUDEOBJ_ID;
+}
+
+E3dExtrudeObj* E3dExtrudeObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return CloneHelper< E3dExtrudeObj >(rTargetModel);
+}
+
+E3dExtrudeObj& E3dExtrudeObj::operator=(const E3dExtrudeObj& rObj)
+{
+ if( this == &rObj )
+ return *this;
+ E3dCompoundObject::operator=(rObj);
+
+ maExtrudePolygon = rObj.maExtrudePolygon;
+
+ return *this;
+}
+
+// Set local parameters with geometry re-creating
+
+void E3dExtrudeObj::SetExtrudePolygon(const basegfx::B2DPolyPolygon &rNew)
+{
+ if(maExtrudePolygon != rNew)
+ {
+ maExtrudePolygon = rNew;
+ ActionChanged();
+ }
+}
+
+// Get the name of the object (singular)
+
+OUString E3dExtrudeObj::TakeObjNameSingul() const
+{
+ OUStringBuffer sName(SvxResId(STR_ObjNameSingulExtrude3d));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName.append(' ');
+ sName.append('\'');
+ sName.append(aName);
+ sName.append('\'');
+ }
+ return sName.makeStringAndClear();
+}
+
+// Get the name of the object (plural)
+
+OUString E3dExtrudeObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralExtrude3d);
+}
+
+bool E3dExtrudeObj::IsBreakObjPossible()
+{
+ return true;
+}
+
+std::unique_ptr<SdrAttrObj,SdrObjectFreeOp> E3dExtrudeObj::GetBreakObj()
+{
+ basegfx::B3DPolyPolygon aFrontSide;
+ basegfx::B3DPolyPolygon aBackSide;
+
+ if(maExtrudePolygon.count())
+ {
+ basegfx::B2DPolyPolygon aTemp(maExtrudePolygon);
+ aTemp.removeDoublePoints();
+ aTemp = basegfx::utils::correctOrientations(aTemp);
+ const basegfx::B2VectorOrientation aOrient = basegfx::utils::getOrientation(aTemp.getB2DPolygon(0));
+
+ if(basegfx::B2VectorOrientation::Positive == aOrient)
+ {
+ aTemp.flip();
+ }
+
+ aFrontSide = basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon(aTemp);
+ }
+
+ if(aFrontSide.count())
+ {
+ aBackSide = aFrontSide;
+
+ if(GetExtrudeDepth())
+ {
+ basegfx::B3DHomMatrix aTransform;
+
+ if(100 != GetPercentBackScale())
+ {
+ // scale polygon from center
+ const double fScaleFactor(GetPercentBackScale() / 100.0);
+ const basegfx::B3DRange aPolyPolyRange(basegfx::utils::getRange(aBackSide));
+ const basegfx::B3DPoint aCenter(aPolyPolyRange.getCenter());
+
+ aTransform.translate(-aCenter.getX(), -aCenter.getY(), -aCenter.getZ());
+ aTransform.scale(fScaleFactor, fScaleFactor, fScaleFactor);
+ aTransform.translate(aCenter.getX(), aCenter.getY(), aCenter.getZ());
+ }
+
+ // translate by extrude depth
+ aTransform.translate(0.0, 0.0, static_cast<double>(GetExtrudeDepth()));
+
+ aBackSide.transform(aTransform);
+ }
+ }
+
+ if(aBackSide.count())
+ {
+ // create PathObj
+ basegfx::B2DPolyPolygon aPoly = TransformToScreenCoor(aBackSide);
+ std::unique_ptr<SdrPathObj,SdrObjectFreeOp> pPathObj(new SdrPathObj(getSdrModelFromSdrObject(), OBJ_PLIN, aPoly));
+
+ SfxItemSet aSet(GetObjectItemSet());
+ aSet.Put(XLineStyleItem(css::drawing::LineStyle_SOLID));
+ pPathObj->SetMergedItemSet(aSet);
+
+ return std::unique_ptr<SdrAttrObj,SdrObjectFreeOp>(pPathObj.release());
+ }
+
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/float3d.cxx b/svx/source/engine3d/float3d.cxx
new file mode 100644
index 000000000..8636cfc2b
--- /dev/null
+++ b/svx/source/engine3d/float3d.cxx
@@ -0,0 +1,2949 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <sfx2/dispatch.hxx>
+#include <sfx2/module.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/itempool.hxx>
+#include <svtools/colrdlg.hxx>
+#include <svx/colorbox.hxx>
+#include <svx/f3dchild.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/fmmodel.hxx>
+#include <svx/dlgutil.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/svx3ditems.hxx>
+
+#include <svx/dialmgr.hxx>
+#include <svx/viewpt3d.hxx>
+
+#include <svx/svxids.hrc>
+#include <svx/strings.hrc>
+
+#include <editeng/colritem.hxx>
+#include <osl/diagnose.h>
+#include <svx/e3ditem.hxx>
+#include <svl/whiter.hxx>
+#include <svtools/unitconv.hxx>
+
+#include <svx/float3d.hxx>
+#include <bitmaps.hlst>
+
+using namespace com::sun::star;
+
+SFX_IMPL_DOCKINGWINDOW_WITHID( Svx3DChildWindow, SID_3D_WIN )
+
+struct Svx3DWinImpl
+{
+ SfxItemPool* pPool;
+};
+
+namespace {
+ /** Get the dispatcher from the current view frame, or, if that is not
+ available, from the given bindings.
+ @param pBindings
+ May be NULL.
+ @returns NULL when both the current view frame is NULL and the given
+ bindings are NULL.
+ */
+ SfxDispatcher* LocalGetDispatcher (const SfxBindings* pBindings)
+ {
+ SfxDispatcher* pDispatcher = nullptr;
+
+ if (SfxViewFrame::Current() != nullptr)
+ pDispatcher = SfxViewFrame::Current()->GetDispatcher();
+ else if (pBindings != nullptr)
+ pDispatcher = pBindings->GetDispatcher();
+
+ return pDispatcher;
+ }
+}
+
+Svx3DWin::Svx3DWin(SfxBindings* pInBindings, SfxChildWindow *pCW, vcl::Window* pParent)
+ : SfxDockingWindow(pInBindings, pCW, pParent,
+ "Docking3DEffects", "svx/ui/docking3deffects.ui")
+
+ , m_xBtnGeo(m_xBuilder->weld_toggle_button("geometry"))
+ , m_xBtnRepresentation(m_xBuilder->weld_toggle_button("representation"))
+ , m_xBtnLight(m_xBuilder->weld_toggle_button("light"))
+ , m_xBtnTexture(m_xBuilder->weld_toggle_button("texture"))
+ , m_xBtnMaterial(m_xBuilder->weld_toggle_button("material"))
+ , m_xBtnUpdate(m_xBuilder->weld_toggle_button("update"))
+ , m_xBtnAssign(m_xBuilder->weld_button("assign"))
+
+ , m_xFLGeometrie(m_xBuilder->weld_container("geoframe"))
+ , m_xFtPercentDiagonal(m_xBuilder->weld_label("diagonalft"))
+ , m_xMtrPercentDiagonal(m_xBuilder->weld_metric_spin_button("diagonal", FieldUnit::PERCENT))
+ , m_xFtBackscale(m_xBuilder->weld_label("scaleddepthft"))
+ , m_xMtrBackscale(m_xBuilder->weld_metric_spin_button("scaleddepth", FieldUnit::PERCENT))
+ , m_xFtEndAngle(m_xBuilder->weld_label("angleft"))
+ , m_xMtrEndAngle(m_xBuilder->weld_metric_spin_button("angle", FieldUnit::DEGREE))
+ , m_xFtDepth(m_xBuilder->weld_label("depthft"))
+ , m_xMtrDepth(m_xBuilder->weld_metric_spin_button("depth", FieldUnit::CM))
+
+ , m_xFLSegments(m_xBuilder->weld_container("segmentsframe"))
+ , m_xNumHorizontal(m_xBuilder->weld_spin_button("hori"))
+ , m_xNumVertical(m_xBuilder->weld_spin_button("veri"))
+
+ , m_xFLNormals(m_xBuilder->weld_container("normals"))
+ , m_xBtnNormalsObj(m_xBuilder->weld_toggle_button("objspecific"))
+ , m_xBtnNormalsFlat(m_xBuilder->weld_toggle_button("flat"))
+ , m_xBtnNormalsSphere(m_xBuilder->weld_toggle_button("spherical"))
+ , m_xBtnNormalsInvert(m_xBuilder->weld_toggle_button("invertnormals"))
+ , m_xBtnTwoSidedLighting(m_xBuilder->weld_toggle_button("doublesidedillum"))
+ , m_xBtnDoubleSided(m_xBuilder->weld_toggle_button("doublesided"))
+
+ , m_xFLRepresentation(m_xBuilder->weld_container("shadingframe"))
+ , m_xLbShademode(m_xBuilder->weld_combo_box("mode"))
+
+ , m_xFLShadow(m_xBuilder->weld_container("shadowframe"))
+ , m_xBtnShadow3d(m_xBuilder->weld_toggle_button("shadow"))
+ , m_xFtSlant(m_xBuilder->weld_label("slantft"))
+ , m_xMtrSlant(m_xBuilder->weld_metric_spin_button("slant", FieldUnit::DEGREE))
+
+ , m_xFLCamera(m_xBuilder->weld_container("cameraframe"))
+ , m_xMtrDistance(m_xBuilder->weld_metric_spin_button("distance", FieldUnit::CM))
+ , m_xMtrFocalLength(m_xBuilder->weld_metric_spin_button("focal", FieldUnit::CM))
+
+ , m_xFLLight(m_xBuilder->weld_container("illumframe"))
+ , m_xBtnLight1(new LightButton(m_xBuilder->weld_toggle_button("light1")))
+ , m_xBtnLight2(new LightButton(m_xBuilder->weld_toggle_button("light2")))
+ , m_xBtnLight3(new LightButton(m_xBuilder->weld_toggle_button("light3")))
+ , m_xBtnLight4(new LightButton(m_xBuilder->weld_toggle_button("light4")))
+ , m_xBtnLight5(new LightButton(m_xBuilder->weld_toggle_button("light5")))
+ , m_xBtnLight6(new LightButton(m_xBuilder->weld_toggle_button("light6")))
+ , m_xBtnLight7(new LightButton(m_xBuilder->weld_toggle_button("light7")))
+ , m_xBtnLight8(new LightButton(m_xBuilder->weld_toggle_button("light8")))
+ , m_xLbLight1(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor1"), GetFrameWeld()))
+ , m_xLbLight2(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor2"), GetFrameWeld()))
+ , m_xLbLight3(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor3"), GetFrameWeld()))
+ , m_xLbLight4(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor4"), GetFrameWeld()))
+ , m_xLbLight5(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor5"), GetFrameWeld()))
+ , m_xLbLight6(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor6"), GetFrameWeld()))
+ , m_xLbLight7(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor7"), GetFrameWeld()))
+ , m_xLbLight8(new ColorListBox(m_xBuilder->weld_menu_button("lightcolor8"), GetFrameWeld()))
+ , m_xBtnLightColor(m_xBuilder->weld_button("colorbutton1"))
+ , m_xLbAmbientlight(new ColorListBox(m_xBuilder->weld_menu_button("ambientcolor"), GetFrameWeld()))
+ , m_xBtnAmbientColor(m_xBuilder->weld_button("colorbutton2"))
+
+ , m_xFLTexture(m_xBuilder->weld_container("textureframe"))
+ , m_xBtnTexLuminance(m_xBuilder->weld_toggle_button("textype"))
+ , m_xBtnTexColor(m_xBuilder->weld_toggle_button("texcolor"))
+ , m_xBtnTexReplace(m_xBuilder->weld_toggle_button("texreplace"))
+ , m_xBtnTexModulate(m_xBuilder->weld_toggle_button("texmodulate"))
+ , m_xBtnTexBlend(m_xBuilder->weld_toggle_button("texblend"))
+ , m_xBtnTexObjectX(m_xBuilder->weld_toggle_button("texobjx"))
+ , m_xBtnTexParallelX(m_xBuilder->weld_toggle_button("texparallelx"))
+ , m_xBtnTexCircleX(m_xBuilder->weld_toggle_button("texcirclex"))
+ , m_xBtnTexObjectY(m_xBuilder->weld_toggle_button("texobjy"))
+ , m_xBtnTexParallelY(m_xBuilder->weld_toggle_button("texparallely"))
+ , m_xBtnTexCircleY(m_xBuilder->weld_toggle_button("texcircley"))
+ , m_xBtnTexFilter(m_xBuilder->weld_toggle_button("texfilter"))
+
+ , m_xFLMaterial(m_xBuilder->weld_container("materialframe"))
+ , m_xLbMatFavorites(m_xBuilder->weld_combo_box("favorites"))
+ , m_xLbMatColor(new ColorListBox(m_xBuilder->weld_menu_button("objcolor"), GetFrameWeld()))
+ , m_xBtnMatColor(m_xBuilder->weld_button("colorbutton3"))
+ , m_xLbMatEmission(new ColorListBox(m_xBuilder->weld_menu_button("illumcolor"), GetFrameWeld()))
+ , m_xBtnEmissionColor(m_xBuilder->weld_button("colorbutton4"))
+
+ , m_xFLMatSpecular(m_xBuilder->weld_container("specframe"))
+ , m_xLbMatSpecular(new ColorListBox(m_xBuilder->weld_menu_button("speccolor"), GetFrameWeld()))
+ , m_xBtnSpecularColor(m_xBuilder->weld_button("colorbutton5"))
+ , m_xMtrMatSpecularIntensity(m_xBuilder->weld_metric_spin_button("intensity", FieldUnit::PERCENT))
+
+ , m_xCtlPreview(new Svx3DPreviewControl)
+ , m_xCtlPreviewWin(new weld::CustomWeld(*m_xBuilder, "preview", *m_xCtlPreview))
+
+ , m_xLightPreviewGrid(m_xBuilder->weld_container("lightpreviewgrid"))
+ , m_xHoriScale(m_xBuilder->weld_scale("horiscale"))
+ , m_xVertScale(m_xBuilder->weld_scale("vertscale"))
+ , m_xBtn_Corner(m_xBuilder->weld_button("corner"))
+ , m_xLightPreview(new Svx3DLightControl)
+ , m_xCtlLightPreviewWin(new weld::CustomWeld(*m_xBuilder, "lightpreview", *m_xLightPreview))
+ , m_xCtlLightPreview(new SvxLightCtl3D(*m_xLightPreview, *m_xHoriScale, *m_xVertScale, *m_xBtn_Corner)) // TODO might be other body widget as arg 1
+
+ , m_xBtnConvertTo3D(m_xBuilder->weld_button("to3d"))
+ , m_xBtnLatheObject(m_xBuilder->weld_button("tolathe"))
+ , m_xBtnPerspective(m_xBuilder->weld_toggle_button("perspective"))
+
+ , bUpdate(false)
+ , eViewType(ViewType3D::Geo)
+ , pBindings(pInBindings)
+ , mpImpl(new Svx3DWinImpl)
+ , ePoolUnit(MapUnit::MapMM)
+{
+ SetText(SvxResId(RID_SVXDLG_FLOAT3D_STR_TITLE));
+
+ weld::DrawingArea* pDrawingArea = m_xCtlPreview->GetDrawingArea();
+ Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(83, 76), MapMode(MapUnit::MapAppFont)));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ m_xCtlPreview->SetOutputSizePixel(aSize);
+
+ m_xLightPreviewGrid->set_size_request(aSize.Width(), aSize.Height());
+ pDrawingArea = m_xLightPreview->GetDrawingArea();
+ pDrawingArea->set_size_request(42, 42); // small to fit to m_xLightPreviewGrid
+
+ mpImpl->pPool = nullptr;
+
+ // Set Metric
+ eFUnit = pInBindings->GetDispatcher()->GetModule()->GetFieldUnit();
+
+ m_xMtrDepth->set_unit( eFUnit );
+ m_xMtrDistance->set_unit( eFUnit );
+ m_xMtrFocalLength->set_unit( eFUnit );
+
+ pControllerItem.reset( new Svx3DCtrlItem(SID_3D_STATE, pBindings) );
+ pConvertTo3DItem.reset( new SvxConvertTo3DItem(SID_CONVERT_TO_3D, pBindings) );
+ pConvertTo3DLatheItem.reset( new SvxConvertTo3DItem(SID_CONVERT_TO_3D_LATHE_FAST, pBindings) );
+
+ m_xBtnAssign->connect_clicked( LINK( this, Svx3DWin, ClickAssignHdl ) );
+ m_xBtnUpdate->connect_toggled( LINK( this, Svx3DWin, ClickUpdateHdl ) );
+
+ Link<weld::Button&,void> aLink( LINK( this, Svx3DWin, ClickViewTypeHdl ) );
+ m_xBtnGeo->connect_clicked( aLink );
+ m_xBtnRepresentation->connect_clicked( aLink );
+ m_xBtnLight->connect_clicked( aLink );
+ m_xBtnTexture->connect_clicked( aLink );
+ m_xBtnMaterial->connect_clicked( aLink );
+
+ aLink = LINK( this, Svx3DWin, ClickHdl );
+ m_xBtnPerspective->connect_clicked( aLink );
+ m_xBtnConvertTo3D->connect_clicked( aLink );
+ m_xBtnLatheObject->connect_clicked( aLink );
+
+ // Geometry
+ m_xBtnNormalsObj->connect_clicked( aLink );
+ m_xBtnNormalsFlat->connect_clicked( aLink );
+ m_xBtnNormalsSphere->connect_clicked( aLink );
+ m_xBtnTwoSidedLighting->connect_clicked( aLink );
+ m_xBtnNormalsInvert->connect_clicked( aLink );
+ m_xBtnDoubleSided->connect_clicked( aLink );
+
+ // Representation
+ m_xBtnShadow3d->connect_clicked( aLink );
+
+ // Lighting
+ m_xBtnLight1->connect_clicked( aLink );
+ m_xBtnLight2->connect_clicked( aLink );
+ m_xBtnLight3->connect_clicked( aLink );
+ m_xBtnLight4->connect_clicked( aLink );
+ m_xBtnLight5->connect_clicked( aLink );
+ m_xBtnLight6->connect_clicked( aLink );
+ m_xBtnLight7->connect_clicked( aLink );
+ m_xBtnLight8->connect_clicked( aLink );
+
+ // Textures
+ m_xBtnTexLuminance->connect_clicked( aLink );
+ m_xBtnTexColor->connect_clicked( aLink );
+ m_xBtnTexReplace->connect_clicked( aLink );
+ m_xBtnTexModulate->connect_clicked( aLink );
+ m_xBtnTexParallelX->connect_clicked( aLink );
+ m_xBtnTexCircleX->connect_clicked( aLink );
+ m_xBtnTexObjectX->connect_clicked( aLink );
+ m_xBtnTexParallelY->connect_clicked( aLink );
+ m_xBtnTexCircleY->connect_clicked( aLink );
+ m_xBtnTexObjectY->connect_clicked( aLink );
+ m_xBtnTexFilter->connect_clicked( aLink );
+
+ // Material
+ aLink = LINK( this, Svx3DWin, ClickColorHdl );
+ m_xBtnLightColor->connect_clicked( aLink );
+ m_xBtnAmbientColor->connect_clicked( aLink );
+ m_xBtnMatColor->connect_clicked( aLink );
+ m_xBtnEmissionColor->connect_clicked( aLink );
+ m_xBtnSpecularColor->connect_clicked( aLink );
+
+
+ Link<weld::ComboBox&,void> aLink2 = LINK( this, Svx3DWin, SelectHdl );
+ Link<ColorListBox&,void> aLink4 = LINK( this, Svx3DWin, SelectColorHdl );
+ m_xLbMatFavorites->connect_changed( aLink2 );
+ m_xLbMatColor->SetSelectHdl( aLink4 );
+ m_xLbMatEmission->SetSelectHdl( aLink4 );
+ m_xLbMatSpecular->SetSelectHdl( aLink4 );
+ m_xLbLight1->SetSelectHdl( aLink4 );
+ m_xLbLight2->SetSelectHdl( aLink4 );
+ m_xLbLight3->SetSelectHdl( aLink4 );
+ m_xLbLight4->SetSelectHdl( aLink4 );
+ m_xLbLight5->SetSelectHdl( aLink4 );
+ m_xLbLight6->SetSelectHdl( aLink4 );
+ m_xLbLight7->SetSelectHdl( aLink4 );
+ m_xLbLight8->SetSelectHdl( aLink4 );
+ m_xLbAmbientlight->SetSelectHdl( aLink4 );
+ m_xLbShademode->connect_changed( aLink2 );
+
+ Link<weld::MetricSpinButton&,void> aLink3 = LINK( this, Svx3DWin, ModifyMetricHdl );
+ Link<weld::SpinButton&,void> aLink5 = LINK( this, Svx3DWin, ModifySpinHdl );
+ m_xMtrMatSpecularIntensity->connect_value_changed( aLink3 );
+ m_xNumHorizontal->connect_value_changed( aLink5 );
+ m_xNumVertical->connect_value_changed( aLink5 );
+ m_xMtrSlant->connect_value_changed( aLink3 );
+
+ // Preview callback
+ m_xCtlLightPreview->SetUserSelectionChangeCallback(LINK( this, Svx3DWin, ChangeSelectionCallbackHdl ));
+
+ aSize = GetOutputSizePixel();
+ SetMinOutputSizePixel( aSize );
+
+ Construct();
+
+ // Initiation of the initialization of the ColorLBs
+ SfxDispatcher* pDispatcher = LocalGetDispatcher(pBindings);
+ if (pDispatcher != nullptr)
+ {
+ SfxBoolItem aItem( SID_3D_INIT, true );
+ pDispatcher->ExecuteList(SID_3D_INIT,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+ }
+
+ Reset();
+
+ //lock down the size of the initial largest default mode as the permanent size
+ aSize = get_preferred_size();
+ set_width_request(aSize.Width());
+ set_height_request(aSize.Height());
+}
+
+Svx3DWin::~Svx3DWin()
+{
+ disposeOnce();
+}
+
+void Svx3DWin::dispose()
+{
+ pModel.reset();
+
+ pControllerItem.reset();
+ pConvertTo3DItem.reset();
+ pConvertTo3DLatheItem.reset();
+
+ mpImpl.reset();
+
+ m_xBtnGeo.reset();
+ m_xBtnRepresentation.reset();
+ m_xBtnLight.reset();
+ m_xBtnTexture.reset();
+ m_xBtnMaterial.reset();
+ m_xBtnUpdate.reset();
+ m_xBtnAssign.reset();
+ m_xFLGeometrie.reset();
+ m_xFtPercentDiagonal.reset();
+ m_xMtrPercentDiagonal.reset();
+ m_xFtBackscale.reset();
+ m_xMtrBackscale.reset();
+ m_xFtEndAngle.reset();
+ m_xMtrEndAngle.reset();
+ m_xFtDepth.reset();
+ m_xMtrDepth.reset();
+ m_xFLSegments.reset();
+ m_xNumHorizontal.reset();
+ m_xNumVertical.reset();
+ m_xFLNormals.reset();
+ m_xBtnNormalsObj.reset();
+ m_xBtnNormalsFlat.reset();
+ m_xBtnNormalsSphere.reset();
+ m_xBtnNormalsInvert.reset();
+ m_xBtnTwoSidedLighting.reset();
+ m_xBtnDoubleSided.reset();
+ m_xFLRepresentation.reset();
+ m_xLbShademode.reset();
+ m_xFLShadow.reset();
+ m_xBtnShadow3d.reset();
+ m_xFtSlant.reset();
+ m_xMtrSlant.reset();
+ m_xFLCamera.reset();
+ m_xMtrDistance.reset();
+ m_xMtrFocalLength.reset();
+ m_xFLLight.reset();
+ m_xBtnLight1.reset();
+ m_xBtnLight2.reset();
+ m_xBtnLight3.reset();
+ m_xBtnLight4.reset();
+ m_xBtnLight5.reset();
+ m_xBtnLight6.reset();
+ m_xBtnLight7.reset();
+ m_xBtnLight8.reset();
+ m_xLbLight1.reset();
+ m_xLbLight2.reset();
+ m_xLbLight3.reset();
+ m_xLbLight4.reset();
+ m_xLbLight5.reset();
+ m_xLbLight6.reset();
+ m_xLbLight7.reset();
+ m_xLbLight8.reset();
+ m_xBtnLightColor.reset();
+ m_xLbAmbientlight.reset();
+ m_xBtnAmbientColor.reset();
+ m_xFLTexture.reset();
+ m_xBtnTexLuminance.reset();
+ m_xBtnTexColor.reset();
+ m_xBtnTexReplace.reset();
+ m_xBtnTexModulate.reset();
+ m_xBtnTexBlend.reset();
+ m_xBtnTexObjectX.reset();
+ m_xBtnTexParallelX.reset();
+ m_xBtnTexCircleX.reset();
+ m_xBtnTexObjectY.reset();
+ m_xBtnTexParallelY.reset();
+ m_xBtnTexCircleY.reset();
+ m_xBtnTexFilter.reset();
+ m_xFLMaterial.reset();
+ m_xLbMatFavorites.reset();
+ m_xLbMatColor.reset();
+ m_xBtnMatColor.reset();
+ m_xLbMatEmission.reset();
+ m_xBtnEmissionColor.reset();
+ m_xFLMatSpecular.reset();
+ m_xLbMatSpecular.reset();
+ m_xBtnSpecularColor.reset();
+ m_xMtrMatSpecularIntensity.reset();
+ m_xCtlPreviewWin.reset();
+ m_xCtlPreview.reset();
+
+ m_xCtlLightPreview.reset();
+ m_xCtlLightPreviewWin.reset();
+ m_xLightPreview.reset();
+ m_xBtn_Corner.reset();
+ m_xVertScale.reset();
+ m_xHoriScale.reset();
+ m_xLightPreviewGrid.reset();
+
+ m_xBtnConvertTo3D.reset();
+ m_xBtnLatheObject.reset();
+ m_xBtnPerspective.reset();
+
+ SfxDockingWindow::dispose();
+}
+
+void Svx3DWin::Construct()
+{
+ m_xBtnGeo->set_active(true);
+ ClickViewTypeHdl(*m_xBtnGeo);
+ m_xLightPreviewGrid->hide();
+}
+
+void Svx3DWin::Reset()
+{
+ // Various initializations, default is AllAttributes
+ m_xLbShademode->set_active( 0 );
+ m_xMtrMatSpecularIntensity->set_value( 50, FieldUnit::PERCENT );
+
+ m_xBtnLight1->set_active(true);
+ m_xBtnUpdate->set_active(true);
+ ClickUpdateHdl(*m_xBtnUpdate);
+
+ // Select nothing, to avoid errors when selecting the first
+ m_xCtlLightPreview->GetSvx3DLightControl().SelectLight(0);
+ m_xCtlLightPreview->CheckSelection();
+}
+
+void Svx3DWin::Update( SfxItemSet const & rAttrs )
+{
+ // remember 2d attributes
+ if(mpRemember2DAttributes)
+ mpRemember2DAttributes->ClearItem();
+ else
+ mpRemember2DAttributes = std::make_unique<SfxItemSet>(*rAttrs.GetPool(),
+ svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
+ SDRATTR_3D_FIRST, SDRATTR_3D_LAST>{});
+
+ SfxWhichIter aIter(*mpRemember2DAttributes);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ SfxItemState eState = rAttrs.GetItemState(nWhich, false);
+ if(SfxItemState::DONTCARE == eState)
+ mpRemember2DAttributes->InvalidateItem(nWhich);
+ else if(SfxItemState::SET == eState)
+ mpRemember2DAttributes->Put(rAttrs.Get(nWhich, false));
+
+ nWhich = aIter.NextWhich();
+ }
+
+ // construct field values
+ const SfxPoolItem* pItem;
+
+ // Possible determine PoolUnit
+ if( !mpImpl->pPool )
+ {
+ mpImpl->pPool = rAttrs.GetPool();
+ DBG_ASSERT( mpImpl->pPool, "Where is the Pool? ");
+ ePoolUnit = mpImpl->pPool->GetMetric( SID_ATTR_LINE_WIDTH );
+ }
+ eFUnit = GetModuleFieldUnit( rAttrs );
+
+
+ // Segment Number Can be changed? and other states
+ SfxItemState eState = rAttrs.GetItemState( SID_ATTR_3D_INTERN, false, &pItem );
+ if( SfxItemState::SET == eState )
+ {
+ sal_uInt32 nState = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
+ bool bExtrude = ( nState & 2 );
+ bool bSphere = ( nState & 4 );
+ bool bCube = ( nState & 8 );
+
+ bool bChart = ( nState & 32 ); // Chart
+
+ if( !bChart )
+ {
+ // For cube objects are no segments set
+ m_xFLSegments->set_sensitive(!bCube);
+
+ m_xFtPercentDiagonal->set_sensitive( !bCube && !bSphere );
+ m_xMtrPercentDiagonal->set_sensitive( !bCube && !bSphere );
+ m_xFtBackscale->set_sensitive( !bCube && !bSphere );
+ m_xMtrBackscale->set_sensitive( !bCube && !bSphere );
+ m_xFtDepth->set_sensitive( !bCube && !bSphere );
+ m_xMtrDepth->set_sensitive( !bCube && !bSphere );
+ if( bCube )
+ {
+ m_xNumHorizontal->set_text("");
+ m_xNumVertical->set_text("");
+ }
+ if( bCube || bSphere )
+ {
+ m_xMtrPercentDiagonal->set_text("");
+ m_xMtrBackscale->set_text("");
+ m_xMtrDepth->set_text("");
+ }
+
+ // There is a final angle only for Lathe objects.
+ m_xFtEndAngle->set_sensitive( !bExtrude && !bCube && !bSphere );
+ m_xMtrEndAngle->set_sensitive( !bExtrude && !bCube && !bSphere );
+ if( bExtrude || bCube || bSphere )
+ m_xMtrEndAngle->set_text("");
+ }
+ else
+ {
+ // Geometry
+ m_xNumHorizontal->set_text("");
+ m_xNumVertical->set_text("");
+ m_xFLSegments->set_sensitive( false );
+ m_xFtEndAngle->set_sensitive( false );
+ m_xMtrEndAngle->set_sensitive( false );
+ m_xMtrEndAngle->set_text("");
+ m_xFtDepth->set_sensitive( false );
+ m_xMtrDepth->set_sensitive( false );
+ m_xMtrDepth->set_text("");
+
+ // Representation
+ m_xFLShadow->set_sensitive(false);
+
+ m_xMtrDistance->set_text("");
+ m_xMtrFocalLength->set_text("");
+ m_xFLCamera->set_sensitive( false );
+
+ //Lower Range
+ m_xBtnConvertTo3D->set_sensitive( false );
+ m_xBtnLatheObject->set_sensitive( false );
+ }
+ }
+ // Bitmap fill ? -> Status
+ bool bBitmap(false);
+ eState = rAttrs.GetItemState(XATTR_FILLSTYLE);
+ if(eState != SfxItemState::DONTCARE)
+ {
+ drawing::FillStyle eXFS = rAttrs.Get(XATTR_FILLSTYLE).GetValue();
+ bBitmap = (eXFS == drawing::FillStyle_BITMAP || eXFS == drawing::FillStyle_GRADIENT || eXFS == drawing::FillStyle_HATCH);
+ }
+
+ m_xFLTexture->set_sensitive(bBitmap);
+
+ // Geometry
+ // Number of segments (horizontal)
+ if( m_xNumHorizontal->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_HORZ_SEGS);
+ if(eState != SfxItemState::DONTCARE)
+ {
+ sal_uInt32 nValue = rAttrs.Get(SDRATTR_3DOBJ_HORZ_SEGS).GetValue();
+ if (nValue != static_cast<sal_uInt32>(m_xNumHorizontal->get_value()))
+ {
+ m_xNumHorizontal->set_value( nValue );
+ bUpdate = true;
+ }
+ else if( m_xNumHorizontal->get_text().isEmpty() )
+ m_xNumHorizontal->set_value( nValue );
+ }
+ else
+ {
+ if( !m_xNumHorizontal->get_text().isEmpty() )
+ {
+ m_xNumHorizontal->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ //Number of segments (vertical)
+ if( m_xNumVertical->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_VERT_SEGS);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt32 nValue = rAttrs.Get(SDRATTR_3DOBJ_VERT_SEGS).GetValue();
+ if( nValue != static_cast<sal_uInt32>(m_xNumVertical->get_value()) )
+ {
+ m_xNumVertical->set_value( nValue );
+ bUpdate = true;
+ }
+ else if( m_xNumVertical->get_text().isEmpty() )
+ m_xNumVertical->set_value( nValue );
+ }
+ else
+ {
+ if( !m_xNumVertical->get_text().isEmpty() )
+ {
+ m_xNumVertical->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ // Depth
+ if( m_xMtrDepth->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_DEPTH);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt32 nValue = rAttrs.Get(SDRATTR_3DOBJ_DEPTH).GetValue();
+ sal_uInt32 nValue2 = GetCoreValue(*m_xMtrDepth, ePoolUnit);
+ if( nValue != nValue2 )
+ {
+ if( eFUnit != m_xMtrDepth->get_unit() )
+ SetFieldUnit(*m_xMtrDepth, eFUnit);
+
+ SetMetricValue(*m_xMtrDepth, nValue, ePoolUnit);
+ bUpdate = true;
+ }
+ else if( m_xMtrDepth->get_text().isEmpty() )
+ m_xMtrDepth->set_value(m_xMtrDepth->get_value(FieldUnit::NONE), FieldUnit::NONE);
+ }
+ else
+ {
+ if( !m_xMtrDepth->get_text().isEmpty() )
+ {
+ m_xMtrDepth->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ // Double walled / Double sided
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_DOUBLE_SIDED);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bValue = rAttrs.Get(SDRATTR_3DOBJ_DOUBLE_SIDED).GetValue();
+ if( bValue != m_xBtnDoubleSided->get_active() )
+ {
+ m_xBtnDoubleSided->set_active( bValue );
+ bUpdate = true;
+ }
+ else if( m_xBtnDoubleSided->get_state() == TRISTATE_INDET )
+ m_xBtnDoubleSided->set_active( bValue );
+ }
+ else
+ {
+ if( m_xBtnDoubleSided->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnDoubleSided->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+
+ // Edge rounding
+ if( m_xMtrPercentDiagonal->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_PERCENT_DIAGONAL);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_PERCENT_DIAGONAL).GetValue();
+ if( nValue != m_xMtrPercentDiagonal->get_value(FieldUnit::PERCENT) )
+ {
+ m_xMtrPercentDiagonal->set_value(nValue, FieldUnit::PERCENT);
+ bUpdate = true;
+ }
+ else if( m_xMtrPercentDiagonal->get_text().isEmpty() )
+ m_xMtrPercentDiagonal->set_value(nValue, FieldUnit::PERCENT);
+ }
+ else
+ {
+ if( !m_xMtrPercentDiagonal->get_text().isEmpty() )
+ {
+ m_xMtrPercentDiagonal->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ // Depth scaling
+ if( m_xMtrBackscale->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_BACKSCALE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_BACKSCALE).GetValue();
+ if( nValue != m_xMtrBackscale->get_value(FieldUnit::PERCENT) )
+ {
+ m_xMtrBackscale->set_value(nValue, FieldUnit::PERCENT);
+ bUpdate = true;
+ }
+ else if( m_xMtrBackscale->get_text().isEmpty() )
+ m_xMtrBackscale->set_value(nValue, FieldUnit::PERCENT);
+ }
+ else
+ {
+ if( !m_xMtrBackscale->get_text().isEmpty() )
+ {
+ m_xMtrBackscale->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ // End angle
+ if( m_xMtrEndAngle->get_sensitive() )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_END_ANGLE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_Int32 nValue = rAttrs.Get(SDRATTR_3DOBJ_END_ANGLE).GetValue();
+ if( nValue != m_xMtrEndAngle->get_value(FieldUnit::DEGREE) )
+ {
+ m_xMtrEndAngle->set_value(nValue, FieldUnit::DEGREE);
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( !m_xMtrEndAngle->get_text().isEmpty() )
+ {
+ m_xMtrEndAngle->set_text("");
+ bUpdate = true;
+ }
+ }
+ }
+
+ // Normal type
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_NORMALS_KIND);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_NORMALS_KIND).GetValue();
+
+ if( ( !m_xBtnNormalsObj->get_active() && nValue == 0 ) ||
+ ( !m_xBtnNormalsFlat->get_active() && nValue == 1 ) ||
+ ( !m_xBtnNormalsSphere->get_active() && nValue == 2 ) )
+ {
+ m_xBtnNormalsObj->set_active( nValue == 0 );
+ m_xBtnNormalsFlat->set_active( nValue == 1 );
+ m_xBtnNormalsSphere->set_active( nValue == 2 );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xBtnNormalsObj->get_active() ||
+ m_xBtnNormalsFlat->get_active() ||
+ m_xBtnNormalsSphere->get_active() )
+ {
+ m_xBtnNormalsObj->set_active( false );
+ m_xBtnNormalsFlat->set_active( false );
+ m_xBtnNormalsSphere->set_active( false );
+ bUpdate = true;
+ }
+ }
+
+ // Normal inverted
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_NORMALS_INVERT);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bValue = rAttrs.Get(SDRATTR_3DOBJ_NORMALS_INVERT).GetValue();
+ if( bValue != m_xBtnNormalsInvert->get_active() )
+ {
+ m_xBtnNormalsInvert->set_active( bValue );
+ bUpdate = true;
+ }
+ else if( m_xBtnNormalsInvert->get_state() == TRISTATE_INDET )
+ m_xBtnNormalsInvert->set_active( bValue );
+ }
+ else
+ {
+ if( m_xBtnNormalsInvert->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnNormalsInvert->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+
+ // 2-sided lighting
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_TWO_SIDED_LIGHTING);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bValue = rAttrs.Get(SDRATTR_3DSCENE_TWO_SIDED_LIGHTING).GetValue();
+ if( bValue != m_xBtnTwoSidedLighting->get_active() )
+ {
+ m_xBtnTwoSidedLighting->set_active( bValue );
+ bUpdate = true;
+ }
+ else if( m_xBtnTwoSidedLighting->get_state() == TRISTATE_INDET )
+ m_xBtnTwoSidedLighting->set_active( bValue );
+ }
+ else
+ {
+ if( m_xBtnTwoSidedLighting->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnTwoSidedLighting->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+
+ // Representation
+ // Shademode
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_SHADE_MODE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DSCENE_SHADE_MODE).GetValue();
+ if( nValue != m_xLbShademode->get_active() )
+ {
+ m_xLbShademode->set_active( nValue );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xLbShademode->get_active() != 0 )
+ {
+ m_xLbShademode->set_active(-1);
+ bUpdate = true;
+ }
+ }
+
+ // 3D-Shadow
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_SHADOW_3D);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bValue = rAttrs.Get(SDRATTR_3DOBJ_SHADOW_3D).GetValue();
+ if( bValue != m_xBtnShadow3d->get_active() )
+ {
+ m_xBtnShadow3d->set_active( bValue );
+ m_xFtSlant->set_sensitive( bValue );
+ m_xMtrSlant->set_sensitive( bValue );
+ bUpdate = true;
+ }
+ else if( m_xBtnShadow3d->get_state() == TRISTATE_INDET )
+ m_xBtnShadow3d->set_active( bValue );
+ }
+ else
+ {
+ if( m_xBtnShadow3d->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnShadow3d->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+
+ // Inclination (Shadow)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_SHADOW_SLANT);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DSCENE_SHADOW_SLANT).GetValue();
+ if( nValue != m_xMtrSlant->get_value(FieldUnit::DEGREE) )
+ {
+ m_xMtrSlant->set_value(nValue, FieldUnit::DEGREE);
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( !m_xMtrSlant->get_text().isEmpty() )
+ {
+ m_xMtrSlant->set_text("");
+ bUpdate = true;
+ }
+ }
+
+ // Distance
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_DISTANCE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt32 nValue = rAttrs.Get(SDRATTR_3DSCENE_DISTANCE).GetValue();
+ sal_uInt32 nValue2 = GetCoreValue(*m_xMtrDistance, ePoolUnit);
+ if( nValue != nValue2 )
+ {
+ if( eFUnit != m_xMtrDistance->get_unit() )
+ SetFieldUnit(*m_xMtrDistance, eFUnit);
+
+ SetMetricValue(*m_xMtrDistance, nValue, ePoolUnit);
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( !m_xMtrDepth->get_text().isEmpty() )
+ {
+ m_xMtrDepth->set_text("");
+ bUpdate = true;
+ }
+ }
+
+ // Focal length
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_FOCAL_LENGTH);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt32 nValue = rAttrs.Get(SDRATTR_3DSCENE_FOCAL_LENGTH).GetValue();
+ sal_uInt32 nValue2 = GetCoreValue(*m_xMtrFocalLength, ePoolUnit);
+ if( nValue != nValue2 )
+ {
+ if( eFUnit != m_xMtrFocalLength->get_unit() )
+ SetFieldUnit(*m_xMtrFocalLength, eFUnit);
+
+ SetMetricValue(*m_xMtrFocalLength, nValue, ePoolUnit);
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( !m_xMtrFocalLength->get_text().isEmpty() )
+ {
+ m_xMtrFocalLength->set_text("");
+ bUpdate = true;
+ }
+ }
+
+// Lighting
+ Color aColor;
+ // Light 1 (Color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_1);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_1).GetValue();
+ ColorListBox* pLb = m_xLbLight1.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight1->IsNoSelection())
+ {
+ m_xLbLight1->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 1 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_1);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_1).GetValue();
+ if (bOn != m_xBtnLight1->isLightOn())
+ {
+ m_xBtnLight1->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight1->get_state() == TRISTATE_INDET )
+ m_xBtnLight1->set_active( m_xBtnLight1->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight1->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight1->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 1 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_1);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ //Light 2 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_2);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_2).GetValue();
+ ColorListBox* pLb = m_xLbLight2.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight2->IsNoSelection())
+ {
+ m_xLbLight2->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 2 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_2);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_2).GetValue();
+ if (bOn != m_xBtnLight2->isLightOn())
+ {
+ m_xBtnLight2->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight2->get_state() == TRISTATE_INDET )
+ m_xBtnLight2->set_active( m_xBtnLight2->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight2->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight2->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ //Light 2 (Direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_2);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ //Light 3 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_3);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_3).GetValue();
+ ColorListBox* pLb = m_xLbLight3.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight3->IsNoSelection())
+ {
+ m_xLbLight3->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 3 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_3);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_3).GetValue();
+ if (bOn != m_xBtnLight3->isLightOn())
+ {
+ m_xBtnLight3->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight3->get_state() == TRISTATE_INDET )
+ m_xBtnLight3->set_active( m_xBtnLight3->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight3->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight3->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 3 (Direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_3);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Light 4 (Color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_4);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_4).GetValue();
+ ColorListBox* pLb = m_xLbLight4.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight4->IsNoSelection())
+ {
+ m_xLbLight4->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 4 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_4);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_4).GetValue();
+ if (bOn != m_xBtnLight4->isLightOn())
+ {
+ m_xBtnLight4->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight4->get_state() == TRISTATE_INDET )
+ m_xBtnLight4->set_active( m_xBtnLight4->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight4->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight4->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 4 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_4);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Light 5 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_5);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_5).GetValue();
+ ColorListBox* pLb = m_xLbLight5.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight5->IsNoSelection())
+ {
+ m_xLbLight5->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 5 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_5);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_5).GetValue();
+ if (bOn != m_xBtnLight5->isLightOn())
+ {
+ m_xBtnLight5->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight5->get_state() == TRISTATE_INDET )
+ m_xBtnLight5->set_active( m_xBtnLight5->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight5->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight5->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 5 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_5);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Light 6 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_6);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_6).GetValue();
+ ColorListBox* pLb = m_xLbLight6.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight6->IsNoSelection())
+ {
+ m_xLbLight6->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 6 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_6);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_6).GetValue();
+ if (bOn != m_xBtnLight6->isLightOn())
+ {
+ m_xBtnLight6->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight6->get_state() == TRISTATE_INDET )
+ m_xBtnLight6->set_active( m_xBtnLight6->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight6->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight6->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 6 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_6);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Light 7 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_7);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_7).GetValue();
+ ColorListBox* pLb = m_xLbLight7.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight7->IsNoSelection())
+ {
+ m_xLbLight7->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 7 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_7);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_7).GetValue();
+ if (bOn != m_xBtnLight7->isLightOn())
+ {
+ m_xBtnLight7->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight7->get_state() == TRISTATE_INDET )
+ m_xBtnLight7->set_active( m_xBtnLight7->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight7->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight7->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 7 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_7);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Light 8 (color)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTCOLOR_8);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_LIGHTCOLOR_8).GetValue();
+ ColorListBox* pLb = m_xLbLight8.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbLight8->IsNoSelection())
+ {
+ m_xLbLight8->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+ // Light 8 (on/off)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTON_8);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bOn = rAttrs.Get(SDRATTR_3DSCENE_LIGHTON_8).GetValue();
+ if (bOn != m_xBtnLight8->isLightOn())
+ {
+ m_xBtnLight8->switchLightOn(bOn);
+ bUpdate = true;
+ }
+ if( m_xBtnLight8->get_state() == TRISTATE_INDET )
+ m_xBtnLight8->set_active( m_xBtnLight8->get_active() );
+ }
+ else
+ {
+ if( m_xBtnLight8->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnLight8->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ // Light 8 (direction)
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_LIGHTDIRECTION_8);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bUpdate = true;
+ }
+
+ // Ambient light
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_AMBIENTCOLOR);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DSCENE_AMBIENTCOLOR).GetValue();
+ ColorListBox* pLb = m_xLbAmbientlight.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbAmbientlight->IsNoSelection())
+ {
+ m_xLbAmbientlight->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+
+
+// Textures
+ // Art
+ if( bBitmap )
+ {
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_TEXTURE_KIND);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_TEXTURE_KIND).GetValue();
+
+ if( ( !m_xBtnTexLuminance->get_active() && nValue == 1 ) ||
+ ( !m_xBtnTexColor->get_active() && nValue == 3 ) )
+ {
+ m_xBtnTexLuminance->set_active( nValue == 1 );
+ m_xBtnTexColor->set_active( nValue == 3 );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xBtnTexLuminance->get_active() ||
+ m_xBtnTexColor->get_active() )
+ {
+ m_xBtnTexLuminance->set_active( false );
+ m_xBtnTexColor->set_active( false );
+ bUpdate = true;
+ }
+ }
+
+ // Mode
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_TEXTURE_MODE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_TEXTURE_MODE).GetValue();
+
+ if( ( !m_xBtnTexReplace->get_active() && nValue == 1 ) ||
+ ( !m_xBtnTexModulate->get_active() && nValue == 2 ) )
+ {
+ m_xBtnTexReplace->set_active( nValue == 1 );
+ m_xBtnTexModulate->set_active( nValue == 2 );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xBtnTexReplace->get_active() ||
+ m_xBtnTexModulate->get_active() )
+ {
+ m_xBtnTexReplace->set_active( false );
+ m_xBtnTexModulate->set_active( false );
+ bUpdate = true;
+ }
+ }
+
+ // Projection X
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_TEXTURE_PROJ_X);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_TEXTURE_PROJ_X).GetValue();
+
+ if( ( !m_xBtnTexObjectX->get_active() && nValue == 0 ) ||
+ ( !m_xBtnTexParallelX->get_active() && nValue == 1 ) ||
+ ( !m_xBtnTexCircleX->get_active() && nValue == 2 ) )
+ {
+ m_xBtnTexObjectX->set_active( nValue == 0 );
+ m_xBtnTexParallelX->set_active( nValue == 1 );
+ m_xBtnTexCircleX->set_active( nValue == 2 );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xBtnTexObjectX->get_active() ||
+ m_xBtnTexParallelX->get_active() ||
+ m_xBtnTexCircleX->get_active() )
+ {
+ m_xBtnTexObjectX->set_active( false );
+ m_xBtnTexParallelX->set_active( false );
+ m_xBtnTexCircleX->set_active( false );
+ bUpdate = true;
+ }
+ }
+
+ // Projection Y
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_TEXTURE_PROJ_Y);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_TEXTURE_PROJ_Y).GetValue();
+
+ if( ( !m_xBtnTexObjectY->get_active() && nValue == 0 ) ||
+ ( !m_xBtnTexParallelY->get_active() && nValue == 1 ) ||
+ ( !m_xBtnTexCircleY->get_active() && nValue == 2 ) )
+ {
+ m_xBtnTexObjectY->set_active( nValue == 0 );
+ m_xBtnTexParallelY->set_active( nValue == 1 );
+ m_xBtnTexCircleY->set_active( nValue == 2 );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( m_xBtnTexObjectY->get_active() ||
+ m_xBtnTexParallelY->get_active() ||
+ m_xBtnTexCircleY->get_active() )
+ {
+ m_xBtnTexObjectY->set_active( false );
+ m_xBtnTexParallelY->set_active( false );
+ m_xBtnTexCircleY->set_active( false );
+ bUpdate = true;
+ }
+ }
+
+ // Filter
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_TEXTURE_FILTER);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ bool bValue = rAttrs.Get(SDRATTR_3DOBJ_TEXTURE_FILTER).GetValue();
+ if( bValue != m_xBtnTexFilter->get_active() )
+ {
+ m_xBtnTexFilter->set_active( bValue );
+ bUpdate = true;
+ }
+ if( m_xBtnTexFilter->get_state() == TRISTATE_INDET )
+ m_xBtnTexFilter->set_active( bValue );
+ }
+ else
+ {
+ if( m_xBtnTexFilter->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnTexFilter->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+ }
+
+
+ // Material Favorites
+ m_xLbMatFavorites->set_active( 0 );
+
+ // Object color
+ eState = rAttrs.GetItemState(XATTR_FILLCOLOR);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(XATTR_FILLCOLOR).GetColorValue();
+ ColorListBox* pLb = m_xLbMatColor.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbMatColor->IsNoSelection())
+ {
+ m_xLbMatColor->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+
+ // Self-luminous color
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_MAT_EMISSION);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DOBJ_MAT_EMISSION).GetValue();
+ ColorListBox* pLb = m_xLbMatEmission.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbMatEmission->IsNoSelection())
+ {
+ m_xLbMatEmission->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+
+ // Specular
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_MAT_SPECULAR);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ aColor = rAttrs.Get(SDRATTR_3DOBJ_MAT_SPECULAR).GetValue();
+ ColorListBox* pLb = m_xLbMatSpecular.get();
+ if( aColor != pLb->GetSelectEntryColor() )
+ {
+ LBSelectColor( pLb, aColor );
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if (!m_xLbMatSpecular->IsNoSelection())
+ {
+ m_xLbMatSpecular->SetNoSelection();
+ bUpdate = true;
+ }
+ }
+
+ // Specular Intensity
+ eState = rAttrs.GetItemState(SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ sal_uInt16 nValue = rAttrs.Get(SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY).GetValue();
+ if( nValue != m_xMtrMatSpecularIntensity->get_value(FieldUnit::PERCENT) )
+ {
+ m_xMtrMatSpecularIntensity->set_value(nValue, FieldUnit::PERCENT);
+ bUpdate = true;
+ }
+ }
+ else
+ {
+ if( !m_xMtrMatSpecularIntensity->get_text().isEmpty() )
+ {
+ m_xMtrMatSpecularIntensity->set_text("");
+ bUpdate = true;
+ }
+ }
+
+
+// Other
+ // Perspective
+ eState = rAttrs.GetItemState(SDRATTR_3DSCENE_PERSPECTIVE);
+ if( eState != SfxItemState::DONTCARE )
+ {
+ ProjectionType ePT = static_cast<ProjectionType>(rAttrs.Get(SDRATTR_3DSCENE_PERSPECTIVE).GetValue());
+ if( ( !m_xBtnPerspective->get_active() && ePT == ProjectionType::Perspective ) ||
+ ( m_xBtnPerspective->get_active() && ePT == ProjectionType::Parallel ) )
+ {
+ m_xBtnPerspective->set_active( ePT == ProjectionType::Perspective );
+ bUpdate = true;
+ }
+ if( m_xBtnPerspective->get_state() == TRISTATE_INDET )
+ m_xBtnPerspective->set_active( ePT == ProjectionType::Perspective );
+ }
+ else
+ {
+ if( m_xBtnPerspective->get_state() != TRISTATE_INDET )
+ {
+ m_xBtnPerspective->set_state( TRISTATE_INDET );
+ bUpdate = true;
+ }
+ }
+
+ if( !bUpdate )
+ {
+ // however the 2D attributes may be different. Compare these and decide
+
+ bUpdate = true;
+ }
+
+ // Update preview
+ SfxItemSet aSet(rAttrs);
+
+ // set LineStyle hard to drawing::LineStyle_NONE when it's not set so that
+ // the default (drawing::LineStyle_SOLID) is not used for 3d preview
+ if(SfxItemState::SET != aSet.GetItemState(XATTR_LINESTYLE, false))
+ aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+
+ // set FillColor hard to WHITE when it's SfxItemState::DONTCARE so that
+ // the default (Blue7) is not used for 3d preview
+ if(SfxItemState::DONTCARE == aSet.GetItemState(XATTR_FILLCOLOR, false))
+ aSet.Put(XFillColorItem(OUString(), COL_WHITE));
+
+ m_xCtlPreview->Set3DAttributes(aSet);
+ m_xCtlLightPreview->GetSvx3DLightControl().Set3DAttributes(aSet);
+
+ // try to select light corresponding to active button
+ sal_uInt32 nNumber(0xffffffff);
+
+ if(m_xBtnLight1->get_active())
+ nNumber = 0;
+ else if(m_xBtnLight2->get_active())
+ nNumber = 1;
+ else if(m_xBtnLight3->get_active())
+ nNumber = 2;
+ else if(m_xBtnLight4->get_active())
+ nNumber = 3;
+ else if(m_xBtnLight5->get_active())
+ nNumber = 4;
+ else if(m_xBtnLight6->get_active())
+ nNumber = 5;
+ else if(m_xBtnLight7->get_active())
+ nNumber = 6;
+ else if(m_xBtnLight8->get_active())
+ nNumber = 7;
+
+ if(nNumber != 0xffffffff)
+ {
+ m_xCtlLightPreview->GetSvx3DLightControl().SelectLight(nNumber);
+ }
+
+ // handle state of converts possible
+ m_xBtnConvertTo3D->set_sensitive(pConvertTo3DItem->GetState());
+ m_xBtnLatheObject->set_sensitive(pConvertTo3DLatheItem->GetState());
+}
+
+
+void Svx3DWin::GetAttr( SfxItemSet& rAttrs )
+{
+ // get remembered 2d attributes from the dialog
+ if(mpRemember2DAttributes)
+ {
+ SfxWhichIter aIter(*mpRemember2DAttributes);
+ sal_uInt16 nWhich(aIter.FirstWhich());
+
+ while(nWhich)
+ {
+ SfxItemState eState = mpRemember2DAttributes->GetItemState(nWhich, false);
+ if(SfxItemState::DONTCARE == eState)
+ rAttrs.InvalidateItem(nWhich);
+ else if(SfxItemState::SET == eState)
+ rAttrs.Put(mpRemember2DAttributes->Get(nWhich, false));
+
+ nWhich = aIter.NextWhich();
+ }
+ }
+
+//Others must stand as the front on all sides
+ // Perspective
+ if( m_xBtnPerspective->get_state() != TRISTATE_INDET )
+ {
+ ProjectionType nValue;
+ if( m_xBtnPerspective->get_active() )
+ nValue = ProjectionType::Perspective;
+ else
+ nValue = ProjectionType::Parallel;
+ rAttrs.Put(Svx3DPerspectiveItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_PERSPECTIVE);
+
+// Geometry
+ // Possible determine PoolUnit (in this case this has not happened in Update() )
+ if( !mpImpl->pPool )
+ {
+ OSL_FAIL( "No Pool in GetAttr()! May be incompatible to drviewsi.cxx ?" );
+ mpImpl->pPool = rAttrs.GetPool();
+ DBG_ASSERT( mpImpl->pPool, "Where is the Pool?" );
+ ePoolUnit = mpImpl->pPool->GetMetric( SID_ATTR_LINE_WIDTH );
+
+ eFUnit = GetModuleFieldUnit( rAttrs );
+ }
+
+ // Number of segments (horizontal)
+ if( !m_xNumHorizontal->get_text().isEmpty() )
+ {
+ sal_uInt32 nValue = static_cast<sal_uInt32>(m_xNumHorizontal->get_value());
+ rAttrs.Put(makeSvx3DHorizontalSegmentsItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_HORZ_SEGS);
+
+ // Number of segments (vertical)
+ if( !m_xNumVertical->get_text().isEmpty() )
+ {
+ sal_uInt32 nValue = static_cast<sal_uInt32>(m_xNumVertical->get_value());
+ rAttrs.Put(makeSvx3DVerticalSegmentsItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_VERT_SEGS);
+
+ // Depth
+ if( !m_xMtrDepth->get_text().isEmpty() )
+ {
+ sal_uInt32 nValue = GetCoreValue(*m_xMtrDepth, ePoolUnit);
+ rAttrs.Put(makeSvx3DDepthItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_DEPTH);
+
+ // Double-sided
+ TriState eState = m_xBtnDoubleSided->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = TRISTATE_TRUE == eState;
+ rAttrs.Put(makeSvx3DDoubleSidedItem(bValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_DOUBLE_SIDED);
+
+ // Edge rounding
+ if( !m_xMtrPercentDiagonal->get_text().isEmpty() )
+ {
+ sal_uInt16 nValue = static_cast<sal_uInt16>(m_xMtrPercentDiagonal->get_value(FieldUnit::PERCENT));
+ rAttrs.Put(makeSvx3DPercentDiagonalItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_PERCENT_DIAGONAL);
+
+ // Depth scale
+ if( !m_xMtrBackscale->get_text().isEmpty() )
+ {
+ sal_uInt16 nValue = static_cast<sal_uInt16>(m_xMtrBackscale->get_value(FieldUnit::PERCENT));
+ rAttrs.Put(makeSvx3DBackscaleItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_BACKSCALE);
+
+ // End angle
+ if( !m_xMtrEndAngle->get_text().isEmpty() )
+ {
+ sal_uInt16 nValue = static_cast<sal_uInt16>(m_xMtrEndAngle->get_value(FieldUnit::DEGREE));
+ rAttrs.Put(makeSvx3DEndAngleItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_END_ANGLE);
+
+ // Normal type
+ sal_uInt16 nValue = 99;
+ if( m_xBtnNormalsObj->get_active() )
+ nValue = 0;
+ else if( m_xBtnNormalsFlat->get_active() )
+ nValue = 1;
+ else if( m_xBtnNormalsSphere->get_active() )
+ nValue = 2;
+
+ if( nValue <= 2 )
+ rAttrs.Put(Svx3DNormalsKindItem(nValue));
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_NORMALS_KIND);
+
+ // Normal inverted
+ eState = m_xBtnNormalsInvert->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = TRISTATE_TRUE == eState;
+ rAttrs.Put(makeSvx3DNormalsInvertItem(bValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_NORMALS_INVERT);
+
+ // 2-sided lighting
+ eState = m_xBtnTwoSidedLighting->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = TRISTATE_TRUE == eState;
+ rAttrs.Put(makeSvx3DTwoSidedLightingItem(bValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_TWO_SIDED_LIGHTING);
+
+// Representation
+ // Shade mode
+ if( m_xLbShademode->get_active() != -1 )
+ {
+ nValue = m_xLbShademode->get_active();
+ rAttrs.Put(Svx3DShadeModeItem(nValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_SHADE_MODE);
+
+ // 3D-Shadow
+ eState = m_xBtnShadow3d->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = TRISTATE_TRUE == eState;
+ rAttrs.Put(makeSvx3DShadow3DItem(bValue));
+ rAttrs.Put(makeSdrShadowItem(bValue));
+ }
+ else
+ {
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_SHADOW_3D);
+ rAttrs.InvalidateItem(SDRATTR_SHADOW);
+ }
+
+ // Slant (Shadow)
+ if( !m_xMtrSlant->get_text().isEmpty() )
+ {
+ sal_uInt16 nValue2 = static_cast<sal_uInt16>(m_xMtrSlant->get_value(FieldUnit::DEGREE));
+ rAttrs.Put(makeSvx3DShadowSlantItem(nValue2));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_SHADOW_SLANT);
+
+ // Distance
+ if( !m_xMtrDistance->get_text().isEmpty() )
+ {
+ sal_uInt32 nValue2 = GetCoreValue(*m_xMtrDistance, ePoolUnit);
+ rAttrs.Put(makeSvx3DDistanceItem(nValue2));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_DISTANCE);
+
+ // Focal length
+ if( !m_xMtrFocalLength->get_text().isEmpty() )
+ {
+ sal_uInt32 nValue2 = GetCoreValue(*m_xMtrFocalLength, ePoolUnit);
+ rAttrs.Put(makeSvx3DFocalLengthItem(nValue2));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_FOCAL_LENGTH);
+
+ // Lighting
+ Color aColor;
+ const SfxItemSet aLightItemSet(m_xCtlLightPreview->GetSvx3DLightControl().Get3DAttributes());
+
+ // Light 1 color
+ if (!m_xLbLight1->IsNoSelection())
+ {
+ aColor = m_xLbLight1->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor1Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_1);
+ // Light 1 (on/off)
+ eState = m_xBtnLight1->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight1->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff1Item(bValue));
+
+ // Light 1 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_1));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_1);
+
+
+ // Light 2 color
+ if (!m_xLbLight2->IsNoSelection())
+ {
+ aColor = m_xLbLight2->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor2Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_2);
+ // Light 2 (on/off)
+ eState = m_xBtnLight2->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight2->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff2Item(bValue));
+
+ // Light 2 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_2));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_2);
+
+ // Light 3 color
+ if (!m_xLbLight3->IsNoSelection())
+ {
+ aColor = m_xLbLight3->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor3Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_3);
+ // Light 3 (on/off)
+ eState = m_xBtnLight3->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight3->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff3Item(bValue));
+
+ // Light 3 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_3));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_3);
+
+ // Light 4 color
+ if (!m_xLbLight4->IsNoSelection())
+ {
+ aColor = m_xLbLight4->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor4Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_4);
+ // Light 4 (on/off)
+ eState = m_xBtnLight4->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight4->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff4Item(bValue));
+
+ // Light 4 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_4));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_4);
+
+ // Light 5 color
+ if (!m_xLbLight5->IsNoSelection())
+ {
+ aColor = m_xLbLight5->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor5Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_5);
+ // Light 5 (on/off)
+ eState = m_xBtnLight5->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight5->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff5Item(bValue));
+
+ // Light 5 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_5));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_5);
+
+ // Light 6 color
+ if (!m_xLbLight6->IsNoSelection())
+ {
+ aColor = m_xLbLight6->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor6Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_6);
+ // Light 6 (on/off)
+ eState = m_xBtnLight6->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight6->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff6Item(bValue));
+
+ // Light 6 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_6));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_6);
+
+ // Light 7 color
+ if (!m_xLbLight7->IsNoSelection())
+ {
+ aColor = m_xLbLight7->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor7Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_7);
+ // Light 7 (on/off)
+ eState = m_xBtnLight7->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight7->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff7Item(bValue));
+
+ // Light 7 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_7));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_7);
+
+ // Light 8 color
+ if (!m_xLbLight8->IsNoSelection())
+ {
+ aColor = m_xLbLight8->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DLightcolor8Item(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTCOLOR_8);
+ // Light 8 (on/off)
+ eState = m_xBtnLight8->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = m_xBtnLight8->isLightOn();
+ rAttrs.Put(makeSvx3DLightOnOff8Item(bValue));
+
+ // Light 8 (direction)
+ if( bValue )
+ {
+ rAttrs.Put(aLightItemSet.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_8));
+ }
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_LIGHTON_8);
+
+ // Ambient light
+ if (!m_xLbAmbientlight->IsNoSelection())
+ {
+ aColor = m_xLbAmbientlight->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DAmbientcolorItem(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DSCENE_AMBIENTCOLOR);
+
+// Textures
+ // Art
+ nValue = 99;
+ if( m_xBtnTexLuminance->get_active() )
+ nValue = 1;
+ else if( m_xBtnTexColor->get_active() )
+ nValue = 3;
+
+ if( nValue == 1 || nValue == 3 )
+ rAttrs.Put(Svx3DTextureKindItem(nValue));
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_TEXTURE_KIND);
+
+
+ // Mode
+ nValue = 99;
+ if( m_xBtnTexReplace->get_active() )
+ nValue = 1;
+ else if( m_xBtnTexModulate->get_active() )
+ nValue = 2;
+
+ if( nValue == 1 || nValue == 2 )
+ rAttrs.Put(Svx3DTextureModeItem(nValue));
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_TEXTURE_MODE);
+
+ // X projection
+ nValue = 99;
+ if( m_xBtnTexObjectX->get_active() )
+ nValue = 0;
+ else if( m_xBtnTexParallelX->get_active() )
+ nValue = 1;
+ else if( m_xBtnTexCircleX->get_active() )
+ nValue = 2;
+
+ if( nValue <= 2 )
+ rAttrs.Put(Svx3DTextureProjectionXItem(nValue));
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_TEXTURE_PROJ_X);
+
+ // Y projection
+ nValue = 99;
+ if( m_xBtnTexObjectY->get_active() )
+ nValue = 0;
+ else if( m_xBtnTexParallelY->get_active() )
+ nValue = 1;
+ else if( m_xBtnTexCircleY->get_active() )
+ nValue = 2;
+
+ if( nValue <= 2 )
+ rAttrs.Put(Svx3DTextureProjectionYItem(nValue));
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_TEXTURE_PROJ_Y);
+
+
+ // Filter
+ eState = m_xBtnTexFilter->get_state();
+ if( eState != TRISTATE_INDET )
+ {
+ bool bValue = TRISTATE_TRUE == eState;
+ rAttrs.Put(makeSvx3DTextureFilterItem(bValue));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_TEXTURE_FILTER);
+
+
+// Material
+ // Object color
+ if (!m_xLbMatColor->IsNoSelection())
+ {
+ aColor = m_xLbMatColor->GetSelectEntryColor();
+ rAttrs.Put( XFillColorItem( "", aColor) );
+ }
+ else
+ {
+ rAttrs.InvalidateItem( XATTR_FILLCOLOR );
+ }
+
+ // luminous color
+ if (!m_xLbMatEmission->IsNoSelection())
+ {
+ aColor = m_xLbMatEmission->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DMaterialEmissionItem(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_MAT_EMISSION);
+
+ // Specular
+ if (!m_xLbMatSpecular->IsNoSelection())
+ {
+ aColor = m_xLbMatSpecular->GetSelectEntryColor();
+ rAttrs.Put(makeSvx3DMaterialSpecularItem(aColor));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_MAT_SPECULAR);
+
+ // Specular intensity
+ if( !m_xMtrMatSpecularIntensity->get_text().isEmpty() )
+ {
+ sal_uInt16 nValue2 = static_cast<sal_uInt16>(m_xMtrMatSpecularIntensity->get_value(FieldUnit::PERCENT));
+ rAttrs.Put(makeSvx3DMaterialSpecularIntensityItem(nValue2));
+ }
+ else
+ rAttrs.InvalidateItem(SDRATTR_3DOBJ_MAT_SPECULAR_INTENSITY);
+}
+
+void Svx3DWin::Resize()
+{
+ if ( !IsFloatingMode() ||
+ !GetFloatingWindow()->IsRollUp() )
+ {
+ Size aWinSize( GetOutputSizePixel() ); // why rSize in Resizing()?
+
+ if( aWinSize.Height() >= GetMinOutputSizePixel().Height() &&
+ aWinSize.Width() >= GetMinOutputSizePixel().Width() )
+ {
+ // Hide
+ m_xBtnUpdate->hide();
+ m_xBtnAssign->hide();
+
+ m_xBtnConvertTo3D->hide();
+ m_xBtnLatheObject->hide();
+ m_xBtnPerspective->hide();
+
+ m_xCtlPreview->Hide();
+ m_xLightPreviewGrid->hide();
+
+ m_xFLGeometrie->hide();
+ m_xFLRepresentation->hide();
+ m_xFLLight->hide();
+ m_xFLTexture->hide();
+ m_xFLMaterial->hide();
+
+ // Show
+ m_xBtnUpdate->show();
+ m_xBtnAssign->show();
+
+ m_xBtnConvertTo3D->show();
+ m_xBtnLatheObject->show();
+ m_xBtnPerspective->show();
+
+ if( m_xBtnGeo->get_active() )
+ ClickViewTypeHdl(*m_xBtnGeo);
+ if( m_xBtnRepresentation->get_active() )
+ ClickViewTypeHdl(*m_xBtnRepresentation);
+ if( m_xBtnLight->get_active() )
+ ClickViewTypeHdl(*m_xBtnLight);
+ if( m_xBtnTexture->get_active() )
+ ClickViewTypeHdl(*m_xBtnTexture);
+ if( m_xBtnMaterial->get_active() )
+ ClickViewTypeHdl(*m_xBtnMaterial);
+ }
+ }
+
+ SfxDockingWindow::Resize();
+}
+
+IMPL_LINK_NOARG(Svx3DWin, ClickUpdateHdl, weld::ToggleButton&, void)
+{
+ bUpdate = m_xBtnUpdate->get_active();
+
+ if( bUpdate )
+ {
+ SfxDispatcher* pDispatcher = LocalGetDispatcher(pBindings);
+ if (pDispatcher != nullptr)
+ {
+ SfxBoolItem aItem( SID_3D_STATE, true );
+ pDispatcher->ExecuteList(SID_3D_STATE,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+ }
+ }
+ else
+ {
+ // Controls can be disabled during certain circumstances
+ }
+}
+
+IMPL_LINK_NOARG(Svx3DWin, ClickAssignHdl, weld::Button&, void)
+{
+ SfxDispatcher* pDispatcher = LocalGetDispatcher(pBindings);
+ if (pDispatcher != nullptr)
+ {
+ SfxBoolItem aItem( SID_3D_ASSIGN, true );
+ pDispatcher->ExecuteList(SID_3D_ASSIGN,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+ }
+}
+
+IMPL_LINK( Svx3DWin, ClickViewTypeHdl, weld::Button&, rBtn, void )
+{
+ // Since the permanent updating of the preview would be too expensive
+ bool bUpdatePreview = m_xBtnLight->get_active();
+
+ m_xBtnGeo->set_active(m_xBtnGeo.get() == &rBtn);
+ m_xBtnRepresentation->set_active(m_xBtnRepresentation.get() == &rBtn);
+ m_xBtnLight->set_active(m_xBtnLight.get() == &rBtn);
+ m_xBtnTexture->set_active(m_xBtnTexture.get() == &rBtn);
+ m_xBtnMaterial->set_active(m_xBtnMaterial.get() == &rBtn);
+
+ if( m_xBtnGeo->get_active() )
+ eViewType = ViewType3D::Geo;
+ if( m_xBtnRepresentation->get_active() )
+ eViewType = ViewType3D::Representation;
+ if( m_xBtnLight->get_active() )
+ eViewType = ViewType3D::Light;
+ if( m_xBtnTexture->get_active() )
+ eViewType = ViewType3D::Texture;
+ if( m_xBtnMaterial->get_active() )
+ eViewType = ViewType3D::Material;
+
+ // Geometry
+ if( eViewType == ViewType3D::Geo )
+ {
+ m_xFLSegments->show();
+ m_xFLGeometrie->show();
+ m_xFLNormals->show();
+ }
+ else
+ {
+ m_xFLSegments->hide();
+ m_xFLGeometrie->hide();
+ m_xFLNormals->hide();
+ }
+
+ // Representation
+ if( eViewType == ViewType3D::Representation )
+ {
+ m_xFLShadow->show();
+ m_xFLCamera->show();
+ m_xFLRepresentation->show();
+ }
+ else
+ {
+ m_xFLShadow->hide();
+ m_xFLCamera->hide();
+ m_xFLRepresentation->hide();
+ }
+
+ // Lighting
+ if( eViewType == ViewType3D::Light )
+ {
+ m_xFLLight->show();
+
+ ColorListBox* pLb = GetCLbByButton();
+ if( pLb )
+ pLb->show();
+
+ m_xLightPreviewGrid->show();
+ m_xCtlPreview->Hide();
+ }
+ else
+ {
+ m_xFLLight->hide();
+
+ if( !m_xCtlPreview->IsVisible() )
+ {
+ m_xCtlPreview->Show();
+ m_xLightPreviewGrid->hide();
+ }
+ }
+
+ // Textures
+ if (eViewType == ViewType3D::Texture)
+ m_xFLTexture->show();
+ else
+ m_xFLTexture->hide();
+
+ // Material
+ if( eViewType == ViewType3D::Material )
+ {
+ m_xFLMatSpecular->show();
+ m_xFLMaterial->show();
+ }
+ else
+ {
+ m_xFLMatSpecular->hide();
+ m_xFLMaterial->hide();
+ }
+ if( bUpdatePreview && !m_xBtnLight->get_active() )
+ UpdatePreview();
+}
+
+IMPL_LINK( Svx3DWin, ClickHdl, weld::Button&, rBtn, void )
+{
+ bool bUpdatePreview = false;
+ sal_uInt16 nSId = 0;
+
+ if( &rBtn == m_xBtnConvertTo3D.get() )
+ {
+ nSId = SID_CONVERT_TO_3D;
+ }
+ else if( &rBtn == m_xBtnLatheObject.get() )
+ {
+ nSId = SID_CONVERT_TO_3D_LATHE_FAST;
+ }
+ // Geometry
+ else if( &rBtn == m_xBtnNormalsObj.get() ||
+ &rBtn == m_xBtnNormalsFlat.get() ||
+ &rBtn == m_xBtnNormalsSphere.get() )
+ {
+ m_xBtnNormalsObj->set_active( &rBtn == m_xBtnNormalsObj.get() );
+ m_xBtnNormalsFlat->set_active( &rBtn == m_xBtnNormalsFlat.get() );
+ m_xBtnNormalsSphere->set_active( &rBtn == m_xBtnNormalsSphere.get() );
+ bUpdatePreview = true;
+ }
+ else if( &rBtn == m_xBtnLight1->get_widget() ||
+ &rBtn == m_xBtnLight2->get_widget() ||
+ &rBtn == m_xBtnLight3->get_widget() ||
+ &rBtn == m_xBtnLight4->get_widget() ||
+ &rBtn == m_xBtnLight5->get_widget() ||
+ &rBtn == m_xBtnLight6->get_widget() ||
+ &rBtn == m_xBtnLight7->get_widget() ||
+ &rBtn == m_xBtnLight8->get_widget() )
+ {
+ // Lighting
+ LightButton* pToggleBtn = GetLbByButton(&rBtn);
+
+ ColorListBox* pLb = GetCLbByButton(pToggleBtn);
+ pLb->show();
+
+ bool bIsChecked = pToggleBtn->get_prev_active();
+
+ if (pToggleBtn != m_xBtnLight1.get() && m_xBtnLight1->get_active())
+ {
+ m_xBtnLight1->set_active( false );
+ m_xBtnLight1->set_prev_active(false);
+ m_xLbLight1->hide();
+ }
+ if (pToggleBtn != m_xBtnLight2.get() && m_xBtnLight2->get_active())
+ {
+ m_xBtnLight2->set_active( false );
+ m_xBtnLight2->set_prev_active(false);
+ m_xLbLight2->hide();
+ }
+ if( pToggleBtn != m_xBtnLight3.get() && m_xBtnLight3->get_active() )
+ {
+ m_xBtnLight3->set_active( false );
+ m_xBtnLight3->set_prev_active(false);
+ m_xLbLight3->hide();
+ }
+ if( pToggleBtn != m_xBtnLight4.get() && m_xBtnLight4->get_active() )
+ {
+ m_xBtnLight4->set_active( false );
+ m_xBtnLight4->set_prev_active(false);
+ m_xLbLight4->hide();
+ }
+ if( pToggleBtn != m_xBtnLight5.get() && m_xBtnLight5->get_active() )
+ {
+ m_xBtnLight5->set_active( false );
+ m_xBtnLight5->set_prev_active(false);
+ m_xLbLight5->hide();
+ }
+ if( pToggleBtn != m_xBtnLight6.get() && m_xBtnLight6->get_active() )
+ {
+ m_xBtnLight6->set_active( false );
+ m_xBtnLight6->set_prev_active(false);
+ m_xLbLight6->hide();
+ }
+ if( pToggleBtn != m_xBtnLight7.get() && m_xBtnLight7->get_active() )
+ {
+ m_xBtnLight7->set_active( false );
+ m_xBtnLight7->set_prev_active(false);
+ m_xLbLight7->hide();
+ }
+ if( pToggleBtn != m_xBtnLight8.get() && m_xBtnLight8->get_active() )
+ {
+ m_xBtnLight8->set_active( false );
+ m_xBtnLight8->set_prev_active(false);
+ m_xLbLight8->hide();
+ }
+
+ //update light button
+ pToggleBtn->set_active(true);
+ pToggleBtn->set_prev_active(true);
+ if (bIsChecked)
+ pToggleBtn->switchLightOn(!pToggleBtn->isLightOn());
+
+ bool bEnable = pToggleBtn->isLightOn();
+ m_xBtnLightColor->set_sensitive( bEnable );
+ pLb->set_sensitive( bEnable );
+
+ ClickLight(*pToggleBtn);
+ bUpdatePreview = true;
+ }
+ // Textures
+ else if( &rBtn == m_xBtnTexLuminance.get() ||
+ &rBtn == m_xBtnTexColor.get() )
+ {
+ m_xBtnTexLuminance->set_active( &rBtn == m_xBtnTexLuminance.get() );
+ m_xBtnTexColor->set_active( &rBtn == m_xBtnTexColor.get() );
+ bUpdatePreview = true;
+ }
+ else if( &rBtn == m_xBtnTexReplace.get() ||
+ &rBtn == m_xBtnTexModulate.get() )
+ {
+ m_xBtnTexReplace->set_active( &rBtn == m_xBtnTexReplace.get() );
+ m_xBtnTexModulate->set_active( &rBtn == m_xBtnTexModulate.get() );
+ bUpdatePreview = true;
+ }
+ else if( &rBtn == m_xBtnTexParallelX.get() ||
+ &rBtn == m_xBtnTexCircleX.get() ||
+ &rBtn == m_xBtnTexObjectX.get() )
+ {
+ m_xBtnTexParallelX->set_active( &rBtn == m_xBtnTexParallelX.get() );
+ m_xBtnTexCircleX->set_active( &rBtn == m_xBtnTexCircleX.get() );
+ m_xBtnTexObjectX->set_active( &rBtn == m_xBtnTexObjectX.get() );
+ bUpdatePreview = true;
+ }
+ else if( &rBtn == m_xBtnTexParallelY.get() ||
+ &rBtn == m_xBtnTexCircleY.get() ||
+ &rBtn == m_xBtnTexObjectY.get() )
+ {
+ m_xBtnTexParallelY->set_active( &rBtn == m_xBtnTexParallelY.get() );
+ m_xBtnTexCircleY->set_active( &rBtn == m_xBtnTexCircleY.get() );
+ m_xBtnTexObjectY->set_active( &rBtn == m_xBtnTexObjectY.get() );
+ bUpdatePreview = true;
+ }
+ else if (&rBtn == m_xBtnShadow3d.get())
+ {
+ m_xFtSlant->set_sensitive( m_xBtnShadow3d->get_active() );
+ m_xMtrSlant->set_sensitive( m_xBtnShadow3d->get_active() );
+ bUpdatePreview = true;
+ }
+ // Other (no groups)
+ else
+ {
+ bUpdatePreview = true;
+ }
+
+ if( nSId > 0 )
+ {
+ SfxDispatcher* pDispatcher = LocalGetDispatcher(pBindings);
+ if (pDispatcher != nullptr)
+ {
+ SfxBoolItem aItem( nSId, true );
+ pDispatcher->ExecuteList(nSId,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
+ }
+ }
+ else if( bUpdatePreview )
+ UpdatePreview();
+}
+
+IMPL_LINK( Svx3DWin, ClickColorHdl, weld::Button&, rBtn, void)
+{
+ SvColorDialog aColorDlg;
+ ColorListBox* pLb;
+
+ if( &rBtn == m_xBtnLightColor.get() )
+ pLb = GetCLbByButton();
+ else if( &rBtn == m_xBtnAmbientColor.get() )
+ pLb = m_xLbAmbientlight.get();
+ else if( &rBtn == m_xBtnMatColor.get() )
+ pLb = m_xLbMatColor.get();
+ else if( &rBtn == m_xBtnEmissionColor.get() )
+ pLb = m_xLbMatEmission.get();
+ else // if( &rBtn == m_xBtnSpecularColor.get() )
+ pLb = m_xLbMatSpecular.get();
+
+ Color aColor = pLb->GetSelectEntryColor();
+
+ aColorDlg.SetColor( aColor );
+ if( aColorDlg.Execute(GetFrameWeld()) == RET_OK )
+ {
+ aColor = aColorDlg.GetColor();
+ LBSelectColor(pLb, aColor);
+ SelectColorHdl(*pLb);
+ }
+}
+
+IMPL_LINK( Svx3DWin, SelectHdl, weld::ComboBox&, rListBox, void )
+{
+ bool bUpdatePreview = false;
+
+ // Material
+ if (&rListBox == m_xLbMatFavorites.get())
+ {
+ Color aColObj( COL_WHITE );
+ Color aColEmis( COL_BLACK );
+ Color aColSpec( COL_WHITE );
+ sal_uInt16 nSpecIntens = 20;
+
+ switch( m_xLbMatFavorites->get_active() )
+ {
+ case 1: // Metall
+ {
+ aColObj = Color(230,230,255);
+ aColEmis = Color(10,10,30);
+ aColSpec = Color(200,200,200);
+ nSpecIntens = 20;
+ }
+ break;
+
+ case 2: // Gold
+ {
+ aColObj = Color(230,255,0);
+ aColEmis = Color(51,0,0);
+ aColSpec = Color(255,255,240);
+ nSpecIntens = 20;
+ }
+ break;
+
+ case 3: // Chrome
+ {
+ aColObj = Color(36,117,153);
+ aColEmis = Color(18,30,51);
+ aColSpec = Color(230,230,255);
+ nSpecIntens = 2;
+ }
+ break;
+
+ case 4: // Plastic
+ {
+ aColObj = Color(255,48,57);
+ aColEmis = Color(35,0,0);
+ aColSpec = Color(179,202,204);
+ nSpecIntens = 60;
+ }
+ break;
+
+ case 5: // Wood
+ {
+ aColObj = Color(153,71,1);
+ aColEmis = Color(21,22,0);
+ aColSpec = Color(255,255,153);
+ nSpecIntens = 75;
+ }
+ break;
+ }
+ LBSelectColor( m_xLbMatColor.get(), aColObj );
+ LBSelectColor( m_xLbMatEmission.get(), aColEmis );
+ LBSelectColor( m_xLbMatSpecular.get(), aColSpec );
+ m_xMtrMatSpecularIntensity->set_value(nSpecIntens, FieldUnit::PERCENT);
+
+ bUpdatePreview = true;
+ }
+ else if (&rListBox == m_xLbShademode.get())
+ bUpdatePreview = true;
+
+ if( bUpdatePreview )
+ UpdatePreview();
+}
+
+IMPL_LINK( Svx3DWin, SelectColorHdl, ColorListBox&, rListBox, void )
+{
+ bool bUpdatePreview = false;
+
+ if( &rListBox == m_xLbMatColor.get() ||
+ &rListBox == m_xLbMatEmission.get() ||
+ &rListBox == m_xLbMatSpecular.get() )
+ {
+ m_xLbMatFavorites->set_active( 0 );
+ bUpdatePreview = true;
+ }
+ // Lighting
+ else if( &rListBox == m_xLbAmbientlight.get() )
+ {
+ bUpdatePreview = true;
+ }
+ else if( &rListBox == m_xLbLight1.get() ||
+ &rListBox == m_xLbLight2.get() ||
+ &rListBox == m_xLbLight3.get() ||
+ &rListBox == m_xLbLight4.get() ||
+ &rListBox == m_xLbLight5.get() ||
+ &rListBox == m_xLbLight6.get() ||
+ &rListBox == m_xLbLight7.get() ||
+ &rListBox == m_xLbLight8.get() )
+ {
+ bUpdatePreview = true;
+ }
+
+ if( bUpdatePreview )
+ UpdatePreview();
+}
+
+IMPL_LINK_NOARG( Svx3DWin, ModifyMetricHdl, weld::MetricSpinButton&, void )
+{
+ UpdatePreview();
+}
+
+IMPL_LINK_NOARG( Svx3DWin, ModifySpinHdl, weld::SpinButton&, void )
+{
+ UpdatePreview();
+}
+
+void Svx3DWin::ClickLight(const LightButton& rBtn)
+{
+ sal_uInt16 nLightSource = GetLightSource( &rBtn );
+ ColorListBox* pLb = GetCLbByButton( &rBtn );
+ Color aColor( pLb->GetSelectEntryColor() );
+ SfxItemSet aLightItemSet(m_xCtlLightPreview->GetSvx3DLightControl().Get3DAttributes());
+ const bool bOnOff(rBtn.isLightOn());
+
+ switch(nLightSource)
+ {
+ case 0: aLightItemSet.Put(makeSvx3DLightcolor1Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff1Item(bOnOff)); break;
+ case 1: aLightItemSet.Put(makeSvx3DLightcolor2Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff2Item(bOnOff)); break;
+ case 2: aLightItemSet.Put(makeSvx3DLightcolor3Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff3Item(bOnOff)); break;
+ case 3: aLightItemSet.Put(makeSvx3DLightcolor4Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff4Item(bOnOff)); break;
+ case 4: aLightItemSet.Put(makeSvx3DLightcolor5Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff5Item(bOnOff)); break;
+ case 5: aLightItemSet.Put(makeSvx3DLightcolor6Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff6Item(bOnOff)); break;
+ case 6: aLightItemSet.Put(makeSvx3DLightcolor7Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff7Item(bOnOff)); break;
+ default:
+ case 7: aLightItemSet.Put(makeSvx3DLightcolor8Item(aColor)); aLightItemSet.Put(makeSvx3DLightOnOff8Item(bOnOff)); break;
+ }
+
+ m_xCtlLightPreview->GetSvx3DLightControl().Set3DAttributes(aLightItemSet);
+ m_xCtlLightPreview->GetSvx3DLightControl().SelectLight(nLightSource);
+ m_xCtlLightPreview->CheckSelection();
+}
+
+IMPL_LINK_NOARG(Svx3DWin, ChangeSelectionCallbackHdl, SvxLightCtl3D*, void)
+{
+ const sal_uInt32 nLight(m_xCtlLightPreview->GetSvx3DLightControl().GetSelectedLight());
+ weld::Button* pBtn = nullptr;
+
+ switch( nLight )
+ {
+ case 0: pBtn = m_xBtnLight1->get_widget(); break;
+ case 1: pBtn = m_xBtnLight2->get_widget(); break;
+ case 2: pBtn = m_xBtnLight3->get_widget(); break;
+ case 3: pBtn = m_xBtnLight4->get_widget(); break;
+ case 4: pBtn = m_xBtnLight5->get_widget(); break;
+ case 5: pBtn = m_xBtnLight6->get_widget(); break;
+ case 6: pBtn = m_xBtnLight7->get_widget(); break;
+ case 7: pBtn = m_xBtnLight8->get_widget(); break;
+ default: break;
+ }
+
+ if (pBtn)
+ ClickHdl(*pBtn);
+ else
+ {
+ // Status: No lamp selected
+ if( m_xBtnLight1->get_active() )
+ {
+ m_xBtnLight1->set_active( false );
+ m_xLbLight1->set_sensitive( false );
+ }
+ else if( m_xBtnLight2->get_active() )
+ {
+ m_xBtnLight2->set_active( false );
+ m_xLbLight2->set_sensitive( false );
+ }
+ else if( m_xBtnLight3->get_active() )
+ {
+ m_xBtnLight3->set_active( false );
+ m_xLbLight3->set_sensitive( false );
+ }
+ else if( m_xBtnLight4->get_active() )
+ {
+ m_xBtnLight4->set_active( false );
+ m_xLbLight4->set_sensitive( false );
+ }
+ else if( m_xBtnLight5->get_active() )
+ {
+ m_xBtnLight5->set_active( false );
+ m_xLbLight5->set_sensitive( false );
+ }
+ else if( m_xBtnLight6->get_active() )
+ {
+ m_xBtnLight6->set_active( false );
+ m_xLbLight6->set_sensitive( false );
+ }
+ else if( m_xBtnLight7->get_active() )
+ {
+ m_xBtnLight7->set_active( false );
+ m_xLbLight7->set_sensitive( false );
+ }
+ else if( m_xBtnLight8->get_active() )
+ {
+ m_xBtnLight8->set_active( false );
+ m_xLbLight8->set_sensitive( false );
+ }
+ m_xBtnLightColor->set_sensitive( false );
+ }
+}
+
+namespace
+{
+ OUString lcl_makeColorName(const Color& rColor)
+ {
+ OUString aStr = SvxResId(RID_SVXFLOAT3D_FIX_R) +
+ OUString::number(rColor.GetRed()) +
+ " " +
+ SvxResId(RID_SVXFLOAT3D_FIX_G) +
+ OUString::number(rColor.GetGreen()) +
+ " " +
+ SvxResId(RID_SVXFLOAT3D_FIX_B) +
+ OUString::number(rColor.GetBlue());
+ return aStr;
+ }
+}
+
+// Method to ensure that the LB is also associated with a color
+void Svx3DWin::LBSelectColor( ColorListBox* pLb, const Color& rColor )
+{
+ pLb->SetNoSelection();
+ pLb->SelectEntry(std::make_pair(rColor, lcl_makeColorName(rColor)));
+}
+
+void Svx3DWin::UpdatePreview()
+{
+ if(!pModel)
+ {
+ pModel.reset(new FmFormModel());
+ }
+
+ // Get Itemset
+ SfxItemSet aSet( pModel->GetItemPool(), svl::Items<SDRATTR_START, SDRATTR_END>{});
+
+ // Get Attributes and set the preview
+ GetAttr( aSet );
+ m_xCtlPreview->Set3DAttributes( aSet );
+ m_xCtlLightPreview->GetSvx3DLightControl().Set3DAttributes( aSet );
+}
+
+
+// document is to be reloaded, destroy remembered ItemSet
+void Svx3DWin::DocumentReload()
+{
+ mpRemember2DAttributes.reset();
+}
+
+void Svx3DWin::InitColorLB()
+{
+ // First...
+ Color aColWhite( COL_WHITE );
+ Color aColBlack( COL_BLACK );
+ m_xLbLight1->SelectEntry( aColWhite );
+ m_xLbLight2->SelectEntry( aColWhite );
+ m_xLbLight3->SelectEntry( aColWhite );
+ m_xLbLight4->SelectEntry( aColWhite );
+ m_xLbLight5->SelectEntry( aColWhite );
+ m_xLbLight6->SelectEntry( aColWhite );
+ m_xLbLight7->SelectEntry( aColWhite );
+ m_xLbLight8->SelectEntry( aColWhite );
+ m_xLbAmbientlight->SelectEntry( aColBlack );
+ m_xLbMatColor->SelectEntry( aColWhite );
+ m_xLbMatEmission->SelectEntry( aColBlack );
+ m_xLbMatSpecular->SelectEntry( aColWhite );
+}
+
+sal_uInt16 Svx3DWin::GetLightSource( const LightButton* pBtn )
+{
+ sal_uInt16 nLight = 8;
+
+ if (pBtn == m_xBtnLight1.get())
+ nLight = 0;
+ else if (pBtn == m_xBtnLight2.get())
+ nLight = 1;
+ else if( pBtn == m_xBtnLight3.get() )
+ nLight = 2;
+ else if( pBtn == m_xBtnLight4.get() )
+ nLight = 3;
+ else if( pBtn == m_xBtnLight5.get() )
+ nLight = 4;
+ else if( pBtn == m_xBtnLight6.get() )
+ nLight = 5;
+ else if( pBtn == m_xBtnLight7.get() )
+ nLight = 6;
+ else if( pBtn == m_xBtnLight8.get() )
+ nLight = 7;
+
+ return nLight;
+};
+
+ColorListBox* Svx3DWin::GetCLbByButton( const LightButton* pBtn )
+{
+ ColorListBox* pLb = nullptr;
+
+ if( pBtn == nullptr )
+ {
+ if( m_xBtnLight1->get_active() )
+ pLb = m_xLbLight1.get();
+ else if( m_xBtnLight2->get_active() )
+ pLb = m_xLbLight2.get();
+ else if( m_xBtnLight3->get_active() )
+ pLb = m_xLbLight3.get();
+ else if( m_xBtnLight4->get_active() )
+ pLb = m_xLbLight4.get();
+ else if( m_xBtnLight5->get_active() )
+ pLb = m_xLbLight5.get();
+ else if( m_xBtnLight6->get_active() )
+ pLb = m_xLbLight6.get();
+ else if( m_xBtnLight7->get_active() )
+ pLb = m_xLbLight7.get();
+ else if( m_xBtnLight8->get_active() )
+ pLb = m_xLbLight8.get();
+ }
+ else
+ {
+ if( pBtn == m_xBtnLight1.get() )
+ pLb = m_xLbLight1.get();
+ else if (pBtn == m_xBtnLight2.get())
+ pLb = m_xLbLight2.get();
+ else if( pBtn == m_xBtnLight3.get() )
+ pLb = m_xLbLight3.get();
+ else if( pBtn == m_xBtnLight4.get() )
+ pLb = m_xLbLight4.get();
+ else if( pBtn == m_xBtnLight5.get() )
+ pLb = m_xLbLight5.get();
+ else if( pBtn == m_xBtnLight6.get() )
+ pLb = m_xLbLight6.get();
+ else if( pBtn == m_xBtnLight7.get() )
+ pLb = m_xLbLight7.get();
+ else if( pBtn == m_xBtnLight8.get() )
+ pLb = m_xLbLight8.get();
+ }
+ return pLb;
+};
+
+LightButton* Svx3DWin::GetLbByButton( const weld::Button* pBtn )
+{
+ LightButton* pLb = nullptr;
+
+ if( pBtn == m_xBtnLight1->get_widget() )
+ pLb = m_xBtnLight1.get();
+ else if (pBtn == m_xBtnLight2->get_widget() )
+ pLb = m_xBtnLight2.get();
+ else if( pBtn == m_xBtnLight3->get_widget() )
+ pLb = m_xBtnLight3.get();
+ else if( pBtn == m_xBtnLight4->get_widget() )
+ pLb = m_xBtnLight4.get();
+ else if( pBtn == m_xBtnLight5->get_widget() )
+ pLb = m_xBtnLight5.get();
+ else if( pBtn == m_xBtnLight6->get_widget() )
+ pLb = m_xBtnLight6.get();
+ else if( pBtn == m_xBtnLight7->get_widget() )
+ pLb = m_xBtnLight7.get();
+ else if( pBtn == m_xBtnLight8->get_widget() )
+ pLb = m_xBtnLight8.get();
+
+ return pLb;
+};
+
+// Derivation from SfxChildWindow as "containers" for effects
+Svx3DChildWindow::Svx3DChildWindow( vcl::Window* _pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo ) :
+ SfxChildWindow( _pParent, nId )
+{
+ VclPtr<Svx3DWin> pWin = VclPtr<Svx3DWin>::Create( pBindings, this, _pParent );
+ SetWindow(pWin);
+
+ pWin->Initialize( pInfo );
+}
+
+Svx3DCtrlItem::Svx3DCtrlItem( sal_uInt16 _nId,
+ SfxBindings* _pBindings) :
+ SfxControllerItem( _nId, *_pBindings )
+{
+}
+
+
+void Svx3DCtrlItem::StateChanged( sal_uInt16 /*nSId*/,
+ SfxItemState /*eState*/, const SfxPoolItem* /*pItem*/ )
+{
+}
+
+// ControllerItem for Status Slot SID_CONVERT_TO_3D
+
+SvxConvertTo3DItem::SvxConvertTo3DItem(sal_uInt16 _nId, SfxBindings* _pBindings)
+: SfxControllerItem(_nId, *_pBindings),
+ bState(false)
+{
+}
+
+void SvxConvertTo3DItem::StateChanged(sal_uInt16 /*_nId*/, SfxItemState eState, const SfxPoolItem* /*pState*/)
+{
+ bool bNewState = (eState != SfxItemState::DISABLED);
+ if(bNewState != bState)
+ {
+ bState = bNewState;
+ SfxDispatcher* pDispatcher = LocalGetDispatcher(&GetBindings());
+ if (pDispatcher != nullptr)
+ {
+ SfxBoolItem aItem( SID_3D_STATE, true );
+ pDispatcher->ExecuteList(SID_3D_STATE,
+ SfxCallMode::ASYNCHRON|SfxCallMode::RECORD, { &aItem });
+ }
+ }
+}
+
+LightButton::LightButton(std::unique_ptr<weld::ToggleButton> xButton)
+ : m_xButton(std::move(xButton))
+ , m_bLightOn(false)
+ , m_bButtonPrevActive(false)
+{
+ m_xButton->set_from_icon_name(RID_SVXBMP_LAMP_OFF);
+}
+
+void LightButton::switchLightOn(bool bOn)
+{
+ if (m_bLightOn == bOn)
+ return;
+ m_bLightOn = bOn;
+ if (m_bLightOn)
+ m_xButton->set_from_icon_name(RID_SVXBMP_LAMP_ON);
+ else
+ m_xButton->set_from_icon_name(RID_SVXBMP_LAMP_OFF);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/helperhittest3d.cxx b/svx/source/engine3d/helperhittest3d.cxx
new file mode 100644
index 000000000..f553b4d0e
--- /dev/null
+++ b/svx/source/engine3d/helperhittest3d.cxx
@@ -0,0 +1,277 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/helperhittest3d.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/svditer.hxx>
+#include <drawinglayer/processor3d/cutfindprocessor3d.hxx>
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <com/sun/star/uno/Sequence.h>
+
+
+using namespace com::sun::star;
+
+namespace {
+
+class ImplPairDephAndObject
+{
+private:
+ const E3dCompoundObject* mpObject;
+ double mfDepth;
+
+public:
+ ImplPairDephAndObject(const E3dCompoundObject* pObject, double fDepth)
+ : mpObject(pObject),
+ mfDepth(fDepth)
+ {}
+
+ // for ::std::sort
+ bool operator<(const ImplPairDephAndObject& rComp) const
+ {
+ return (mfDepth < rComp.mfDepth);
+ }
+
+ // data read access
+ const E3dCompoundObject* getObject() const { return mpObject; }
+};
+
+}
+
+static void getAllHit3DObjectWithRelativePoint(
+ const basegfx::B3DPoint& rFront,
+ const basegfx::B3DPoint& rBack,
+ const E3dCompoundObject& rObject,
+ const drawinglayer::geometry::ViewInformation3D& rObjectViewInformation3D,
+ ::std::vector< basegfx::B3DPoint >& o_rResult,
+ bool bAnyHit)
+{
+ o_rResult.clear();
+
+ if(!rFront.equal(rBack))
+ {
+ // rObject is an E3dCompoundObject, so it cannot be a scene (which is an E3dObject)
+ const sdr::contact::ViewContactOfE3d& rVCObject = static_cast< sdr::contact::ViewContactOfE3d& >(rObject.GetViewContact());
+ const drawinglayer::primitive3d::Primitive3DContainer aPrimitives(rVCObject.getViewIndependentPrimitive3DContainer());
+
+ if(!aPrimitives.empty())
+ {
+ // make BoundVolume empty and overlapping test for speedup
+ const basegfx::B3DRange aObjectRange(aPrimitives.getB3DRange(rObjectViewInformation3D));
+
+ if(!aObjectRange.isEmpty())
+ {
+ const basegfx::B3DRange aFrontBackRange(rFront, rBack);
+
+ if(aObjectRange.overlaps(aFrontBackRange))
+ {
+ // bound volumes hit, geometric cut tests needed
+ drawinglayer::processor3d::CutFindProcessor aCutFindProcessor(rObjectViewInformation3D, rFront, rBack, bAnyHit);
+ aCutFindProcessor.process(aPrimitives);
+ o_rResult = aCutFindProcessor.getCutPoints();
+ }
+ }
+ }
+ }
+}
+
+
+E3dScene* fillViewInformation3DForCompoundObject(drawinglayer::geometry::ViewInformation3D& o_rViewInformation3D, const E3dCompoundObject& rCandidate)
+{
+ // Search for root scene (outmost scene) of the 3d object since e.g. in chart, multiple scenes may
+ // be placed between object and outmost scene. On that search, remember the in-between scene's
+ // transformation for the correct complete ObjectTransformation. For historical reasons, the
+ // root scene's own object transformation is part of the scene's ViewTransformation, o do not
+ // add it. For more details, see ViewContactOfE3dScene::createViewInformation3D.
+ E3dScene* pParentScene(rCandidate.getParentE3dSceneFromE3dObject());
+ E3dScene* pRootScene(nullptr);
+ basegfx::B3DHomMatrix aInBetweenSceneMatrix;
+
+ while(pParentScene)
+ {
+ E3dScene* pParentParentScene(pParentScene->getParentE3dSceneFromE3dObject());
+
+ if(pParentParentScene)
+ {
+ // pParentScene is an in-between scene
+ aInBetweenSceneMatrix = pParentScene->GetTransform() * aInBetweenSceneMatrix;
+ }
+ else
+ {
+ // pParentScene is the root scene
+ pRootScene = pParentScene;
+ }
+
+ pParentScene = pParentParentScene;
+ }
+
+ if(pRootScene)
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+
+ if(aInBetweenSceneMatrix.isIdentity())
+ {
+ o_rViewInformation3D = rVCScene.getViewInformation3D();
+ }
+ else
+ {
+ // build new ViewInformation containing all transforms for the candidate
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+
+ o_rViewInformation3D = drawinglayer::geometry::ViewInformation3D(
+ aViewInfo3D.getObjectTransformation() * aInBetweenSceneMatrix,
+ aViewInfo3D.getOrientation(),
+ aViewInfo3D.getProjection(),
+ aViewInfo3D.getDeviceToView(),
+ aViewInfo3D.getViewTime(),
+ aViewInfo3D.getExtendedInformationSequence());
+ }
+ }
+ else
+ {
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ o_rViewInformation3D = drawinglayer::geometry::ViewInformation3D(aEmptyParameters);
+ }
+
+ return pRootScene;
+}
+
+
+void getAllHit3DObjectsSortedFrontToBack(
+ const basegfx::B2DPoint& rPoint,
+ const E3dScene& rScene,
+ ::std::vector< const E3dCompoundObject* >& o_rResult)
+{
+ o_rResult.clear();
+ SdrObjList* pList = rScene.GetSubList();
+
+ if(nullptr != pList && 0 != pList->GetObjCount())
+ {
+ // prepare relative HitPoint. To do so, get the VC of the 3DScene and from there
+ // the Scene's 2D transformation. Multiplying with the inverse transformation
+ // will create a point relative to the 3D scene as unit-2d-object
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(rScene.GetViewContact());
+ basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
+ aInverseSceneTransform.invert();
+ const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * rPoint);
+
+ // check if test point is inside scene's area at all
+ if(aRelativePoint.getX() >= 0.0 && aRelativePoint.getX() <= 1.0 && aRelativePoint.getY() >= 0.0 && aRelativePoint.getY() <= 1.0)
+ {
+ SdrObjListIter aIterator(pList, SdrIterMode::DeepNoGroups);
+ ::std::vector< ImplPairDephAndObject > aDepthAndObjectResults;
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+
+ while(aIterator.IsMore())
+ {
+ const E3dCompoundObject* pCandidate = dynamic_cast< const E3dCompoundObject* >(aIterator.Next());
+
+ if(pCandidate)
+ {
+ fillViewInformation3DForCompoundObject(aViewInfo3D, *pCandidate);
+
+ // create HitPoint Front and Back, transform to object coordinates
+ basegfx::B3DHomMatrix aViewToObject(aViewInfo3D.getObjectToView());
+ aViewToObject.invert();
+ const basegfx::B3DPoint aFront(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 0.0));
+ const basegfx::B3DPoint aBack(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 1.0));
+
+ if(!aFront.equal(aBack))
+ {
+ // get all hit points with object
+ ::std::vector< basegfx::B3DPoint > aHitsWithObject;
+ getAllHit3DObjectWithRelativePoint(aFront, aBack, *pCandidate, aViewInfo3D, aHitsWithObject, false);
+
+ for(const basegfx::B3DPoint & a : aHitsWithObject)
+ {
+ const basegfx::B3DPoint aPointInViewCoordinates(aViewInfo3D.getObjectToView() * a);
+ aDepthAndObjectResults.emplace_back(pCandidate, aPointInViewCoordinates.getZ());
+ }
+ }
+ }
+ }
+
+ // fill nRetval
+ const sal_uInt32 nCount(aDepthAndObjectResults.size());
+
+ if(nCount)
+ {
+ // sort aDepthAndObjectResults by depth
+ ::std::sort(aDepthAndObjectResults.begin(), aDepthAndObjectResults.end());
+
+ // copy SdrObject pointers to return result set
+ for(const auto& rResult : aDepthAndObjectResults)
+ {
+ o_rResult.push_back(rResult.getObject());
+ }
+ }
+ }
+ }
+}
+
+
+bool checkHitSingle3DObject(
+ const basegfx::B2DPoint& rPoint,
+ const E3dCompoundObject& rCandidate)
+{
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+ E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, rCandidate);
+
+ if(pRootScene)
+ {
+ // prepare relative HitPoint. To do so, get the VC of the 3DScene and from there
+ // the Scene's 2D transformation. Multiplying with the inverse transformation
+ // will create a point relative to the 3D scene as unit-2d-object
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+ basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
+ aInverseSceneTransform.invert();
+ const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * rPoint);
+
+ // check if test point is inside scene's area at all
+ if(aRelativePoint.getX() >= 0.0 && aRelativePoint.getX() <= 1.0 && aRelativePoint.getY() >= 0.0 && aRelativePoint.getY() <= 1.0)
+ {
+ // create HitPoint Front and Back, transform to object coordinates
+ basegfx::B3DHomMatrix aViewToObject(aViewInfo3D.getObjectToView());
+ aViewToObject.invert();
+ const basegfx::B3DPoint aFront(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 0.0));
+ const basegfx::B3DPoint aBack(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 1.0));
+
+ if(!aFront.equal(aBack))
+ {
+ // get all hit points with object
+ ::std::vector< basegfx::B3DPoint > aHitsWithObject;
+ getAllHit3DObjectWithRelativePoint(aFront, aBack, rCandidate, aViewInfo3D, aHitsWithObject, true);
+
+ if(!aHitsWithObject.empty())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/helperminimaldepth3d.cxx b/svx/source/engine3d/helperminimaldepth3d.cxx
new file mode 100644
index 000000000..cfcc2c7d1
--- /dev/null
+++ b/svx/source/engine3d/helperminimaldepth3d.cxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "helperminimaldepth3d.hxx"
+#include <drawinglayer/processor3d/baseprocessor3d.hxx>
+#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
+#include <drawinglayer/primitive3d/transformprimitive3d.hxx>
+#include <drawinglayer/primitive3d/polygonprimitive3d.hxx>
+#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx>
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/scene3d.hxx>
+
+
+namespace drawinglayer::processor3d
+{
+ namespace {
+
+ class MinimalDephInViewExtractor : public BaseProcessor3D
+ {
+ private:
+ // the value which will be fetched as result
+ double mfMinimalDepth;
+
+ // as tooling, the process() implementation takes over API handling and calls this
+ // virtual render method when the primitive implementation is BasePrimitive3D-based.
+ virtual void processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate) override;
+
+ public:
+ explicit MinimalDephInViewExtractor(const geometry::ViewInformation3D& rViewInformation)
+ : BaseProcessor3D(rViewInformation),
+ mfMinimalDepth(DBL_MAX)
+ {}
+
+ // data access
+ double getMinimalDepth() const { return mfMinimalDepth; }
+ };
+
+ }
+
+ void MinimalDephInViewExtractor::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate)
+ {
+ // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch
+ switch(rCandidate.getPrimitive3DID())
+ {
+ case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D :
+ {
+ // transform group. Remember current transformations
+ const primitive3d::TransformPrimitive3D& rPrimitive = static_cast< const primitive3d::TransformPrimitive3D& >(rCandidate);
+ const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D());
+
+ // create new transformation; add new object transform from right side
+ const geometry::ViewInformation3D aNewViewInformation3D(
+ aLastViewInformation3D.getObjectTransformation() * rPrimitive.getTransformation(),
+ aLastViewInformation3D.getOrientation(),
+ aLastViewInformation3D.getProjection(),
+ aLastViewInformation3D.getDeviceToView(),
+ aLastViewInformation3D.getViewTime(),
+ aLastViewInformation3D.getExtendedInformationSequence());
+ updateViewInformation(aNewViewInformation3D);
+
+ // let break down
+ process(rPrimitive.getChildren());
+
+ // restore transformations
+ updateViewInformation(aLastViewInformation3D);
+ break;
+ }
+ case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D :
+ {
+ // PolygonHairlinePrimitive3D
+ const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rCandidate);
+ const basegfx::B3DPolygon& rPolygon = rPrimitive.getB3DPolygon();
+ const sal_uInt32 nCount(rPolygon.count());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const basegfx::B3DPoint aPointInView(getViewInformation3D().getObjectToView() * rPolygon.getB3DPoint(a));
+
+ if(aPointInView.getZ() < mfMinimalDepth)
+ {
+ mfMinimalDepth = aPointInView.getZ();
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D :
+ {
+ // PolyPolygonMaterialPrimitive3D
+ const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rCandidate);
+ const basegfx::B3DPolyPolygon& rPolyPolygon = rPrimitive.getB3DPolyPolygon();
+ const sal_uInt32 nPolyCount(rPolyPolygon.count());
+
+ for(sal_uInt32 a(0); a < nPolyCount; a++)
+ {
+ const basegfx::B3DPolygon& aPolygon(rPolyPolygon.getB3DPolygon(a));
+ const sal_uInt32 nCount(aPolygon.count());
+
+ for(sal_uInt32 b(0); b < nCount; b++)
+ {
+ const basegfx::B3DPoint aPointInView(getViewInformation3D().getObjectToView() * aPolygon.getB3DPoint(b));
+
+ if(aPointInView.getZ() < mfMinimalDepth)
+ {
+ mfMinimalDepth = aPointInView.getZ();
+ }
+ }
+ }
+
+ break;
+ }
+ default :
+ {
+ // process recursively
+ process(rCandidate.get3DDecomposition(getViewInformation3D()));
+ break;
+ }
+ }
+ }
+} // end of namespace
+
+
+// changed to create values using VCs, Primitive3DContainer and ViewInformation3D to allow
+// removal of old 3D bucket geometry. There is one slight difference in the result, it's
+// in [0.0 .. 1.0] for Z-Depth since the scaling of the scene as 2D object is no longer
+// part of the 3D transformations. This could be added since the ViewContactOfE3dScene is
+// given, but is not needed since the permutation of the depth values needs only be correct
+// relative to each other
+
+double getMinimalDepthInViewCoordinates(const E3dCompoundObject& rObject)
+{
+ // this is an E3dCompoundObject, so it cannot be a scene (which is an E3dObject).
+ // Get primitive sequence using VC
+ const sdr::contact::ViewContactOfE3d& rVCObject = static_cast< sdr::contact::ViewContactOfE3d& >(rObject.GetViewContact());
+ const drawinglayer::primitive3d::Primitive3DContainer aPrimitives = rVCObject.getViewIndependentPrimitive3DContainer();
+ double fRetval(DBL_MAX);
+
+ if(!aPrimitives.empty())
+ {
+ const E3dScene* pScene(rObject.getRootE3dSceneFromE3dObject());
+
+ if(pScene)
+ {
+ // get ViewInformation3D from scene using VC
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+
+ // the scene's object transformation is already part of aViewInfo3D.getObjectTransformation()
+ // for historical reasons (see ViewContactOfE3dScene::createViewInformation3D for more info)
+ // and the object's transform is part of aPrimitives (and taken into account when decomposing
+ // to PolygonHairlinePrimitive3D and PolyPolygonMaterialPrimitive3D). The missing part may be
+ // some Scene SdrObjects lying in-between which may need to be added. This is e.g. used in chart,
+ // and generally allowed in 3d scenes and their 3d object hierarchy
+ basegfx::B3DHomMatrix aInBetweenSceneMatrix;
+ E3dScene* pParentScene(rObject.getParentE3dSceneFromE3dObject());
+
+ while(pParentScene && pParentScene != pScene)
+ {
+ aInBetweenSceneMatrix = pParentScene->GetTransform() * aInBetweenSceneMatrix;
+ pParentScene = pParentScene->getParentE3dSceneFromE3dObject();
+ }
+
+ // build new ViewInformation containing all transforms
+ const drawinglayer::geometry::ViewInformation3D aNewViewInformation3D(
+ aViewInfo3D.getObjectTransformation() * aInBetweenSceneMatrix,
+ aViewInfo3D.getOrientation(),
+ aViewInfo3D.getProjection(),
+ aViewInfo3D.getDeviceToView(),
+ aViewInfo3D.getViewTime(),
+ aViewInfo3D.getExtendedInformationSequence());
+
+ // create extractor helper, process geometry and get return value
+ drawinglayer::processor3d::MinimalDephInViewExtractor aExtractor(aNewViewInformation3D);
+ aExtractor.process(aPrimitives);
+ fRetval = aExtractor.getMinimalDepth();
+ }
+ }
+
+ return fRetval;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/helperminimaldepth3d.hxx b/svx/source/engine3d/helperminimaldepth3d.hxx
new file mode 100644
index 000000000..15da40d09
--- /dev/null
+++ b/svx/source/engine3d/helperminimaldepth3d.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVX_SOURCE_ENGINE3D_HELPERMINIMALDEPTH3D_HXX
+#define INCLUDED_SVX_SOURCE_ENGINE3D_HELPERMINIMALDEPTH3D_HXX
+
+
+// predefines
+
+class E3dCompoundObject;
+
+
+/** support extracting the minimal depth of a 3d object in its scene
+
+ @param rObject
+ The 3D Object from which the minimal depth needs to be calculated. The scene
+ is defined by the object already
+
+ @return
+ The minimal depth of this object in unified ViewCoordinates. This is the
+ Z-Coordinate of one object point in the range of [0.0 .. 1.0]. ViewCoordinates
+ means the transformations (esp. rotation) of the scene are taken into account
+
+*/
+// support extracting the minimal depth of a 3d object in its scene
+
+double getMinimalDepthInViewCoordinates(const E3dCompoundObject& rObject);
+
+
+#endif // INCLUDED_SVX_SOURCE_ENGINE3D_HELPERMINIMALDEPTH3D_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/lathe3d.cxx b/svx/source/engine3d/lathe3d.cxx
new file mode 100644
index 000000000..37060f96e
--- /dev/null
+++ b/svx/source/engine3d/lathe3d.cxx
@@ -0,0 +1,205 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/deflt3d.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/globl3d.hxx>
+#include <svx/lathe3d.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svx3ditems.hxx>
+#include <svx/xlineit0.hxx>
+#include <sdr/properties/e3dlatheproperties.hxx>
+#include <sdr/contact/viewcontactofe3dlathe.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <rtl/ustrbuf.hxx>
+
+
+// DrawContact section
+std::unique_ptr<sdr::contact::ViewContact> E3dLatheObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dLathe>(*this);
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dLatheObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dLatheProperties>(*this);
+}
+
+// Constructor from 3D polygon, scale is the conversion factor for the coordinates
+E3dLatheObj::E3dLatheObj(
+ SdrModel& rSdrModel,
+ const E3dDefaultAttributes& rDefault,
+ const basegfx::B2DPolyPolygon& rPoly2D)
+: E3dCompoundObject(rSdrModel),
+ maPolyPoly2D(rPoly2D)
+{
+ // since the old class PolyPolygon3D did mirror the given PolyPolygons in Y, do the same here
+ basegfx::B2DHomMatrix aMirrorY;
+ aMirrorY.scale(1.0, -1.0);
+ maPolyPoly2D.transform(aMirrorY);
+
+ // Set Defaults
+ SetDefaultAttributes(rDefault);
+
+ // Superfluous items removed, in particular to prevent duplicate
+ // start and end points
+ maPolyPoly2D.removeDoublePoints();
+
+ if(maPolyPoly2D.count())
+ {
+ const basegfx::B2DPolygon rPoly(maPolyPoly2D.getB2DPolygon(0));
+ sal_uInt32 nSegCnt(rPoly.count());
+
+ if(nSegCnt && !rPoly.isClosed())
+ {
+ nSegCnt -= 1;
+ }
+
+ GetProperties().SetObjectItemDirect(makeSvx3DVerticalSegmentsItem(nSegCnt));
+ }
+}
+
+E3dLatheObj::E3dLatheObj(SdrModel& rSdrModel)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set Defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+}
+
+E3dLatheObj::~E3dLatheObj()
+{
+}
+
+void E3dLatheObj::SetDefaultAttributes(const E3dDefaultAttributes& rDefault)
+{
+ GetProperties().SetObjectItemDirect(Svx3DSmoothNormalsItem(rDefault.GetDefaultLatheSmoothed()));
+ GetProperties().SetObjectItemDirect(Svx3DSmoothLidsItem(rDefault.GetDefaultLatheSmoothFrontBack()));
+ GetProperties().SetObjectItemDirect(Svx3DCharacterModeItem(rDefault.GetDefaultLatheCharacterMode()));
+ GetProperties().SetObjectItemDirect(Svx3DCloseFrontItem(rDefault.GetDefaultLatheCloseFront()));
+ GetProperties().SetObjectItemDirect(Svx3DCloseBackItem(rDefault.GetDefaultLatheCloseBack()));
+}
+
+sal_uInt16 E3dLatheObj::GetObjIdentifier() const
+{
+ return E3D_LATHEOBJ_ID;
+}
+
+E3dLatheObj* E3dLatheObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return CloneHelper< E3dLatheObj >(rTargetModel);
+}
+
+E3dLatheObj& E3dLatheObj::operator=(const E3dLatheObj& rObj)
+{
+ if( this == &rObj )
+ return *this;
+ E3dCompoundObject::operator=(rObj);
+
+ maPolyPoly2D = rObj.maPolyPoly2D;
+
+ return *this;
+}
+
+// Convert the object to group object consisting of n polygons
+
+SdrObjectUniquePtr E3dLatheObj::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
+{
+ return nullptr;
+}
+
+// Set Local parameters set to re-create geometry
+
+void E3dLatheObj::SetPolyPoly2D(const basegfx::B2DPolyPolygon& rNew)
+{
+ if(maPolyPoly2D != rNew)
+ {
+ maPolyPoly2D = rNew;
+ maPolyPoly2D.removeDoublePoints();
+
+ if(maPolyPoly2D.count())
+ {
+ const basegfx::B2DPolygon rPoly(maPolyPoly2D.getB2DPolygon(0));
+ sal_uInt32 nSegCnt(rPoly.count());
+
+ if(nSegCnt && !rPoly.isClosed())
+ {
+ nSegCnt -= 1;
+ }
+
+ GetProperties().SetObjectItemDirect(makeSvx3DVerticalSegmentsItem(nSegCnt));
+ }
+
+ ActionChanged();
+ }
+}
+
+// Get the name of the object (singular)
+
+OUString E3dLatheObj::TakeObjNameSingul() const
+{
+ OUStringBuffer sName(SvxResId(STR_ObjNameSingulLathe3d));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName.append(' ');
+ sName.append('\'');
+ sName.append(aName);
+ sName.append('\'');
+ }
+ return sName.makeStringAndClear();
+}
+
+// Get the name of the object (plural)
+
+OUString E3dLatheObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralLathe3d);
+}
+
+bool E3dLatheObj::IsBreakObjPossible()
+{
+ return true;
+}
+
+std::unique_ptr<SdrAttrObj,SdrObjectFreeOp> E3dLatheObj::GetBreakObj()
+{
+ // create PathObj
+ basegfx::B3DPolyPolygon aLathePoly3D(basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon(maPolyPoly2D));
+ basegfx::B2DPolyPolygon aTransPoly(TransformToScreenCoor(aLathePoly3D));
+ std::unique_ptr<SdrPathObj,SdrObjectFreeOp> pPathObj(new SdrPathObj(getSdrModelFromSdrObject(), OBJ_PLIN, aTransPoly));
+
+ // Set Attribute
+ SfxItemSet aSet(GetObjectItemSet());
+
+ // Enable lines to guarantee that the object becomes visible
+ aSet.Put(XLineStyleItem(css::drawing::LineStyle_SOLID));
+
+ pPathObj->SetMergedItemSet(aSet);
+
+ return std::unique_ptr<SdrAttrObj,SdrObjectFreeOp>(pPathObj.release());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/obj3d.cxx b/svx/source/engine3d/obj3d.cxx
new file mode 100644
index 000000000..eca597bb4
--- /dev/null
+++ b/svx/source/engine3d/obj3d.cxx
@@ -0,0 +1,625 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <o3tl/numeric.hxx>
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/globl3d.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/obj3d.hxx>
+#include <sdr/properties/e3dproperties.hxx>
+#include <sdr/properties/e3dcompoundproperties.hxx>
+#include <basegfx/polygon/b3dpolypolygontools.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/helperhittest3d.hxx>
+#include <sdr/contact/viewcontactofe3d.hxx>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+#include <com/sun/star/uno/Sequence.h>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/e3dsceneupdater.hxx>
+#include <rtl/ustrbuf.hxx>
+
+using namespace com::sun::star;
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dObject::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dProperties>(*this);
+}
+
+E3dObject::E3dObject(SdrModel& rSdrModel)
+: SdrAttrObj(rSdrModel),
+ maLocalBoundVol(),
+ maTransformation(),
+ maFullTransform(),
+ mbTfHasChanged(true),
+ mbIsSelected(false)
+{
+ bIs3DObj = true;
+ bClosedObj = true;
+}
+
+E3dObject::~E3dObject()
+{
+}
+
+void E3dObject::SetSelected(bool bNew)
+{
+ if(mbIsSelected != bNew)
+ {
+ mbIsSelected = bNew;
+ }
+}
+
+// Break, default implementations
+bool E3dObject::IsBreakObjPossible()
+{
+ return false;
+}
+
+std::unique_ptr<SdrAttrObj,SdrObjectFreeOp> E3dObject::GetBreakObj()
+{
+ return nullptr;
+}
+
+SdrInventor E3dObject::GetObjInventor() const
+{
+ return SdrInventor::E3d;
+}
+
+sal_uInt16 E3dObject::GetObjIdentifier() const
+{
+ return E3D_OBJECT_ID;
+}
+
+// Determine the capabilities of the object
+void E3dObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ rInfo.bResizeFreeAllowed = true;
+ rInfo.bResizePropAllowed = true;
+ rInfo.bRotateFreeAllowed = true;
+ rInfo.bRotate90Allowed = true;
+ rInfo.bMirrorFreeAllowed = false;
+ rInfo.bMirror45Allowed = false;
+ rInfo.bMirror90Allowed = false;
+ rInfo.bShearAllowed = false;
+ rInfo.bEdgeRadiusAllowed = false;
+ rInfo.bCanConvToPath = false;
+
+ // no transparence for 3d objects
+ rInfo.bTransparenceAllowed = false;
+
+ // Convert 3D objects in a group of polygons:
+ // At first not only possible, because the creation of a group of
+ // 2D polygons would be required which need to be sorted by depth,
+ // ie at intersections be cut relative to each other. Also the texture
+ // coordinates were an unsolved problem.
+ rInfo.bCanConvToPoly = false;
+ rInfo.bCanConvToContour = false;
+ rInfo.bCanConvToPathLineToArea = false;
+ rInfo.bCanConvToPolyLineToArea = false;
+}
+
+// resize object, used from old 2d interfaces, e.g. in Move/Scale dialog (F4)
+void E3dObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ // Movement in X, Y in the eye coordinate system
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr == pScene)
+ {
+ return;
+ }
+
+ // transform pos from 2D world to 3D eye
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ basegfx::B2DPoint aScaleCenter2D(static_cast<double>(rRef.X()), static_cast<double>(rRef.Y()));
+ basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
+
+ aInverseSceneTransform.invert();
+ aScaleCenter2D = aInverseSceneTransform * aScaleCenter2D;
+
+ basegfx::B3DPoint aScaleCenter3D(aScaleCenter2D.getX(), aScaleCenter2D.getY(), 0.5);
+ basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
+
+ aInverseViewToEye.invert();
+ aScaleCenter3D = aInverseViewToEye * aScaleCenter3D;
+
+ // Get scale factors
+ double fScaleX(xFact);
+ double fScaleY(yFact);
+
+ // build transform
+ basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
+ aInverseOrientation.invert();
+ basegfx::B3DHomMatrix aFullTransform(GetFullTransform());
+ basegfx::B3DHomMatrix aTrans(aFullTransform);
+
+ aTrans *= aViewInfo3D.getOrientation();
+ aTrans.translate(-aScaleCenter3D.getX(), -aScaleCenter3D.getY(), -aScaleCenter3D.getZ());
+ aTrans.scale(fScaleX, fScaleY, 1.0);
+ aTrans.translate(aScaleCenter3D.getX(), aScaleCenter3D.getY(), aScaleCenter3D.getZ());
+ aTrans *= aInverseOrientation;
+ aFullTransform.invert();
+ aTrans *= aFullTransform;
+
+ // Apply
+ basegfx::B3DHomMatrix aObjTrans(GetTransform());
+ aObjTrans *= aTrans;
+
+ E3DModifySceneSnapRectUpdater aUpdater(this);
+ SetTransform(aObjTrans);
+}
+
+// Move object in 2D is needed when using cursor keys
+void E3dObject::NbcMove(const Size& rSize)
+{
+ // Movement in X, Y in the eye coordinate system
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr == pScene)
+ {
+ return;
+ }
+
+ //Dimensions of the scene in 3D and 2D for comparison
+ tools::Rectangle aRect = pScene->GetSnapRect();
+ basegfx::B3DHomMatrix aInvDispTransform;
+ E3dScene* pParent(getParentE3dSceneFromE3dObject());
+
+ if(nullptr != pParent)
+ {
+ aInvDispTransform = pParent->GetFullTransform();
+ aInvDispTransform.invert();
+ }
+
+ // BoundVolume from 3d world to 3d eye
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ basegfx::B3DRange aEyeVol(pScene->GetBoundVolume());
+ aEyeVol.transform(aViewInfo3D.getOrientation());
+
+ if ((aRect.GetWidth() == 0) || (aRect.GetHeight() == 0))
+ throw o3tl::divide_by_zero();
+
+ // build relative movement vector in eye coordinates
+ basegfx::B3DPoint aMove(
+ static_cast<double>(rSize.Width()) * aEyeVol.getWidth() / static_cast<double>(aRect.GetWidth()),
+ static_cast<double>(-rSize.Height()) * aEyeVol.getHeight() / static_cast<double>(aRect.GetHeight()),
+ 0.0);
+ basegfx::B3DPoint aPos(0.0, 0.0, 0.0);
+
+ // movement vector to local coordinates of objects' parent
+ basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
+ aInverseOrientation.invert();
+ basegfx::B3DHomMatrix aCompleteTrans(aInvDispTransform * aInverseOrientation);
+
+ aMove = aCompleteTrans * aMove;
+ aPos = aCompleteTrans * aPos;
+
+ // build transformation and apply
+ basegfx::B3DHomMatrix aTranslate;
+ aTranslate.translate(aMove.getX() - aPos.getX(), aMove.getY() - aPos.getY(), aMove.getZ() - aPos.getZ());
+
+ E3DModifySceneSnapRectUpdater aUpdater(pScene);
+ SetTransform(aTranslate * GetTransform());
+}
+
+void E3dObject::RecalcSnapRect()
+{
+ maSnapRect = tools::Rectangle();
+}
+
+// Inform parent of changes in the structure (eg by transformation), in this
+// process the object in which the change has occurred is returned.
+void E3dObject::StructureChanged()
+{
+ E3dScene* pParent(getParentE3dSceneFromE3dObject());
+
+ if(nullptr != pParent)
+ {
+ pParent->InvalidateBoundVolume();
+ pParent->StructureChanged();
+ }
+}
+
+E3dScene* E3dObject::getParentE3dSceneFromE3dObject() const
+{
+ return dynamic_cast< E3dScene* >(getParentSdrObjectFromSdrObject());
+}
+
+// Determine the top-level scene object
+E3dScene* E3dObject::getRootE3dSceneFromE3dObject() const
+{
+ E3dScene* pParent(getParentE3dSceneFromE3dObject());
+
+ if(nullptr != pParent)
+ {
+ return pParent->getRootE3dSceneFromE3dObject();
+ }
+
+ return nullptr;
+}
+
+// Calculate enclosed volume, including all child objects
+basegfx::B3DRange E3dObject::RecalcBoundVolume() const
+{
+ basegfx::B3DRange aRetval;
+ const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
+
+ if(pVCOfE3D)
+ {
+ // BoundVolume is without 3D object transformation, use correct sequence
+ const drawinglayer::primitive3d::Primitive3DContainer& xLocalSequence(pVCOfE3D->getVIP3DSWithoutObjectTransform());
+
+ if(!xLocalSequence.empty())
+ {
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ const drawinglayer::geometry::ViewInformation3D aLocalViewInformation3D(aEmptyParameters);
+
+ aRetval = xLocalSequence.getB3DRange(aLocalViewInformation3D);
+ }
+ }
+
+ return aRetval;
+}
+
+// Get enclosed volume and possibly recalculate it
+const basegfx::B3DRange& E3dObject::GetBoundVolume() const
+{
+ if(maLocalBoundVol.isEmpty())
+ {
+ const_cast< E3dObject* >(this)->maLocalBoundVol = RecalcBoundVolume();
+ }
+
+ return maLocalBoundVol;
+}
+
+void E3dObject::InvalidateBoundVolume()
+{
+ maLocalBoundVol.reset();
+}
+
+// Pass on the changes in transformation to all child objects
+void E3dObject::SetTransformChanged()
+{
+ InvalidateBoundVolume();
+ mbTfHasChanged = true;
+}
+
+// Define the hierarchical transformation over all Parents, store in
+// maFullTransform and return them
+const basegfx::B3DHomMatrix& E3dObject::GetFullTransform() const
+{
+ if(mbTfHasChanged)
+ {
+ basegfx::B3DHomMatrix aNewFullTransformation(maTransformation);
+ E3dScene* pParent(getParentE3dSceneFromE3dObject());
+
+ if(nullptr != pParent)
+ {
+ aNewFullTransformation = pParent->GetFullTransform() * aNewFullTransformation;
+ }
+
+ const_cast< E3dObject* >(this)->maFullTransform = aNewFullTransformation;
+ const_cast< E3dObject* >(this)->mbTfHasChanged = false;
+ }
+
+ return maFullTransform;
+}
+
+void E3dObject::NbcSetTransform(const basegfx::B3DHomMatrix& rMatrix)
+{
+ if(maTransformation != rMatrix)
+ {
+ maTransformation = rMatrix;
+ SetTransformChanged();
+ StructureChanged();
+ }
+}
+
+// Set transformation matrix with repaint broadcast
+void E3dObject::SetTransform(const basegfx::B3DHomMatrix& rMatrix)
+{
+ if(rMatrix != maTransformation)
+ {
+ NbcSetTransform(rMatrix);
+ SetChanged();
+ BroadcastObjectChange();
+ if (pUserCall != nullptr) pUserCall->Changed(*this, SdrUserCallType::Resize, tools::Rectangle());
+ }
+}
+
+basegfx::B3DPolyPolygon E3dObject::CreateWireframe() const
+{
+ const basegfx::B3DRange aBoundVolume(GetBoundVolume());
+ return basegfx::utils::createCubePolyPolygonFromB3DRange(aBoundVolume);
+}
+
+// Get the name of the object (singular)
+OUString E3dObject::TakeObjNameSingul() const
+{
+ OUStringBuffer sName(SvxResId(STR_ObjNameSingulObj3d));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName.append(' ');
+ sName.append('\'');
+ sName.append(aName);
+ sName.append('\'');
+ }
+ return sName.makeStringAndClear();
+}
+
+// Get the name of the object (plural)
+OUString E3dObject::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralObj3d);
+}
+
+E3dObject* E3dObject::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return CloneHelper< E3dObject >(rTargetModel);
+}
+
+E3dObject& E3dObject::operator=(const E3dObject& rSource)
+{
+ if(this != &rSource)
+ {
+ // call parent
+ SdrAttrObj::operator=(rSource);
+
+ // BoundVol can be copied since also the children are copied
+ maLocalBoundVol = rSource.maLocalBoundVol;
+ maTransformation = rSource.maTransformation;
+
+ // Because the parent may have changed, definitely redefine the total
+ // transformation next time
+ SetTransformChanged();
+
+ // Copy selection status
+ mbIsSelected = rSource.mbIsSelected;
+ }
+
+ return *this;
+}
+
+SdrObjGeoData *E3dObject::NewGeoData() const
+{
+ return new E3DObjGeoData;
+}
+
+void E3dObject::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrAttrObj::SaveGeoData (rGeo);
+
+ static_cast<E3DObjGeoData &>(rGeo).maLocalBoundVol = maLocalBoundVol;
+ static_cast<E3DObjGeoData &>(rGeo).maTransformation = maTransformation;
+}
+
+void E3dObject::RestGeoData(const SdrObjGeoData& rGeo)
+{
+ maLocalBoundVol = static_cast<const E3DObjGeoData &>(rGeo).maLocalBoundVol;
+ E3DModifySceneSnapRectUpdater aUpdater(this);
+ NbcSetTransform(static_cast<const E3DObjGeoData &>(rGeo).maTransformation);
+ SdrAttrObj::RestGeoData (rGeo);
+}
+
+// 2D-rotation of a 3D-body, normally this is done by the scene itself.
+// This is however a correct implementation, because everything that has
+// happened is a rotation around the axis perpendicular to the screen and that
+// is regardless of how the scene has been rotated up until now.
+void E3dObject::NbcRotate(const Point& rRef, long nAngle, double sn, double cs)
+{
+ // So currently the glue points are defined relative to the scene aOutRect.
+ // Before turning the glue points are defined relative to the page. They
+ // take no part in the rotation of the scene. To ensure this, there is the
+ // SetGlueReallyAbsolute(sal_True);
+ double fAngleInRad = basegfx::deg2rad(nAngle/100.0);
+
+ basegfx::B3DHomMatrix aRotateZ;
+ aRotateZ.rotate(0.0, 0.0, fAngleInRad);
+ NbcSetTransform(aRotateZ * GetTransform());
+
+ SetRectsDirty(); // This forces a recalculation of all BoundRects
+ NbcRotateGluePoints(rRef,nAngle,sn,cs); // Rotate the glue points (who still
+ // have coordinates relative to the
+ // original page)
+ SetGlueReallyAbsolute(false); // from now they are again relative to BoundRect (that is defined as aOutRect)
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dCompoundObject::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dCompoundProperties>(*this);
+}
+
+E3dCompoundObject::E3dCompoundObject(SdrModel& rSdrModel)
+: E3dObject(rSdrModel)
+{
+}
+
+E3dCompoundObject::~E3dCompoundObject ()
+{
+}
+
+basegfx::B2DPolyPolygon E3dCompoundObject::TakeXorPoly() const
+{
+ basegfx::B2DPolyPolygon aRetval;
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+ E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
+
+ if(pRootScene)
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+ const basegfx::B3DPolyPolygon aCubePolyPolygon(CreateWireframe());
+ aRetval = basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aCubePolyPolygon,
+ aViewInfo3D.getObjectToView() * GetTransform());
+ aRetval.transform(rVCScene.getObjectTransformation());
+ }
+
+ return aRetval;
+}
+
+sal_uInt32 E3dCompoundObject::GetHdlCount() const
+{
+ // 8 corners + 1 E3dVolumeMarker (= Wireframe representation)
+ return 9;
+}
+
+void E3dCompoundObject::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+ E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
+
+ if(pRootScene)
+ {
+ const basegfx::B3DRange aBoundVolume(GetBoundVolume());
+
+ if(!aBoundVolume.isEmpty())
+ {
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+
+ for(sal_uInt32 a(0); a < 8; a++)
+ {
+ basegfx::B3DPoint aPos3D;
+
+ switch(a)
+ {
+ case 0 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
+ case 1 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
+ case 2 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
+ case 3 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
+ case 4 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
+ case 5 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
+ case 6 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
+ case 7 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
+ }
+
+ // to 3d view coor
+ aPos3D *= aViewInfo3D.getObjectToView() * GetTransform();
+
+ // create 2d relative scene
+ basegfx::B2DPoint aPos2D(aPos3D.getX(), aPos3D.getY());
+
+ // to 2d world coor
+ aPos2D *= rVCScene.getObjectTransformation();
+
+ rHdlList.AddHdl(std::make_unique<SdrHdl>(Point(basegfx::fround(aPos2D.getX()), basegfx::fround(aPos2D.getY())), SdrHdlKind::BezierWeight));
+ }
+ }
+ }
+
+ const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());
+
+ if(aPolyPolygon.count())
+ {
+ rHdlList.AddHdl(std::make_unique<E3dVolumeMarker>(aPolyPolygon));
+ }
+}
+
+sal_uInt16 E3dCompoundObject::GetObjIdentifier() const
+{
+ return E3D_COMPOUNDOBJ_ID;
+}
+
+void E3dCompoundObject::RecalcSnapRect()
+{
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+ E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
+ maSnapRect = tools::Rectangle();
+
+ if(pRootScene)
+ {
+ // get VC of 3D candidate
+ const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
+
+ if(pVCOfE3D)
+ {
+ // get 3D primitive sequence
+ const drawinglayer::primitive3d::Primitive3DContainer xLocalSequence(pVCOfE3D->getViewIndependentPrimitive3DContainer());
+
+ if(!xLocalSequence.empty())
+ {
+ // get BoundVolume
+ basegfx::B3DRange aBoundVolume(xLocalSequence.getB3DRange(aViewInfo3D));
+
+ // transform bound volume to relative scene coordinates
+ aBoundVolume.transform(aViewInfo3D.getObjectToView());
+
+ // build 2d relative scene range
+ basegfx::B2DRange aSnapRange(
+ aBoundVolume.getMinX(), aBoundVolume.getMinY(),
+ aBoundVolume.getMaxX(), aBoundVolume.getMaxY());
+
+ // transform to 2D world coordinates
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+ aSnapRange.transform(rVCScene.getObjectTransformation());
+
+ // snap to integer
+ maSnapRect = tools::Rectangle(
+ sal_Int32(floor(aSnapRange.getMinX())), sal_Int32(floor(aSnapRange.getMinY())),
+ sal_Int32(ceil(aSnapRange.getMaxX())), sal_Int32(ceil(aSnapRange.getMaxY())));
+ }
+ }
+ }
+}
+
+E3dCompoundObject* E3dCompoundObject::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return CloneHelper< E3dCompoundObject >(rTargetModel);
+}
+
+E3dCompoundObject& E3dCompoundObject::operator=(const E3dCompoundObject& rObj)
+{
+ if( this == &rObj )
+ return *this;
+ E3dObject::operator=(rObj);
+ return *this;
+}
+
+// convert given basegfx::B3DPolyPolygon to screen coor
+basegfx::B2DPolyPolygon E3dCompoundObject::TransformToScreenCoor(const basegfx::B3DPolyPolygon& rCandidate)
+{
+ const uno::Sequence< beans::PropertyValue > aEmptyParameters;
+ drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
+ E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
+ basegfx::B2DPolyPolygon aRetval;
+
+ if(pRootScene)
+ {
+ aRetval = basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(rCandidate,
+ aViewInfo3D.getObjectToView() * GetTransform());
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
+ aRetval.transform(rVCScene.getObjectTransformation());
+ }
+
+ return aRetval;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/objfac3d.cxx b/svx/source/engine3d/objfac3d.cxx
new file mode 100644
index 000000000..5c617127b
--- /dev/null
+++ b/svx/source/engine3d/objfac3d.cxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/globl3d.hxx>
+#include <svx/cube3d.hxx>
+#include <svx/sphere3d.hxx>
+#include <extrud3d.hxx>
+#include <svx/lathe3d.hxx>
+#include <polygn3d.hxx>
+#include <svx/objfac3d.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/scene3d.hxx>
+
+static bool bInit = false;
+
+E3dObjFactory::E3dObjFactory()
+{
+ if ( !bInit )
+ {
+ SdrObjFactory::InsertMakeObjectHdl(LINK(this, E3dObjFactory, MakeObject));
+ bInit = true;
+ }
+}
+
+E3dObjFactory::~E3dObjFactory()
+{
+}
+
+// Generate chart internal objects
+
+IMPL_STATIC_LINK( E3dObjFactory, MakeObject, SdrObjCreatorParams, aParams, SdrObject* )
+{
+ if ( aParams.nInventor == SdrInventor::E3d )
+ {
+ switch ( aParams.nObjIdentifier )
+ {
+ case E3D_SCENE_ID:
+ return new E3dScene(aParams.rSdrModel);
+ case E3D_POLYGONOBJ_ID :
+ return new E3dPolygonObj(aParams.rSdrModel);
+ case E3D_CUBEOBJ_ID :
+ return new E3dCubeObj(aParams.rSdrModel);
+ case E3D_SPHEREOBJ_ID:
+ return new E3dSphereObj(aParams.rSdrModel);
+ case E3D_EXTRUDEOBJ_ID:
+ return new E3dExtrudeObj(aParams.rSdrModel);
+ case E3D_LATHEOBJ_ID:
+ return new E3dLatheObj(aParams.rSdrModel);
+ case E3D_COMPOUNDOBJ_ID:
+ return new E3dCompoundObject(aParams.rSdrModel);
+ }
+ }
+ return nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/polygn3d.cxx b/svx/source/engine3d/polygn3d.cxx
new file mode 100644
index 000000000..d8c1b5d0c
--- /dev/null
+++ b/svx/source/engine3d/polygn3d.cxx
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <polygn3d.hxx>
+#include <svx/globl3d.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <sdr/contact/viewcontactofe3dpolygon.hxx>
+#include <basegfx/polygon/b3dpolygon.hxx>
+#include <basegfx/polygon/b3dpolygontools.hxx>
+
+// DrawContact section
+std::unique_ptr<sdr::contact::ViewContact> E3dPolygonObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dPolygon>(*this);
+}
+
+E3dPolygonObj::E3dPolygonObj(
+ SdrModel& rSdrModel,
+ const basegfx::B3DPolyPolygon& rPolyPoly3D)
+: E3dCompoundObject(rSdrModel),
+ bLineOnly(true)
+{
+ // Set geometry
+ SetPolyPolygon3D(rPolyPoly3D);
+
+ // Create default normals
+ CreateDefaultNormals();
+
+ // Create default texture coordinates
+ CreateDefaultTexture();
+}
+
+E3dPolygonObj::E3dPolygonObj(SdrModel& rSdrModel)
+: E3dCompoundObject(rSdrModel),
+ bLineOnly(false)
+{
+ // Create no geometry
+}
+
+void E3dPolygonObj::CreateDefaultNormals()
+{
+ basegfx::B3DPolyPolygon aPolyNormals;
+
+ // Create a complete tools::PolyPolygon with the plane normal
+ for(sal_uInt32 a(0); a < aPolyPoly3D.count(); a++)
+ {
+ // Find source polygon
+ const basegfx::B3DPolygon aPolygon(aPolyPoly3D.getB3DPolygon(a));
+
+ // Creating a new polygon for the normal
+ basegfx::B3DPolygon aNormals;
+
+ // Get normal (and invert)
+ basegfx::B3DVector aNormal(-aPolygon.getNormal());
+
+ // Fill new polygon
+ for(sal_uInt32 b(0); b < aPolygon.count(); b++)
+ {
+ aNormals.append(aNormal);
+ }
+
+ // Insert new polygon into the PolyPolygon
+ aPolyNormals.append(aNormals);
+ }
+
+ // Set default normal
+ SetPolyNormals3D(aPolyNormals);
+}
+
+void E3dPolygonObj::CreateDefaultTexture()
+{
+ basegfx::B2DPolyPolygon aPolyTexture;
+ // Create a complete tools::PolyPolygon with the texture coordinates
+ // The texture coordinates extend over X,Y and Z
+ // on the whole extreme values in the range 0.0 .. 1.0
+ for(sal_uInt32 a(0); a < aPolyPoly3D.count(); a++)
+ {
+ // Find source polygon
+ const basegfx::B3DPolygon& aPolygon(aPolyPoly3D.getB3DPolygon(a));
+
+ // Determine the total size of the object
+ basegfx::B3DRange aVolume(basegfx::utils::getRange(aPolygon));
+
+ // Get normal
+ basegfx::B3DVector aNormal(aPolygon.getNormal());
+ aNormal.setX(fabs(aNormal.getX()));
+ aNormal.setY(fabs(aNormal.getY()));
+ aNormal.setZ(fabs(aNormal.getZ()));
+
+ // Decide which coordinates should be used as a source for the mapping
+ sal_uInt16 nSourceMode = 0;
+
+ // Determine the greatest degree of freedom
+ if(!(aNormal.getX() > aNormal.getY() && aNormal.getX() > aNormal.getZ()))
+ {
+ if(aNormal.getY() > aNormal.getZ())
+ {
+ // Y is the largest, use X,Z as mapping
+ nSourceMode = 1;
+ }
+ else
+ {
+ // Z is the largest, use X,Y as mapping
+ nSourceMode = 2;
+ }
+ }
+
+ // Create new polygon for texture coordinates
+ basegfx::B2DPolygon aTexture;
+
+ // Fill new polygon
+ for(sal_uInt32 b(0); b < aPolygon.count(); b++)
+ {
+ basegfx::B2DPoint aTex;
+ const basegfx::B3DPoint aCandidate(aPolygon.getB3DPoint(b));
+
+ switch(nSourceMode)
+ {
+ case 0: //Source is Y,Z
+ if(aVolume.getHeight())
+ aTex.setX((aCandidate.getY() - aVolume.getMinY()) / aVolume.getHeight());
+ if(aVolume.getDepth())
+ aTex.setY((aCandidate.getZ() - aVolume.getMinZ()) / aVolume.getDepth());
+ break;
+
+ case 1: // Source is X,Z
+ if(aVolume.getWidth())
+ aTex.setX((aCandidate.getX() - aVolume.getMinX()) / aVolume.getWidth());
+ if(aVolume.getDepth())
+ aTex.setY((aCandidate.getZ() - aVolume.getMinZ()) / aVolume.getDepth());
+ break;
+
+ case 2: // Source is X,Y
+ if(aVolume.getWidth())
+ aTex.setX((aCandidate.getX() - aVolume.getMinX()) / aVolume.getWidth());
+ if(aVolume.getHeight())
+ aTex.setY((aCandidate.getY() - aVolume.getMinY()) / aVolume.getHeight());
+ break;
+ }
+
+ aTexture.append(aTex);
+ }
+
+ // Insert new polygon into the PolyPolygon
+ aPolyTexture.append(aTexture);
+ }
+
+ // Set default Texture coordinates
+ SetPolyTexture2D(aPolyTexture);
+}
+
+E3dPolygonObj::~E3dPolygonObj()
+{
+}
+
+sal_uInt16 E3dPolygonObj::GetObjIdentifier() const
+{
+ return E3D_POLYGONOBJ_ID;
+}
+
+void E3dPolygonObj::SetPolyPolygon3D(const basegfx::B3DPolyPolygon& rNewPolyPoly3D)
+{
+ if ( aPolyPoly3D != rNewPolyPoly3D )
+ {
+ // New PolyPolygon; copying
+ aPolyPoly3D = rNewPolyPoly3D;
+
+ // Create new geometry
+ ActionChanged();
+ }
+}
+
+void E3dPolygonObj::SetPolyNormals3D(const basegfx::B3DPolyPolygon& rNewPolyNormals3D)
+{
+ if ( aPolyNormals3D != rNewPolyNormals3D )
+ {
+ // New PolyPolygon; copying
+ aPolyNormals3D = rNewPolyNormals3D;
+
+ // Create new geometry
+ ActionChanged();
+ }
+}
+
+void E3dPolygonObj::SetPolyTexture2D(const basegfx::B2DPolyPolygon& rNewPolyTexture2D)
+{
+ if ( aPolyTexture2D != rNewPolyTexture2D )
+ {
+ // New PolyPolygon; copying
+ aPolyTexture2D = rNewPolyTexture2D;
+
+ // Create new geometry
+ ActionChanged();
+ }
+}
+
+// Convert the object into a group object consisting of 6 polygons
+
+SdrObjectUniquePtr E3dPolygonObj::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
+{
+ return nullptr;
+}
+
+E3dPolygonObj* E3dPolygonObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return CloneHelper< E3dPolygonObj >(rTargetModel);
+}
+
+E3dPolygonObj& E3dPolygonObj::operator=(const E3dPolygonObj& rObj)
+{
+ if( this == &rObj )
+ return *this;
+ E3dCompoundObject::operator=(rObj);
+
+ aPolyPoly3D = rObj.aPolyPoly3D;
+ aPolyNormals3D = rObj.aPolyNormals3D;
+ aPolyTexture2D = rObj.aPolyTexture2D;
+ bLineOnly = rObj.bLineOnly;
+
+ return *this;
+}
+
+void E3dPolygonObj::SetLineOnly(bool bNew)
+{
+ if(bNew != bLineOnly)
+ {
+ bLineOnly = bNew;
+ ActionChanged();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/scene3d.cxx b/svx/source/engine3d/scene3d.cxx
new file mode 100644
index 000000000..66b134770
--- /dev/null
+++ b/svx/source/engine3d/scene3d.cxx
@@ -0,0 +1,909 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/svditer.hxx>
+
+#include <stdlib.h>
+#include <svx/globl3d.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/svdtrans.hxx>
+#include <sdr/properties/e3dsceneproperties.hxx>
+#include <svx/sdr/contact/viewcontactofe3dscene.hxx>
+#include <svx/svddrag.hxx>
+#include "helperminimaldepth3d.hxx"
+#include <algorithm>
+#include <drawinglayer/geometry/viewinformation3d.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/e3dsceneupdater.hxx>
+#include <svx/svdmodel.hxx>
+#include <rtl/ustrbuf.hxx>
+
+namespace {
+
+class ImpRemap3DDepth
+{
+ sal_uInt32 mnOrdNum;
+ double mfMinimalDepth;
+
+ // bit field
+ bool mbIsScene : 1;
+
+public:
+ ImpRemap3DDepth(sal_uInt32 nOrdNum, double fMinimalDepth);
+ explicit ImpRemap3DDepth(sal_uInt32 nOrdNum);
+
+ // for ::std::sort
+ bool operator<(const ImpRemap3DDepth& rComp) const;
+
+ sal_uInt32 GetOrdNum() const { return mnOrdNum; }
+ bool IsScene() const { return mbIsScene; }
+};
+
+}
+
+ImpRemap3DDepth::ImpRemap3DDepth(sal_uInt32 nOrdNum, double fMinimalDepth)
+: mnOrdNum(nOrdNum),
+ mfMinimalDepth(fMinimalDepth),
+ mbIsScene(false)
+{
+}
+
+ImpRemap3DDepth::ImpRemap3DDepth(sal_uInt32 nOrdNum)
+: mnOrdNum(nOrdNum),
+ mfMinimalDepth(0.0),
+ mbIsScene(true)
+{
+}
+
+bool ImpRemap3DDepth::operator<(const ImpRemap3DDepth& rComp) const
+{
+ if(IsScene())
+ {
+ return false;
+ }
+ else
+ {
+ if(rComp.IsScene())
+ {
+ return true;
+ }
+ else
+ {
+ return mfMinimalDepth < rComp.mfMinimalDepth;
+ }
+ }
+}
+
+class Imp3DDepthRemapper
+{
+ std::vector< ImpRemap3DDepth > maVector;
+
+public:
+ explicit Imp3DDepthRemapper(E3dScene const & rScene);
+
+ sal_uInt32 RemapOrdNum(sal_uInt32 nOrdNum) const;
+};
+
+Imp3DDepthRemapper::Imp3DDepthRemapper(E3dScene const & rScene)
+{
+ // only called when rScene.GetSubList() and nObjCount > 1
+ SdrObjList* pList = rScene.GetSubList();
+ const size_t nObjCount(pList->GetObjCount());
+
+ for(size_t a = 0; a < nObjCount; ++a)
+ {
+ SdrObject* pCandidate = pList->GetObj(a);
+
+ if(pCandidate)
+ {
+ if(dynamic_cast< const E3dCompoundObject*>(pCandidate))
+ {
+ // single 3d object, calc depth
+ const double fMinimalDepth(getMinimalDepthInViewCoordinates(static_cast< const E3dCompoundObject& >(*pCandidate)));
+ ImpRemap3DDepth aEntry(a, fMinimalDepth);
+ maVector.push_back(aEntry);
+ }
+ else
+ {
+ // scene, use standard entry for scene
+ ImpRemap3DDepth aEntry(a);
+ maVector.push_back(aEntry);
+ }
+ }
+ }
+
+ // now, we need to sort the maVector by its members minimal depth. The
+ // smaller, the nearer to the viewer.
+ ::std::sort(maVector.begin(), maVector.end());
+}
+
+sal_uInt32 Imp3DDepthRemapper::RemapOrdNum(sal_uInt32 nOrdNum) const
+{
+ if(nOrdNum < maVector.size())
+ {
+ nOrdNum = maVector[(maVector.size() - 1) - nOrdNum].GetOrdNum();
+ }
+
+ return nOrdNum;
+}
+
+
+// BaseProperties section
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dScene::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dSceneProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> E3dScene::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dScene>(*this);
+}
+
+
+E3dScene::E3dScene(SdrModel& rSdrModel)
+: E3dObject(rSdrModel),
+ SdrObjList(),
+ aCamera(basegfx::B3DPoint(0.0, 0.0, 4.0), basegfx::B3DPoint()),
+ bDrawOnlySelected(false),
+ mbSkipSettingDirty(false)
+{
+ // Set defaults
+ SetDefaultAttributes();
+}
+
+void E3dScene::SetDefaultAttributes()
+{
+ // For WIN95/NT turn off the FP-Exceptions
+#if defined(_WIN32)
+ _control87( _MCW_EM, _MCW_EM );
+#endif
+
+ // Set defaults
+ aCamera.SetViewWindow(-2, -2, 4, 4);
+ aCameraSet.SetDeviceRectangle(-2, 2, -2, 2);
+ aCamera.SetDeviceWindow(tools::Rectangle(0, 0, 10, 10));
+ tools::Rectangle aRect(0, 0, 10, 10);
+ aCameraSet.SetViewportRectangle(aRect);
+
+ // set defaults for Camera from ItemPool
+ aCamera.SetProjection(GetPerspective());
+ basegfx::B3DPoint aActualPosition(aCamera.GetPosition());
+ double fNew = GetDistance();
+
+ if(fabs(fNew - aActualPosition.getZ()) > 1.0)
+ {
+ aCamera.SetPosition( basegfx::B3DPoint( aActualPosition.getX(), aActualPosition.getY(), fNew) );
+ }
+
+ fNew = GetFocalLength() / 100.0;
+ aCamera.SetFocalLength(fNew);
+}
+
+E3dScene::~E3dScene()
+{
+ ImpCleanup3DDepthMapper();
+}
+
+SdrPage* E3dScene::getSdrPageFromSdrObjList() const
+{
+ return getSdrPageFromSdrObject();
+}
+
+SdrObject* E3dScene::getSdrObjectFromSdrObjList() const
+{
+ return const_cast< E3dScene* >(this);
+}
+
+SdrObjList* E3dScene::getChildrenOfSdrObject() const
+{
+ return const_cast< E3dScene* >(this);
+}
+
+basegfx::B2DPolyPolygon E3dScene::TakeXorPoly() const
+{
+ const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(GetViewContact());
+ const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
+ const basegfx::B3DPolyPolygon aCubePolyPolygon(CreateWireframe());
+
+ basegfx::B2DPolyPolygon aRetval(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aCubePolyPolygon,
+ aViewInfo3D.getObjectToView()));
+ aRetval.transform(rVCScene.getObjectTransformation());
+
+ return aRetval;
+}
+
+void E3dScene::ImpCleanup3DDepthMapper()
+{
+ mp3DDepthRemapper.reset();
+}
+
+sal_uInt32 E3dScene::RemapOrdNum(sal_uInt32 nNewOrdNum) const
+{
+ if(!mp3DDepthRemapper)
+ {
+ const size_t nObjCount(GetSubList() ? GetSubList()->GetObjCount() : 0);
+
+ if(nObjCount > 1)
+ {
+ mp3DDepthRemapper.reset(new Imp3DDepthRemapper(*this));
+ }
+ }
+
+ if(mp3DDepthRemapper)
+ {
+ return mp3DDepthRemapper->RemapOrdNum(nNewOrdNum);
+ }
+
+ return nNewOrdNum;
+}
+
+sal_uInt16 E3dScene::GetObjIdentifier() const
+{
+ return E3D_SCENE_ID;
+}
+
+void E3dScene::SetBoundRectDirty()
+{
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(pScene == this)
+ {
+ // avoid resetting aOutRect which in case of a 3D scene used as 2d object
+ // is model data,not re-creatable view data
+ }
+ else
+ {
+ // if not the outmost scene it is used as group in 3d, call parent
+ E3dObject::SetBoundRectDirty();
+ }
+}
+
+void E3dScene::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ SetRectsDirty();
+ E3dObject::NbcSetSnapRect(rRect);
+ aCamera.SetDeviceWindow(rRect);
+ aCameraSet.SetViewportRectangle(rRect);
+
+ ImpCleanup3DDepthMapper();
+}
+
+void E3dScene::NbcMove(const Size& rSize)
+{
+ tools::Rectangle aNewSnapRect = GetSnapRect();
+ aNewSnapRect.Move(rSize);
+ NbcSetSnapRect(aNewSnapRect);
+}
+
+void E3dScene::NbcResize(const Point& rRef, const Fraction& rXFact,
+ const Fraction& rYFact)
+{
+ tools::Rectangle aNewSnapRect = GetSnapRect();
+ ResizeRect(aNewSnapRect, rRef, rXFact, rYFact);
+ NbcSetSnapRect(aNewSnapRect);
+}
+
+// Set new camera, and thus mark the scene and if possible the bound volume
+// as changed
+
+void E3dScene::SetCamera(const Camera3D& rNewCamera)
+{
+ aCamera = rNewCamera;
+ static_cast<sdr::properties::E3dSceneProperties&>(GetProperties()).SetSceneItemsFromCamera();
+
+ SetRectsDirty();
+
+ // Turn off ratio
+ GetCameraSet().SetRatio(0.0);
+
+ // Set Imaging geometry
+ basegfx::B3DPoint aVRP(aCamera.GetViewPoint());
+ basegfx::B3DVector aVPN(aVRP - aCamera.GetVRP());
+ basegfx::B3DVector aVUV(aCamera.GetVUV());
+
+ // use SetViewportValues() to set VRP, VPN and VUV as vectors, too.
+ // Else these values would not be exported/imported correctly.
+ GetCameraSet().SetViewportValues(aVRP, aVPN, aVUV);
+
+ // Set perspective
+ GetCameraSet().SetPerspective(aCamera.GetProjection() == ProjectionType::Perspective);
+ GetCameraSet().SetViewportRectangle(aCamera.GetDeviceWindow());
+
+ ImpCleanup3DDepthMapper();
+}
+
+// Inform parent of changes of a child
+
+void E3dScene::StructureChanged()
+{
+ E3dObject::StructureChanged();
+
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene && !pScene->mbSkipSettingDirty)
+ {
+ SetRectsDirty();
+ }
+
+ ImpCleanup3DDepthMapper();
+}
+
+// Determine the overall scene object
+
+E3dScene* E3dScene::getRootE3dSceneFromE3dObject() const
+{
+ E3dScene* pParent(getParentE3dSceneFromE3dObject());
+
+ if(nullptr != pParent)
+ {
+ return pParent->getRootE3dSceneFromE3dObject();
+ }
+
+ return const_cast< E3dScene* >(this);
+}
+
+void E3dScene::removeAllNonSelectedObjects()
+{
+ E3DModifySceneSnapRectUpdater aUpdater(this);
+
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ SdrObject* pObj = GetObj(a);
+
+ if(pObj)
+ {
+ bool bRemoveObject(false);
+
+ if(dynamic_cast< const E3dScene*>(pObj))
+ {
+ E3dScene* pScene = static_cast<E3dScene*>(pObj);
+
+ // iterate over this sub-scene
+ pScene->removeAllNonSelectedObjects();
+
+ // check object count. Empty scenes can be deleted
+ const size_t nObjCount(pScene->GetSubList() ? pScene->GetSubList()->GetObjCount() : 0);
+
+ if(!nObjCount)
+ {
+ // all objects removed, scene can be removed, too
+ bRemoveObject = true;
+ }
+ }
+ else if(dynamic_cast< const E3dCompoundObject*>(pObj))
+ {
+ E3dCompoundObject* pCompound = static_cast<E3dCompoundObject*>(pObj);
+
+ if(!pCompound->GetSelected())
+ {
+ bRemoveObject = true;
+ }
+ }
+
+ if(bRemoveObject)
+ {
+ NbcRemoveObject(pObj->GetOrdNum());
+ a--;
+ SdrObject::Free(pObj);
+ }
+ }
+ }
+}
+
+E3dScene* E3dScene::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return CloneHelper< E3dScene >(rTargetModel);
+}
+
+E3dScene& E3dScene::operator=(const E3dScene& rSource)
+{
+ if(this != &rSource)
+ {
+ // call parent
+ E3dObject::operator=(rSource);
+
+ // copy child SdrObjects
+ if (rSource.GetSubList())
+ {
+ CopyObjects(*rSource.GetSubList());
+
+ // tdf#116979: needed here, we need bSnapRectDirty to be true
+ // which it is after using SdrObject::operator= (see above),
+ // but set to false again using CopyObjects
+ SetRectsDirty();
+ }
+
+ // copy local data
+ aCamera = rSource.aCamera;
+ aCameraSet = rSource.aCameraSet;
+ static_cast<sdr::properties::E3dSceneProperties&>(GetProperties()).SetSceneItemsFromCamera();
+ InvalidateBoundVolume();
+ RebuildLists();
+ ImpCleanup3DDepthMapper();
+ GetViewContact().ActionChanged();
+ }
+
+ return *this;
+}
+
+void E3dScene::SuspendReportingDirtyRects()
+{
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ pScene->mbSkipSettingDirty = true;
+ }
+}
+
+void E3dScene::ResumeReportingDirtyRects()
+{
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ pScene->mbSkipSettingDirty = false;
+ }
+}
+
+void E3dScene::SetAllSceneRectsDirty()
+{
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(nullptr != pScene)
+ {
+ pScene->SetRectsDirty();
+ }
+}
+
+// Rebuild Light- and label- object lists rebuild (after loading, allocation)
+
+void E3dScene::RebuildLists()
+{
+ // first delete
+ const SdrLayerID nCurrLayerID(GetLayer());
+ SdrObjListIter a3DIterator(GetSubList(), SdrIterMode::Flat);
+
+ // then examine all the objects in the scene
+ while(a3DIterator.IsMore())
+ {
+ E3dObject* p3DObj(static_cast< E3dObject* >(a3DIterator.Next()));
+ p3DObj->NbcSetLayer(nCurrLayerID);
+ }
+
+ ImpCleanup3DDepthMapper();
+}
+
+SdrObjGeoData *E3dScene::NewGeoData() const
+{
+ return new E3DSceneGeoData;
+}
+
+void E3dScene::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ E3dObject::SaveGeoData (rGeo);
+
+ static_cast<E3DSceneGeoData &>(rGeo).aCamera = aCamera;
+}
+
+void E3dScene::RestGeoData(const SdrObjGeoData& rGeo)
+{
+ // #i94832# removed E3DModifySceneSnapRectUpdater here.
+ // It should not be needed, is already part of E3dObject::RestGeoData
+ E3dObject::RestGeoData (rGeo);
+ SetCamera (static_cast<const E3DSceneGeoData &>(rGeo).aCamera);
+}
+
+// Something was changed in the style sheet, so change scene
+
+void E3dScene::Notify(SfxBroadcaster &rBC, const SfxHint &rHint)
+{
+ SetRectsDirty();
+ E3dObject::Notify(rBC, rHint);
+}
+
+void E3dScene::RotateScene (const Point& rRef, double sn, double cs)
+{
+ Point UpperLeft, LowerRight, Center, NewCenter;
+
+ UpperLeft = aOutRect.TopLeft();
+ LowerRight = aOutRect.BottomRight();
+
+ long dxOutRectHalf = labs(UpperLeft.X() - LowerRight.X());
+ dxOutRectHalf /= 2;
+ long dyOutRectHalf = labs(UpperLeft.Y() - LowerRight.Y());
+ dyOutRectHalf /= 2;
+
+ // Only the center is moved. The corners are moved by NbcMove. For the
+ // rotation a cartesian coordinate system is used in which the pivot
+ // point is the origin, and the y-axis increases upward, the X-axis to
+ // the right. This must be especially noted for the Y-values.
+ // (When considering a flat piece of paper the Y-axis pointing downwards
+ Center.setX( (UpperLeft.X() + dxOutRectHalf) - rRef.X() );
+ Center.setY( -((UpperLeft.Y() + dyOutRectHalf) - rRef.Y()) );
+ // A few special cases has to be dealt with first (n * 90 degrees n integer)
+ if (sn==1.0 && cs==0.0) { // 90deg
+ NewCenter.setX( -Center.Y() );
+ NewCenter.setY( -Center.X() );
+ } else if (sn==0.0 && cs==-1.0) { // 180deg
+ NewCenter.setX( -Center.X() );
+ NewCenter.setY( -Center.Y() );
+ } else if (sn==-1.0 && cs==0.0) { // 270deg
+ NewCenter.setX( Center.Y() );
+ NewCenter.setY( -Center.X() );
+ }
+ else // Here it is rotated to any angle in the mathematically
+ // positive direction!
+ { // xnew = x * cos(alpha) - y * sin(alpha)
+ // ynew = x * sin(alpha) + y * cos(alpha)
+ // Bottom Right is not rotated: the pages of aOutRect must
+ // remain parallel to the coordinate axes.
+ NewCenter.setX( static_cast<long>(Center.X() * cs - Center.Y() * sn) );
+ NewCenter.setY( static_cast<long>(Center.X() * sn + Center.Y() * cs) );
+ }
+
+ Size Differenz;
+ Point DiffPoint = NewCenter - Center;
+ Differenz.setWidth( DiffPoint.X() );
+ Differenz.setHeight( -DiffPoint.Y() ); // Note that the Y-axis is counted ad positive downward.
+ NbcMove (Differenz); // Actually executes the coordinate transformation.
+}
+
+OUString E3dScene::TakeObjNameSingul() const
+{
+ OUStringBuffer sName(SvxResId(STR_ObjNameSingulScene3d));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName.append(' ');
+ sName.append('\'');
+ sName.append(aName);
+ sName.append('\'');
+ }
+ return sName.makeStringAndClear();
+}
+
+OUString E3dScene::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralScene3d);
+}
+
+// The NbcRotate routine overrides the one of the SdrObject. The idea is
+// to be able to rotate the scene relative to the position of the scene
+// and then the objects in the scene
+
+void E3dScene::NbcSetTransform(const basegfx::B3DHomMatrix& rMatrix)
+{
+ if(maTransformation != rMatrix)
+ {
+ // call parent
+ E3dObject::NbcSetTransform(rMatrix);
+ }
+}
+
+void E3dScene::SetTransform(const basegfx::B3DHomMatrix& rMatrix)
+{
+ if(rMatrix != maTransformation)
+ {
+ // call parent
+ E3dObject::SetTransform(rMatrix);
+ }
+}
+
+void E3dScene::NbcRotate(const Point& rRef, long nAngle, double sn, double cs)
+{
+ // So currently the glue points are defined relative to the scene aOutRect.
+ // Before turning the glue points are defined relative to the page. They
+ // take no part in the rotation of the scene. To ensure this, there is the
+ // SetGlueReallyAbsolute(sal_True);
+
+ // So that was the scene, now the objects used in the scene
+ // 3D objects, if there is only one it can still have multiple surfaces but
+ // the surfaces do not have to be connected. This allows you to access child
+ // objects. So going through the entire list and rotate around the Z axis
+ // through the enter of aOutRect's (Steiner's theorem), so RotateZ
+
+ RotateScene (rRef, sn, cs); // Rotates the scene
+ double fAngleInRad = basegfx::deg2rad(nAngle/100.0);
+
+ basegfx::B3DHomMatrix aRotation;
+ aRotation.rotate(0.0, 0.0, fAngleInRad);
+ NbcSetTransform(aRotation * GetTransform());
+
+ SetRectsDirty(); // This forces a recalculation of all BoundRects
+ NbcRotateGluePoints(rRef,nAngle,sn,cs); // Rotate the glue points (who still
+ // have coordinates relative to the
+ // original page)
+ SetGlueReallyAbsolute(false); // from now they are again relative to BoundRect (that is defined as aOutRect)
+ SetRectsDirty();
+}
+
+void E3dScene::RecalcSnapRect()
+{
+ E3dScene* pScene(getRootE3dSceneFromE3dObject());
+
+ if(pScene == this)
+ {
+ // The Scene is used as a 2D-Object, take the SnapRect from the
+ // 2D Display settings
+ maSnapRect = pScene->aCamera.GetDeviceWindow();
+ }
+ else
+ {
+ // The Scene itself is a member of another scene, get the SnapRect
+ // as a composite object
+ // call parent
+ E3dObject::RecalcSnapRect();
+
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ E3dObject* pCandidate(dynamic_cast< E3dObject* >(GetObj(a)));
+
+ if(pCandidate)
+ {
+ maSnapRect.Union(pCandidate->GetSnapRect());
+ }
+ }
+ }
+}
+
+bool E3dScene::IsBreakObjPossible()
+{
+ // Break scene, if all members are able to break
+ SdrObjListIter a3DIterator(GetSubList(), SdrIterMode::DeepWithGroups);
+
+ while ( a3DIterator.IsMore() )
+ {
+ E3dObject* pObj = static_cast<E3dObject*>(a3DIterator.Next());
+ DBG_ASSERT(dynamic_cast< const E3dObject*>(pObj), "only 3D objects are allowed in scenes!");
+ if(!pObj->IsBreakObjPossible())
+ return false;
+ }
+
+ return true;
+}
+
+basegfx::B2DPolyPolygon E3dScene::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
+{
+ return TakeXorPoly();
+}
+
+bool E3dScene::BegCreate(SdrDragStat& rStat)
+{
+ rStat.SetOrtho4Possible();
+ tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
+ aRect1.Justify();
+ rStat.SetActionRect(aRect1);
+ NbcSetSnapRect(aRect1);
+ return true;
+}
+
+bool E3dScene::MovCreate(SdrDragStat& rStat)
+{
+ tools::Rectangle aRect1;
+ rStat.TakeCreateRect(aRect1);
+ aRect1.Justify();
+ rStat.SetActionRect(aRect1);
+ NbcSetSnapRect(aRect1);
+ SetBoundRectDirty();
+ bSnapRectDirty=true;
+ return true;
+}
+
+bool E3dScene::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
+{
+ tools::Rectangle aRect1;
+ rStat.TakeCreateRect(aRect1);
+ aRect1.Justify();
+ NbcSetSnapRect(aRect1);
+ SetRectsDirty();
+ return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
+}
+
+bool E3dScene::BckCreate(SdrDragStat& /*rStat*/)
+{
+ return false;
+}
+
+void E3dScene::BrkCreate(SdrDragStat& /*rStat*/)
+{
+}
+
+void E3dScene::SetSelected(bool bNew)
+{
+ // call parent
+ E3dObject::SetSelected(bNew);
+
+ for(size_t a(0); a < GetObjCount(); a++)
+ {
+ E3dObject* pCandidate(dynamic_cast< E3dObject* >(GetObj(a)));
+
+ if(pCandidate)
+ {
+ pCandidate->SetSelected(bNew);
+ }
+ }
+}
+
+void E3dScene::NbcInsertObject(SdrObject* pObj, size_t nPos)
+{
+ // Is it even a 3D object?
+ if(nullptr != dynamic_cast< const E3dObject* >(pObj))
+ {
+ // Normal 3D object, insert means call parent
+ SdrObjList::NbcInsertObject(pObj, nPos);
+
+ // local needed stuff
+ InvalidateBoundVolume();
+ StructureChanged();
+ }
+ else
+ {
+ // No 3D object, inserted a page in place in a scene ...
+ getSdrObjectFromSdrObjList()->getSdrPageFromSdrObject()->InsertObject(pObj, nPos);
+ }
+}
+
+void E3dScene::InsertObject(SdrObject* pObj, size_t nPos)
+{
+ // Is it even a 3D object?
+ if(nullptr != dynamic_cast< const E3dObject* >(pObj))
+ {
+ // call parent
+ SdrObjList::InsertObject(pObj, nPos);
+
+ // local needed stuff
+ InvalidateBoundVolume();
+ StructureChanged();
+ }
+ else
+ {
+ // No 3D object, inserted a page in place in a scene ...
+ getSdrObjectFromSdrObjList()->getSdrPageFromSdrObject()->InsertObject(pObj, nPos);
+ }
+}
+
+SdrObject* E3dScene::NbcRemoveObject(size_t nObjNum)
+{
+ // call parent
+ SdrObject* pRetval = SdrObjList::NbcRemoveObject(nObjNum);
+
+ InvalidateBoundVolume();
+ StructureChanged();
+
+ return pRetval;
+}
+
+SdrObject* E3dScene::RemoveObject(size_t nObjNum)
+{
+ // call parent
+ SdrObject* pRetval(SdrObjList::RemoveObject(nObjNum));
+
+ InvalidateBoundVolume();
+ StructureChanged();
+
+ return pRetval;
+}
+
+void E3dScene::SetRectsDirty(bool bNotMyself, bool bRecursive)
+{
+ // call parent
+ E3dObject::SetRectsDirty(bNotMyself, bRecursive);
+
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ E3dObject* pCandidate = dynamic_cast< E3dObject* >(GetObj(a));
+
+ if(pCandidate)
+ {
+ pCandidate->SetRectsDirty(bNotMyself, false);
+ }
+ }
+}
+
+void E3dScene::NbcSetLayer(SdrLayerID nLayer)
+{
+ // call parent
+ E3dObject::NbcSetLayer(nLayer);
+
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ E3dObject* pCandidate = dynamic_cast< E3dObject* >(GetObj(a));
+
+ if(pCandidate)
+ {
+ pCandidate->NbcSetLayer(nLayer);
+ }
+ }
+}
+
+void E3dScene::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ if(pOldPage != pNewPage)
+ {
+ // call parent
+ E3dObject::handlePageChange(pOldPage, pNewPage);
+
+ for(size_t a(0); a < GetObjCount(); a++)
+ {
+ E3dObject* pCandidate = dynamic_cast< E3dObject* >(GetObj(a));
+
+ if(pCandidate)
+ {
+ pCandidate->handlePageChange(pOldPage, pNewPage);
+ }
+ else
+ {
+ OSL_ENSURE(false, "E3dScene::handlePageChange invalid object list (!)");
+ }
+ }
+ }
+}
+
+SdrObjList* E3dScene::GetSubList() const
+{
+ return const_cast< E3dScene* >(this);
+}
+
+basegfx::B3DRange E3dScene::RecalcBoundVolume() const
+{
+ basegfx::B3DRange aRetval;
+ const size_t nObjCnt(GetObjCount());
+
+ for(size_t a = 0; a < nObjCnt; ++a)
+ {
+ const E3dObject* p3DObject = dynamic_cast< const E3dObject* >(GetObj(a));
+
+ if(p3DObject)
+ {
+ basegfx::B3DRange aLocalRange(p3DObject->GetBoundVolume());
+ aLocalRange.transform(p3DObject->GetTransform());
+ aRetval.expand(aLocalRange);
+ }
+ }
+
+ return aRetval;
+}
+
+void E3dScene::SetTransformChanged()
+{
+ // call parent
+ E3dObject::SetTransformChanged();
+
+ for(size_t a = 0; a < GetObjCount(); ++a)
+ {
+ E3dObject* pCandidate = dynamic_cast< E3dObject* >(GetObj(a));
+
+ if(pCandidate)
+ {
+ pCandidate->SetTransformChanged();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/sphere3d.cxx b/svx/source/engine3d/sphere3d.cxx
new file mode 100644
index 000000000..e5e6939c1
--- /dev/null
+++ b/svx/source/engine3d/sphere3d.cxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/strings.hrc>
+#include <svx/deflt3d.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/globl3d.hxx>
+#include <svx/sphere3d.hxx>
+
+#include <sdr/properties/e3dsphereproperties.hxx>
+#include <basegfx/vector/b3dvector.hxx>
+#include <basegfx/point/b3dpoint.hxx>
+#include <sdr/contact/viewcontactofe3dsphere.hxx>
+#include <rtl/ustrbuf.hxx>
+
+// DrawContact section
+std::unique_ptr<sdr::contact::ViewContact> E3dSphereObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfE3dSphere>(*this);
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> E3dSphereObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::E3dSphereProperties>(*this);
+}
+
+// Build Sphere from polygon facets in latitude and longitude
+E3dSphereObj::E3dSphereObj(
+ SdrModel& rSdrModel,
+ const E3dDefaultAttributes& rDefault,
+ const basegfx::B3DPoint& rCenter,
+ const basegfx::B3DVector& r3DSize)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set defaults
+ SetDefaultAttributes(rDefault);
+
+ aCenter = rCenter;
+ aSize = r3DSize;
+}
+
+E3dSphereObj::E3dSphereObj(SdrModel& rSdrModel)
+: E3dCompoundObject(rSdrModel)
+{
+ // Set defaults
+ const E3dDefaultAttributes aDefault;
+
+ SetDefaultAttributes(aDefault);
+}
+
+E3dSphereObj::~E3dSphereObj()
+{
+}
+
+void E3dSphereObj::SetDefaultAttributes(const E3dDefaultAttributes& rDefault)
+{
+ // Set defaults
+ aCenter = rDefault.GetDefaultSphereCenter();
+ aSize = rDefault.GetDefaultSphereSize();
+}
+
+sal_uInt16 E3dSphereObj::GetObjIdentifier() const
+{
+ return E3D_SPHEREOBJ_ID;
+}
+
+// Convert the object into a group object consisting of n polygons
+
+SdrObjectUniquePtr E3dSphereObj::DoConvertToPolyObj(bool /*bBezier*/, bool /*bAddText*/) const
+{
+ return nullptr;
+}
+
+E3dSphereObj* E3dSphereObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return CloneHelper< E3dSphereObj >(rTargetModel);
+}
+
+E3dSphereObj& E3dSphereObj::operator=(const E3dSphereObj& rObj)
+{
+ if( this == &rObj )
+ return *this;
+ E3dCompoundObject::operator=(rObj);
+
+ aCenter = rObj.aCenter;
+ aSize = rObj.aSize;
+
+ return *this;
+}
+
+// Set local parameters with geometry re-creating
+
+void E3dSphereObj::SetCenter(const basegfx::B3DPoint& rNew)
+{
+ if(aCenter != rNew)
+ {
+ aCenter = rNew;
+ ActionChanged();
+ }
+}
+
+void E3dSphereObj::SetSize(const basegfx::B3DVector& rNew)
+{
+ if(aSize != rNew)
+ {
+ aSize = rNew;
+ ActionChanged();
+ }
+}
+
+// Get the name of the object (singular)
+
+OUString E3dSphereObj::TakeObjNameSingul() const
+{
+ OUStringBuffer sName(SvxResId(STR_ObjNameSingulSphere3d));
+
+ OUString aName(GetName());
+ if (!aName.isEmpty())
+ {
+ sName.append(' ');
+ sName.append('\'');
+ sName.append(aName);
+ sName.append('\'');
+ }
+ return sName.makeStringAndClear();
+}
+
+// Get the name of the object (plural)
+
+OUString E3dSphereObj::TakeObjNamePlural() const
+{
+ return SvxResId(STR_ObjNamePluralSphere3d);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/svx3ditems.cxx b/svx/source/engine3d/svx3ditems.cxx
new file mode 100644
index 000000000..1468fb0ff
--- /dev/null
+++ b/svx/source/engine3d/svx3ditems.cxx
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svx3ditems.hxx>
+#include <com/sun/star/drawing/NormalsKind.hpp>
+#include <com/sun/star/drawing/TextureProjectionMode.hpp>
+#include <com/sun/star/drawing/TextureKind.hpp>
+#include <com/sun/star/drawing/TextureMode.hpp>
+#include <com/sun/star/drawing/ProjectionMode.hpp>
+#include <com/sun/star/drawing/ShadeMode.hpp>
+
+
+using namespace ::com::sun::star;
+
+// #i28528#
+// Added extra Item (Bool) for chart2 to be able to show reduced line geometry
+
+Svx3DReducedLineGeometryItem::Svx3DReducedLineGeometryItem(bool bVal)
+: SfxBoolItem(SDRATTR_3DOBJ_REDUCED_LINE_GEOMETRY, bVal)
+{}
+
+Svx3DReducedLineGeometryItem* Svx3DReducedLineGeometryItem::Clone(SfxItemPool *) const
+{
+ return new Svx3DReducedLineGeometryItem(*this);
+}
+
+Svx3DNormalsKindItem::Svx3DNormalsKindItem(sal_uInt16 nVal)
+: SfxUInt16Item(SDRATTR_3DOBJ_NORMALS_KIND, nVal)
+{}
+
+Svx3DTextureProjectionXItem::Svx3DTextureProjectionXItem(sal_uInt16 nVal)
+: SfxUInt16Item(SDRATTR_3DOBJ_TEXTURE_PROJ_X, nVal)
+{}
+
+Svx3DTextureProjectionYItem::Svx3DTextureProjectionYItem(sal_uInt16 nVal)
+: SfxUInt16Item(SDRATTR_3DOBJ_TEXTURE_PROJ_Y, nVal)
+{}
+
+Svx3DTextureKindItem::Svx3DTextureKindItem(sal_uInt16 nVal)
+: SfxUInt16Item(SDRATTR_3DOBJ_TEXTURE_KIND, nVal)
+{}
+
+Svx3DTextureModeItem::Svx3DTextureModeItem(sal_uInt16 nVal)
+: SfxUInt16Item(SDRATTR_3DOBJ_TEXTURE_MODE, nVal)
+{}
+
+Svx3DPerspectiveItem::Svx3DPerspectiveItem(ProjectionType nVal)
+: SfxUInt16Item(SDRATTR_3DSCENE_PERSPECTIVE, static_cast<sal_uInt16>(nVal))
+{}
+
+Svx3DShadeModeItem::Svx3DShadeModeItem(sal_uInt16 nVal)
+: SfxUInt16Item(SDRATTR_3DSCENE_SHADE_MODE, nVal)
+{}
+
+
+Svx3DSmoothNormalsItem::Svx3DSmoothNormalsItem(bool bVal)
+: SfxBoolItem(SDRATTR_3DOBJ_SMOOTH_NORMALS, bVal)
+{}
+
+Svx3DSmoothNormalsItem* Svx3DSmoothNormalsItem::Clone(SfxItemPool *) const
+{
+ return new Svx3DSmoothNormalsItem(*this);
+}
+
+Svx3DSmoothLidsItem::Svx3DSmoothLidsItem(bool bVal)
+: SfxBoolItem(SDRATTR_3DOBJ_SMOOTH_LIDS, bVal)
+{}
+
+Svx3DSmoothLidsItem* Svx3DSmoothLidsItem::Clone(SfxItemPool *) const
+{
+ return new Svx3DSmoothLidsItem(*this);
+}
+
+Svx3DCharacterModeItem::Svx3DCharacterModeItem(bool bVal)
+: SfxBoolItem(SDRATTR_3DOBJ_CHARACTER_MODE, bVal)
+{}
+
+Svx3DCharacterModeItem* Svx3DCharacterModeItem::Clone(SfxItemPool *) const
+{
+ return new Svx3DCharacterModeItem(*this);
+}
+
+Svx3DCloseFrontItem::Svx3DCloseFrontItem(bool bVal)
+: SfxBoolItem(SDRATTR_3DOBJ_CLOSE_FRONT, bVal)
+{}
+
+Svx3DCloseFrontItem* Svx3DCloseFrontItem::Clone(SfxItemPool *) const
+{
+ return new Svx3DCloseFrontItem(*this);
+}
+
+Svx3DCloseBackItem::Svx3DCloseBackItem(bool bVal)
+: SfxBoolItem(SDRATTR_3DOBJ_CLOSE_BACK, bVal)
+{}
+
+Svx3DCloseBackItem* Svx3DCloseBackItem::Clone(SfxItemPool *) const
+{
+ return new Svx3DCloseBackItem(*this);
+}
+
+// Svx3DNormalsKindItem: use drawing::NormalsKind
+bool Svx3DNormalsKindItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::NormalsKind>(GetValue());
+ return true;
+}
+
+bool Svx3DNormalsKindItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::NormalsKind eVar;
+ if(!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DNormalsKindItem* Svx3DNormalsKindItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DNormalsKindItem(*this);
+}
+
+// Svx3DTextureProjectionXItem: use drawing::TextureProjectionMode
+bool Svx3DTextureProjectionXItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextureProjectionMode>(GetValue());
+ return true;
+}
+
+bool Svx3DTextureProjectionXItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextureProjectionMode eVar;
+ if(!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DTextureProjectionXItem* Svx3DTextureProjectionXItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DTextureProjectionXItem(*this);
+}
+
+// Svx3DTextureProjectionYItem: use drawing::TextureProjectionMode
+bool Svx3DTextureProjectionYItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextureProjectionMode>(GetValue());
+ return true;
+}
+
+bool Svx3DTextureProjectionYItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextureProjectionMode eVar;
+ if(!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DTextureProjectionYItem* Svx3DTextureProjectionYItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DTextureProjectionYItem(*this);
+}
+
+// Svx3DTextureKindItem: use drawing::TextureKind
+bool Svx3DTextureKindItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextureKind>(GetValue());
+ return true;
+}
+
+bool Svx3DTextureKindItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextureKind eVar;
+ if(!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DTextureKindItem* Svx3DTextureKindItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DTextureKindItem(*this);
+}
+
+// Svx3DTextureModeItem: use drawing:TextureMode
+bool Svx3DTextureModeItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::TextureMode>(GetValue());
+ return true;
+}
+
+bool Svx3DTextureModeItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::TextureMode eVar;
+ if(!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DTextureModeItem* Svx3DTextureModeItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DTextureModeItem(*this);
+}
+
+// Svx3DPerspectiveItem: use drawing::ProjectionMode
+bool Svx3DPerspectiveItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::ProjectionMode>(GetValue());
+ return true;
+}
+
+bool Svx3DPerspectiveItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::ProjectionMode eVar;
+ if(!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DPerspectiveItem* Svx3DPerspectiveItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DPerspectiveItem(*this);
+}
+
+// Svx3DShadeModeItem: use drawing::ShadeMode
+bool Svx3DShadeModeItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/) const
+{
+ rVal <<= static_cast<drawing::ShadeMode>(GetValue());
+ return true;
+}
+
+bool Svx3DShadeModeItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/)
+{
+ drawing::ShadeMode eVar;
+ if(!(rVal >>= eVar))
+ return false;
+ SetValue(static_cast<sal_Int16>(eVar));
+ return true;
+}
+
+Svx3DShadeModeItem* Svx3DShadeModeItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new Svx3DShadeModeItem(*this);
+}
+
+// EOF
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/view3d.cxx b/svx/source/engine3d/view3d.cxx
new file mode 100644
index 000000000..77d94ab1c
--- /dev/null
+++ b/svx/source/engine3d/view3d.cxx
@@ -0,0 +1,1599 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdopath.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpagv.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdview.hxx>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/lathe3d.hxx>
+#include <extrud3d.hxx>
+#include <dragmt3d.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/view3d.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xlineit0.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/sdr/overlay/overlaypolypolygon.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+#include <svx/e3dsceneupdater.hxx>
+
+using namespace com::sun::star;
+
+
+// Migrate Marking
+
+class Impl3DMirrorConstructOverlay
+{
+ // The OverlayObjects
+ sdr::overlay::OverlayObjectList maObjects;
+
+ // the view
+ const E3dView& mrView;
+
+ // the object count
+ size_t mnCount;
+
+ // the unmirrored polygons
+ basegfx::B2DPolyPolygon* mpPolygons;
+
+ // the overlay geometry from selected objects
+ drawinglayer::primitive2d::Primitive2DContainer maFullOverlay;
+
+ // Copy assignment is forbidden and not implemented.
+ Impl3DMirrorConstructOverlay (const Impl3DMirrorConstructOverlay &) = delete;
+ Impl3DMirrorConstructOverlay & operator= (const Impl3DMirrorConstructOverlay &) = delete;
+
+public:
+ explicit Impl3DMirrorConstructOverlay(const E3dView& rView);
+ ~Impl3DMirrorConstructOverlay();
+
+ void SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB);
+};
+
+Impl3DMirrorConstructOverlay::Impl3DMirrorConstructOverlay(const E3dView& rView)
+: maObjects(),
+ mrView(rView),
+ mnCount(rView.GetMarkedObjectCount()),
+ mpPolygons(nullptr),
+ maFullOverlay()
+{
+ if(mnCount)
+ {
+ if(mrView.IsSolidDragging())
+ {
+ SdrPageView* pPV = rView.GetSdrPageView();
+
+ if(pPV && pPV->PageWindowCount())
+ {
+ for(size_t a = 0; a < mnCount; ++a)
+ {
+ SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
+
+ if(pObject)
+ {
+ // use the view-independent primitive representation (without
+ // evtl. GridOffset, that may be applied to the DragEntry individually)
+ const drawinglayer::primitive2d::Primitive2DContainer& aNewSequence(
+ pObject->GetViewContact().getViewIndependentPrimitive2DContainer());
+ maFullOverlay.append(aNewSequence);
+ }
+ }
+ }
+ }
+ else
+ {
+ mpPolygons = new basegfx::B2DPolyPolygon[mnCount];
+
+ for(size_t a = 0; a < mnCount; ++a)
+ {
+ SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
+ mpPolygons[mnCount - (a + 1)] = pObject->TakeXorPoly();
+ }
+ }
+ }
+}
+
+Impl3DMirrorConstructOverlay::~Impl3DMirrorConstructOverlay()
+{
+ // The OverlayObjects are cleared using the destructor of OverlayObjectList.
+ // That destructor calls clear() at the list which removes all objects from the
+ // OverlayManager and deletes them.
+ if(!mrView.IsSolidDragging())
+ {
+ delete[] mpPolygons;
+ }
+}
+
+void Impl3DMirrorConstructOverlay::SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB)
+{
+ // get rid of old overlay objects
+ maObjects.clear();
+
+ // create new ones
+ for(sal_uInt32 a(0); a < mrView.PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pCandidate = mrView.GetPaintWindow(a);
+ const rtl::Reference< sdr::overlay::OverlayManager >& xTargetOverlay = pCandidate->GetOverlayManager();
+
+ if(xTargetOverlay.is())
+ {
+ // build transformation: translate and rotate so that given edge is
+ // on x axis, them mirror in y and translate back
+ const basegfx::B2DVector aEdge(aMirrorAxisB.X() - aMirrorAxisA.X(), aMirrorAxisB.Y() - aMirrorAxisA.Y());
+ basegfx::B2DHomMatrix aMatrixTransform(basegfx::utils::createTranslateB2DHomMatrix(
+ -aMirrorAxisA.X(), -aMirrorAxisA.Y()));
+ aMatrixTransform.rotate(-atan2(aEdge.getY(), aEdge.getX()));
+ aMatrixTransform.scale(1.0, -1.0);
+ aMatrixTransform.rotate(atan2(aEdge.getY(), aEdge.getX()));
+ aMatrixTransform.translate(aMirrorAxisA.X(), aMirrorAxisA.Y());
+
+ if(mrView.IsSolidDragging())
+ {
+ if(!maFullOverlay.empty())
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aContent(maFullOverlay);
+
+ if(!aMatrixTransform.isIdentity())
+ {
+ // embed in transformation group
+ drawinglayer::primitive2d::Primitive2DReference aTransformPrimitive2D(new drawinglayer::primitive2d::TransformPrimitive2D(aMatrixTransform, aContent));
+ aContent = drawinglayer::primitive2d::Primitive2DContainer { aTransformPrimitive2D };
+ }
+
+ // if we have full overlay from selected objects, embed with 50% transparence, the
+ // transformation is added to the OverlayPrimitive2DSequenceObject
+ drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(aContent, 0.5));
+ aContent = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparencePrimitive2D };
+
+ std::unique_ptr<sdr::overlay::OverlayPrimitive2DSequenceObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(aContent));
+
+ xTargetOverlay->add(*pNew);
+ maObjects.append(std::move(pNew));
+ }
+ }
+ else
+ {
+ for(size_t b = 0; b < mnCount; ++b)
+ {
+ // apply to polygon
+ basegfx::B2DPolyPolygon aPolyPolygon(mpPolygons[b]);
+ aPolyPolygon.transform(aMatrixTransform);
+
+ std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
+ aPolyPolygon));
+ xTargetOverlay->add(*pNew);
+ maObjects.append(std::move(pNew));
+ }
+ }
+ }
+ }
+}
+
+E3dView::E3dView(
+ SdrModel& rSdrModel,
+ OutputDevice* pOut)
+: SdrView(rSdrModel, pOut)
+{
+ InitView();
+}
+
+// DrawMarkedObj override, since possibly only a single 3D object is to be
+// drawn
+
+void E3dView::DrawMarkedObj(OutputDevice& rOut) const
+{
+ // Does 3D objects exist which scenes are not selected?
+ bool bSpecialHandling = false;
+ E3dScene *pScene = nullptr;
+
+ const size_t nCnt = GetMarkedObjectCount();
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(auto pCompoundObject = dynamic_cast<E3dCompoundObject*>(pObj))
+ {
+ // related scene
+ pScene = pCompoundObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene && !IsObjMarked(pScene))
+ {
+ bSpecialHandling = true;
+ }
+ }
+ // Reset all selection flags
+ if(auto p3dObject = dynamic_cast< const E3dObject*>(pObj))
+ {
+ pScene = p3dObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene)
+ {
+ pScene->SetSelected(false);
+ }
+ }
+ }
+
+ if(bSpecialHandling)
+ {
+ // Set selection flag to "not selected" for scenes related to all 3D
+ // objects
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(auto pCompoundObject = dynamic_cast<E3dCompoundObject*>(pObj))
+ {
+ // related scene
+ pScene = pCompoundObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene)
+ {
+ pScene->SetSelected(false);
+ }
+ }
+ }
+
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(auto p3DObj = dynamic_cast<E3dObject*>(pObj))
+ {
+ // Select object
+ p3DObj->SetSelected(true);
+ pScene = p3DObj->getRootE3dSceneFromE3dObject();
+ }
+ }
+
+ if(nullptr != pScene)
+ {
+ // code from parent
+ SortMarkedObjects();
+
+ pScene->SetDrawOnlySelected(true);
+ pScene->SingleObjectPainter(rOut);
+ pScene->SetDrawOnlySelected(false);
+ }
+
+ // Reset selection flag
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(auto pCompoundObject = dynamic_cast<E3dCompoundObject*>(pObj))
+ {
+ // related scene
+ pScene = pCompoundObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene)
+ {
+ pScene->SetSelected(false);
+ }
+ }
+ }
+ }
+ else
+ {
+ // call parent
+ SdrExchangeView::DrawMarkedObj(rOut);
+ }
+}
+
+// override get model, since in some 3D objects an additional scene
+// must be pushed in
+
+std::unique_ptr<SdrModel> E3dView::CreateMarkedObjModel() const
+{
+ // Does 3D objects exist which scenes are not selected?
+ bool bSpecialHandling(false);
+ const size_t nCount(GetMarkedObjectCount());
+ E3dScene *pScene = nullptr;
+
+ for(size_t nObjs = 0; nObjs < nCount; ++nObjs)
+ {
+ const SdrObject* pObj = GetMarkedObjectByIndex(nObjs);
+
+ if(!bSpecialHandling && dynamic_cast< const E3dCompoundObject*>(pObj))
+ {
+ // if the object is selected, but it's scene not,
+ // we need special handling
+ pScene = static_cast<const E3dCompoundObject*>(pObj)->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene && !IsObjMarked(pScene))
+ {
+ bSpecialHandling = true;
+ }
+ }
+
+ if(auto p3dObject = dynamic_cast< const E3dObject*>(pObj))
+ {
+ // reset all selection flags at 3D objects
+ pScene = p3dObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene)
+ {
+ pScene->SetSelected(false);
+ }
+ }
+ }
+
+ if(!bSpecialHandling)
+ {
+ // call parent
+ return SdrView::CreateMarkedObjModel();
+ }
+
+ std::unique_ptr<SdrModel> pNewModel;
+ tools::Rectangle aSelectedSnapRect;
+
+ // set 3d selection flags at all directly selected objects
+ // and collect SnapRect of selected objects
+ for(size_t nObjs = 0; nObjs < nCount; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+
+ if(auto p3DObj = dynamic_cast<E3dCompoundObject*>(pObj))
+ {
+ // mark object, but not scenes
+ p3DObj->SetSelected(true);
+ aSelectedSnapRect.Union(p3DObj->GetSnapRect());
+ }
+ }
+
+ // create new mark list which contains all indirectly selected3d
+ // scenes as selected objects
+ SdrMarkList aOldML(GetMarkedObjectList());
+ SdrMarkList aNewML;
+ SdrMarkList& rCurrentMarkList = const_cast<E3dView*>(this)->GetMarkedObjectListWriteAccess();
+ rCurrentMarkList = aNewML;
+
+ for(size_t nObjs = 0; nObjs < nCount; ++nObjs)
+ {
+ SdrObject *pObj = aOldML.GetMark(nObjs)->GetMarkedSdrObj();
+
+ if(auto p3dObject = dynamic_cast< E3dObject* >(pObj))
+ {
+ pScene = p3dObject->getRootE3dSceneFromE3dObject();
+
+ if(nullptr != pScene && !IsObjMarked(pScene) && GetSdrPageView())
+ {
+ const_cast<E3dView*>(this)->MarkObj(pScene, GetSdrPageView(), false, true);
+ }
+ }
+ }
+
+ // call parent. This will copy all scenes and the selection flags at the 3D objects. So
+ // it will be possible to delete all non-selected 3d objects from the cloned 3d scenes
+ pNewModel = SdrView::CreateMarkedObjModel();
+
+ if(pNewModel)
+ {
+ for(sal_uInt16 nPg(0); nPg < pNewModel->GetPageCount(); nPg++)
+ {
+ const SdrPage* pSrcPg=pNewModel->GetPage(nPg);
+ const size_t nObjCount(pSrcPg->GetObjCount());
+
+ for(size_t nOb = 0; nOb < nObjCount; ++nOb)
+ {
+ const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
+
+ if(auto p3dscene = dynamic_cast< const E3dScene* >( pSrcOb))
+ {
+ pScene = const_cast<E3dScene*>(p3dscene);
+
+ // delete all not intentionally cloned 3d objects
+ pScene->removeAllNonSelectedObjects();
+
+ // reset select flags and set SnapRect of all selected objects
+ pScene->SetSelected(false);
+ pScene->SetSnapRect(aSelectedSnapRect);
+ }
+ }
+ }
+ }
+
+ // restore old selection
+ rCurrentMarkList = aOldML;
+
+ return pNewModel;
+}
+
+// When pasting objects have to integrated if a scene is inserted, but
+// not the scene itself
+
+bool E3dView::Paste(
+ const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
+{
+ bool bRetval = false;
+
+ // Get list
+ Point aPos(rPos);
+ SdrObjList* pDstList = pLst;
+ ImpGetPasteObjList(aPos, pDstList);
+
+ if(!pDstList)
+ return false;
+
+ // Get owner of the list
+ E3dScene* pDstScene(dynamic_cast< E3dScene* >(pDstList->getSdrObjectFromSdrObjList()));
+
+ if(nullptr != pDstScene)
+ {
+ BegUndo(SvxResId(RID_SVX_3D_UNDO_EXCHANGE_PASTE));
+
+ // Copy all objects from E3dScenes and insert them directly
+ for(sal_uInt16 nPg(0); nPg < rMod.GetPageCount(); nPg++)
+ {
+ const SdrPage* pSrcPg=rMod.GetPage(nPg);
+ const size_t nObjCount(pSrcPg->GetObjCount());
+
+ // calculate offset for paste
+ tools::Rectangle aR = pSrcPg->GetAllObjBoundRect();
+ Point aDist(aPos - aR.Center());
+
+ // Insert sub-objects for scenes
+ for(size_t nOb = 0; nOb < nObjCount; ++nOb)
+ {
+ const SdrObject* pSrcOb = pSrcPg->GetObj(nOb);
+ if(auto p3dscene = dynamic_cast< const E3dScene* >(pSrcOb))
+ {
+ E3dScene* pSrcScene = const_cast<E3dScene*>(p3dscene);
+ ImpCloneAll3DObjectsToDestScene(pSrcScene, pDstScene, aDist);
+ }
+ }
+ }
+ EndUndo();
+ }
+ else
+ {
+ // call parent
+ bRetval = SdrView::Paste(rMod, rPos, pLst, nOptions);
+ }
+
+ return bRetval;
+}
+
+// Service routine used from local Clone() and from SdrCreateView::EndCreateObj(...)
+bool E3dView::ImpCloneAll3DObjectsToDestScene(E3dScene const * pSrcScene, E3dScene* pDstScene, Point /*aOffset*/)
+{
+ bool bRetval(false);
+
+ if(pSrcScene && pDstScene)
+ {
+ for(size_t i = 0; i < pSrcScene->GetSubList()->GetObjCount(); ++i)
+ {
+ E3dCompoundObject* pCompoundObj = dynamic_cast< E3dCompoundObject* >(pSrcScene->GetSubList()->GetObj(i));
+
+ if(pCompoundObj)
+ {
+ E3dCompoundObject* pNewCompoundObj(pCompoundObj->CloneSdrObject(pDstScene->getSdrModelFromSdrObject()));
+
+ if(pNewCompoundObj)
+ {
+ // get dest scene's current range in 3D world coordinates
+ const basegfx::B3DHomMatrix aSceneToWorldTrans(pDstScene->GetFullTransform());
+ basegfx::B3DRange aSceneRange(pDstScene->GetBoundVolume());
+ aSceneRange.transform(aSceneToWorldTrans);
+
+ // get new object's implied object transformation
+ const basegfx::B3DHomMatrix aNewObjectTrans(pNewCompoundObj->GetTransform());
+
+ // get new object's range in 3D world coordinates in dest scene
+ // as if it were already added
+ const basegfx::B3DHomMatrix aObjectToWorldTrans(aSceneToWorldTrans * aNewObjectTrans);
+ basegfx::B3DRange aObjectRange(pNewCompoundObj->GetBoundVolume());
+ aObjectRange.transform(aObjectToWorldTrans);
+
+ // get scale adaptation
+ const basegfx::B3DVector aSceneScale(aSceneRange.getRange());
+ const basegfx::B3DVector aObjectScale(aObjectRange.getRange());
+ double fScale(1.0);
+
+ // if new object's size in X,Y or Z is bigger that 80% of dest scene, adapt scale
+ // to not change the scene by the inserted object
+ const double fSizeFactor(0.5);
+
+ if(aObjectScale.getX() * fScale > aSceneScale.getX() * fSizeFactor)
+ {
+ const double fObjSize(aObjectScale.getX() * fScale);
+ const double fFactor((aSceneScale.getX() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
+ fScale *= fFactor;
+ }
+
+ if(aObjectScale.getY() * fScale > aSceneScale.getY() * fSizeFactor)
+ {
+ const double fObjSize(aObjectScale.getY() * fScale);
+ const double fFactor((aSceneScale.getY() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
+ fScale *= fFactor;
+ }
+
+ if(aObjectScale.getZ() * fScale > aSceneScale.getZ() * fSizeFactor)
+ {
+ const double fObjSize(aObjectScale.getZ() * fScale);
+ const double fFactor((aSceneScale.getZ() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
+ fScale *= fFactor;
+ }
+
+ // get translation adaptation
+ const basegfx::B3DPoint aSceneCenter(aSceneRange.getCenter());
+ const basegfx::B3DPoint aObjectCenter(aObjectRange.getCenter());
+
+ // build full modification transform. The object's transformation
+ // shall be modified, so start at object coordinates; transform to 3d world coor
+ basegfx::B3DHomMatrix aModifyingTransform(aObjectToWorldTrans);
+
+ // translate to absolute center in 3d world coor
+ aModifyingTransform.translate(-aObjectCenter.getX(), -aObjectCenter.getY(), -aObjectCenter.getZ());
+
+ // scale to dest size in 3d world coor
+ aModifyingTransform.scale(fScale, fScale, fScale);
+
+ // translate to dest scene center in 3d world coor
+ aModifyingTransform.translate(aSceneCenter.getX(), aSceneCenter.getY(), aSceneCenter.getZ());
+
+ // transform from 3d world to dest object coordinates
+ basegfx::B3DHomMatrix aWorldToObject(aObjectToWorldTrans);
+ aWorldToObject.invert();
+ aModifyingTransform = aWorldToObject * aModifyingTransform;
+
+ // correct implied object transform by applying changing one in object coor
+ pNewCompoundObj->SetTransform(aModifyingTransform * aNewObjectTrans);
+
+ // fill and insert new object
+ pNewCompoundObj->NbcSetLayer(pCompoundObj->GetLayer());
+ pNewCompoundObj->NbcSetStyleSheet(pCompoundObj->GetStyleSheet(), true);
+ pDstScene->InsertObject(pNewCompoundObj);
+ bRetval = true;
+
+ // Create undo
+ if( GetModel()->IsUndoEnabled() )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewCompoundObj));
+ }
+ }
+ }
+ }
+
+ return bRetval;
+}
+
+bool E3dView::IsConvertTo3DObjPossible() const
+{
+ bool bAny3D(false);
+ bool bGroupSelected(false);
+ bool bRetval(true);
+
+ for(size_t a=0; !bAny3D && a<GetMarkedObjectCount(); ++a)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(a);
+ if(pObj)
+ {
+ ImpIsConvertTo3DPossible(pObj, bAny3D, bGroupSelected);
+ }
+ }
+
+ bRetval = !bAny3D
+ && (
+ IsConvertToPolyObjPossible()
+ || IsConvertToPathObjPossible()
+ || IsImportMtfPossible());
+ return bRetval;
+}
+
+void E3dView::ImpIsConvertTo3DPossible(SdrObject const * pObj, bool& rAny3D,
+ bool& rGroupSelected) const
+{
+ if(pObj)
+ {
+ if(dynamic_cast< const E3dObject* >(pObj) != nullptr)
+ {
+ rAny3D = true;
+ }
+ else
+ {
+ if(pObj->IsGroupObject())
+ {
+ SdrObjListIter aIter(*pObj, SdrIterMode::DeepNoGroups);
+ while(aIter.IsMore())
+ {
+ SdrObject* pNewObj = aIter.Next();
+ ImpIsConvertTo3DPossible(pNewObj, rAny3D, rGroupSelected);
+ }
+ rGroupSelected = true;
+ }
+ }
+ }
+}
+
+void E3dView::ImpChangeSomeAttributesFor3DConversion(SdrObject* pObj)
+{
+ if(dynamic_cast<const SdrTextObj*>( pObj) != nullptr)
+ {
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+ const SvxColorItem& rTextColorItem = rSet.Get(EE_CHAR_COLOR);
+ if(rTextColorItem.GetValue() == COL_BLACK)
+ {
+ //For black text objects, the color set to gray
+ if(pObj->getSdrPageFromSdrObject())
+ {
+ // if black is only default attribute from
+ // pattern set it hard so that it is used in undo.
+ pObj->SetMergedItem(SvxColorItem(COL_BLACK, EE_CHAR_COLOR));
+
+ // add undo now
+ if( GetModel()->IsUndoEnabled() )
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
+ }
+
+ pObj->SetMergedItem(SvxColorItem(COL_GRAY, EE_CHAR_COLOR));
+ }
+ }
+}
+
+void E3dView::ImpChangeSomeAttributesFor3DConversion2(SdrObject* pObj)
+{
+ if(dynamic_cast<const SdrPathObj*>( pObj) != nullptr)
+ {
+ const SfxItemSet& rSet = pObj->GetMergedItemSet();
+ sal_Int32 nLineWidth = rSet.Get(XATTR_LINEWIDTH).GetValue();
+ drawing::LineStyle eLineStyle = rSet.Get(XATTR_LINESTYLE).GetValue();
+ drawing::FillStyle eFillStyle = rSet.Get(XATTR_FILLSTYLE).GetValue();
+
+ if(static_cast<SdrPathObj*>(pObj)->IsClosed()
+ && eLineStyle == drawing::LineStyle_SOLID
+ && !nLineWidth
+ && eFillStyle != drawing::FillStyle_NONE)
+ {
+ if(pObj->getSdrPageFromSdrObject() && GetModel()->IsUndoEnabled() )
+ {
+ AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
+ }
+
+ pObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ pObj->SetMergedItem(XLineWidthItem(0));
+ }
+ }
+}
+
+void E3dView::ImpCreateSingle3DObjectFlat(E3dScene* pScene, SdrObject* pObj, bool bExtrude, double fDepth, basegfx::B2DHomMatrix const & rLatheMat)
+{
+ // Single PathObject, transform this
+ SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pObj );
+
+ if(pPath)
+ {
+ E3dDefaultAttributes aDefault = Get3DDefaultAttributes();
+
+ if(bExtrude)
+ {
+ aDefault.SetDefaultExtrudeCharacterMode(true);
+ }
+ else
+ {
+ aDefault.SetDefaultLatheCharacterMode(true);
+ }
+
+ // Get Itemset of the original object
+ SfxItemSet aSet(pObj->GetMergedItemSet());
+
+ drawing::FillStyle eFillStyle = aSet.Get(XATTR_FILLSTYLE).GetValue();
+
+ // line style turned off
+ aSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
+
+ //Determining if FILL_Attribut is set.
+ if(!pPath->IsClosed() || eFillStyle == drawing::FillStyle_NONE)
+ {
+ // This SdrPathObj is not filled, leave the front and rear face out.
+ // Moreover, a two-sided representation necessary.
+ aDefault.SetDefaultExtrudeCloseFront(false);
+ aDefault.SetDefaultExtrudeCloseBack(false);
+
+ aSet.Put(makeSvx3DDoubleSidedItem(true));
+
+ // Set fill attribute
+ aSet.Put(XFillStyleItem(drawing::FillStyle_SOLID));
+
+ // Fill color must be the color line, because the object was
+ // previously just a line
+ Color aColorLine = aSet.Get(XATTR_LINECOLOR).GetColorValue();
+ aSet.Put(XFillColorItem(OUString(), aColorLine));
+ }
+
+ // Create a new extrude object
+ E3dObject* p3DObj = nullptr;
+ if(bExtrude)
+ {
+ p3DObj = new E3dExtrudeObj(pObj->getSdrModelFromSdrObject(), aDefault, pPath->GetPathPoly(), fDepth);
+ }
+ else
+ {
+ // rLatheMat expects coordinates with y-axis up, pPath uses y-axis down
+ basegfx::B2DHomMatrix aFlipVerticalMat(1.0, 0.0, 0.0, 0.0, -1.0, 0.0);
+ basegfx::B2DPolyPolygon aPolyPoly2D(pPath->GetPathPoly());
+ aPolyPoly2D.transform(aFlipVerticalMat);
+ aPolyPoly2D.transform(rLatheMat);
+ // ctor E3dLatheObj expects coordinates with y-axis down
+ aPolyPoly2D.transform(aFlipVerticalMat);
+ p3DObj = new E3dLatheObj(pObj->getSdrModelFromSdrObject(), aDefault, aPolyPoly2D);
+ }
+
+ // Set attribute
+ p3DObj->NbcSetLayer(pObj->GetLayer());
+
+ p3DObj->SetMergedItemSet(aSet);
+
+ p3DObj->NbcSetStyleSheet(pObj->GetStyleSheet(), true);
+
+ // Insert a new extrude object
+ pScene->InsertObject(p3DObj);
+ }
+}
+
+void E3dView::ImpCreate3DObject(E3dScene* pScene, SdrObject* pObj, bool bExtrude, double fDepth, basegfx::B2DHomMatrix const & rLatheMat)
+{
+ if(pObj)
+ {
+ // change text color attribute for not so dark colors
+ if(pObj->IsGroupObject())
+ {
+ SdrObjListIter aIter(*pObj, SdrIterMode::DeepWithGroups);
+ while(aIter.IsMore())
+ {
+ SdrObject* pGroupMember = aIter.Next();
+ ImpChangeSomeAttributesFor3DConversion(pGroupMember);
+ }
+ }
+ else
+ ImpChangeSomeAttributesFor3DConversion(pObj);
+
+ // convert completely to path objects
+ SdrObject* pNewObj1 = pObj->ConvertToPolyObj(false, false).release();
+
+ if(pNewObj1)
+ {
+ // change text color attribute for not so dark colors
+ if(pNewObj1->IsGroupObject())
+ {
+ SdrObjListIter aIter(*pNewObj1, SdrIterMode::DeepWithGroups);
+ while(aIter.IsMore())
+ {
+ SdrObject* pGroupMember = aIter.Next();
+ ImpChangeSomeAttributesFor3DConversion2(pGroupMember);
+ }
+ }
+ else
+ ImpChangeSomeAttributesFor3DConversion2(pNewObj1);
+
+ // convert completely to path objects
+ SdrObject* pNewObj2 = pObj->ConvertToContourObj(pNewObj1, true);
+
+ if(pNewObj2)
+ {
+ // add all to flat scene
+ if(pNewObj2->IsGroupObject())
+ {
+ SdrObjListIter aIter(*pNewObj2, SdrIterMode::DeepWithGroups);
+ while(aIter.IsMore())
+ {
+ SdrObject* pGroupMember = aIter.Next();
+ ImpCreateSingle3DObjectFlat(pScene, pGroupMember, bExtrude, fDepth, rLatheMat);
+ }
+ }
+ else
+ ImpCreateSingle3DObjectFlat(pScene, pNewObj2, bExtrude, fDepth, rLatheMat);
+
+ // delete object in between
+ if (pNewObj2 != pObj && pNewObj2 != pNewObj1)
+ SdrObject::Free( pNewObj2 );
+ }
+
+ // delete object in between
+ if (pNewObj1 != pObj)
+ SdrObject::Free( pNewObj1 );
+ }
+ }
+}
+
+void E3dView::ConvertMarkedObjTo3D(bool bExtrude, const basegfx::B2DPoint& rPnt1, const basegfx::B2DPoint& rPnt2)
+{
+ if(!AreObjectsMarked())
+ return;
+
+ // Create undo
+ if(bExtrude)
+ BegUndo(SvxResId(RID_SVX_3D_UNDO_EXTRUDE));
+ else
+ BegUndo(SvxResId(RID_SVX_3D_UNDO_LATHE));
+
+ SdrModel& rSdrModel(GetSdrMarkByIndex(0)->GetMarkedSdrObj()->getSdrModelFromSdrObject());
+
+ // Create a new scene for the created 3D object
+ E3dScene* pScene = new E3dScene(rSdrModel);
+
+ // Determine rectangle and possibly correct it
+ tools::Rectangle aRect = GetAllMarkedRect();
+ if(aRect.GetWidth() <= 1)
+ aRect.SetSize(Size(500, aRect.GetHeight()));
+ if(aRect.GetHeight() <= 1)
+ aRect.SetSize(Size(aRect.GetWidth(), 500));
+
+ // Determine the depth relative to the size of the selection
+ double fDepth = 0.0;
+ double fRot3D = 0.0;
+ basegfx::B2DHomMatrix aLatheMat;
+
+ if(bExtrude)
+ {
+ double fW = static_cast<double>(aRect.GetWidth());
+ double fH = static_cast<double>(aRect.GetHeight());
+ fDepth = sqrt(fW*fW + fH*fH) / 6.0;
+ }
+ if(!bExtrude)
+ {
+ // Create transformation for the polygons rotating body
+ if (rPnt1 != rPnt2)
+ {
+ // Rotation around control point #1 with set angle
+ // for 3D coordinates
+ basegfx::B2DPoint aDiff(rPnt1 - rPnt2);
+ fRot3D = atan2(aDiff.getY(), aDiff.getX()) - F_PI2;
+
+ if(basegfx::fTools::equalZero(fabs(fRot3D)))
+ fRot3D = 0.0;
+
+ if(fRot3D != 0.0)
+ {
+ aLatheMat = basegfx::utils::createRotateAroundPoint(rPnt2, -fRot3D)
+ * aLatheMat;
+ }
+ }
+
+ if (rPnt2.getX() != 0.0)
+ {
+ // Translation to Y=0 - axis
+ aLatheMat.translate(-rPnt2.getX(), 0.0);
+ }
+ else
+ {
+ aLatheMat.translate(static_cast<double>(-aRect.Left()), 0.0);
+ }
+
+ // Form the inverse matrix to determine the target expansion
+ basegfx::B2DHomMatrix aInvLatheMat(aLatheMat);
+ aInvLatheMat.invert();
+
+ // SnapRect extension enables mirroring in the axis of rotation
+ for(size_t a=0; a<GetMarkedObjectCount(); ++a)
+ {
+ SdrMark* pMark = GetSdrMarkByIndex(a);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+ tools::Rectangle aTurnRect = pObj->GetSnapRect();
+ basegfx::B2DPoint aRot;
+ Point aRotPnt;
+
+ aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Top());
+ aRot *= aLatheMat;
+ aRot.setX(-aRot.getX());
+ aRot *= aInvLatheMat;
+ aRotPnt = Point(static_cast<long>(aRot.getX() + 0.5), static_cast<long>(-aRot.getY() - 0.5));
+ aRect.Union(tools::Rectangle(aRotPnt, aRotPnt));
+
+ aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Bottom());
+ aRot *= aLatheMat;
+ aRot.setX(-aRot.getX());
+ aRot *= aInvLatheMat;
+ aRotPnt = Point(static_cast<long>(aRot.getX() + 0.5), static_cast<long>(-aRot.getY() - 0.5));
+ aRect.Union(tools::Rectangle(aRotPnt, aRotPnt));
+
+ aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Top());
+ aRot *= aLatheMat;
+ aRot.setX(-aRot.getX());
+ aRot *= aInvLatheMat;
+ aRotPnt = Point(static_cast<long>(aRot.getX() + 0.5), static_cast<long>(-aRot.getY() - 0.5));
+ aRect.Union(tools::Rectangle(aRotPnt, aRotPnt));
+
+ aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Bottom());
+ aRot *= aLatheMat;
+ aRot.setX(-aRot.getX());
+ aRot *= aInvLatheMat;
+ aRotPnt = Point(static_cast<long>(aRot.getX() + 0.5), static_cast<long>(-aRot.getY() - 0.5));
+ aRect.Union(tools::Rectangle(aRotPnt, aRotPnt));
+ }
+ }
+
+ // Walk through the selection and convert it into 3D, complete with
+ // Conversion to SdrPathObject, also fonts
+ for(size_t a=0; a<GetMarkedObjectCount(); ++a)
+ {
+ SdrMark* pMark = GetSdrMarkByIndex(a);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ ImpCreate3DObject(pScene, pObj, bExtrude, fDepth, aLatheMat);
+ }
+
+ if(pScene->GetSubList() && pScene->GetSubList()->GetObjCount() != 0)
+ {
+ // Arrange all created objects by depth
+ if(bExtrude)
+ DoDepthArrange(pScene, fDepth);
+
+ // Center 3D objects in the middle of the overall rectangle
+ basegfx::B3DPoint aCenter(pScene->GetBoundVolume().getCenter());
+ basegfx::B3DHomMatrix aMatrix;
+
+ aMatrix.translate(-aCenter.getX(), -aCenter.getY(), -aCenter.getZ());
+ pScene->SetTransform(aMatrix * pScene->GetTransform());
+
+ // Initialize scene
+ pScene->NbcSetSnapRect(aRect);
+ basegfx::B3DRange aBoundVol = pScene->GetBoundVolume();
+ InitScene(pScene, static_cast<double>(aRect.GetWidth()), static_cast<double>(aRect.GetHeight()), aBoundVol.getDepth());
+
+ // Insert scene instead of the first selected object and throw away
+ // all the old objects
+ SdrObject* pRepObj = GetMarkedObjectByIndex(0);
+ SdrPageView* pPV = GetSdrPageViewOfMarkedByIndex(0);
+ MarkObj(pRepObj, pPV, true);
+ ReplaceObjectAtView(pRepObj, *pPV, pScene, false);
+ DeleteMarked();
+ MarkObj(pScene, pPV);
+
+ // Rotate Rotation body around the axis of rotation
+ if(!bExtrude && fRot3D != 0.0)
+ {
+ basegfx::B3DHomMatrix aRotate;
+ aRotate.rotate(0.0, 0.0, fRot3D);
+ pScene->SetTransform(aRotate * pScene->GetTransform());
+ }
+
+ // Set default rotation
+ {
+ basegfx::B3DHomMatrix aRotate;
+ aRotate.rotate(DEG2RAD(20.0), 0.0, 0.0);
+ // E3DModifySceneSnapRectUpdater updates the 2D representation of the scene.
+ // It prepares things in ctor and acts in dtor.
+ E3DModifySceneSnapRectUpdater aUpdater(pScene->getSdrObjectFromSdrObjList());
+ pScene->SetTransform(aRotate * pScene->GetTransform());
+ }
+ }
+ else
+ {
+ // No 3D object was created, throw away everything
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pScene);
+ SdrObject::Free(pTemp);
+ }
+
+ EndUndo();
+}
+
+//Arrange all created extrude objects by depth
+
+namespace {
+
+struct E3dDepthNeighbour
+{
+ E3dExtrudeObj* mpObj;
+ basegfx::B2DPolyPolygon maPreparedPolyPolygon;
+
+ E3dDepthNeighbour(E3dExtrudeObj* pObj, basegfx::B2DPolyPolygon const & rPreparedPolyPolygon)
+ : mpObj(pObj),
+ maPreparedPolyPolygon(rPreparedPolyPolygon)
+ {
+ }
+};
+
+struct E3dDepthLayer
+{
+ E3dDepthLayer* mpDown;
+ std::vector<E3dDepthNeighbour> mvNeighbours;
+
+ E3dDepthLayer()
+ : mpDown(nullptr)
+ {
+ }
+};
+
+}
+
+void E3dView::DoDepthArrange(E3dScene const * pScene, double fDepth)
+{
+ if(pScene && pScene->GetSubList() && pScene->GetSubList()->GetObjCount() > 1)
+ {
+ SdrObjList* pSubList = pScene->GetSubList();
+ SdrObjListIter aIter(pSubList, SdrIterMode::Flat);
+ E3dDepthLayer* pBaseLayer = nullptr;
+ E3dDepthLayer* pLayer = nullptr;
+ sal_Int32 nNumLayers = 0;
+
+ while(aIter.IsMore())
+ {
+ E3dExtrudeObj* pExtrudeObj = dynamic_cast< E3dExtrudeObj* >(aIter.Next());
+
+ if(pExtrudeObj)
+ {
+ const basegfx::B2DPolyPolygon aExtrudePoly(
+ basegfx::utils::prepareForPolygonOperation(pExtrudeObj->GetExtrudePolygon()));
+ const SfxItemSet& rLocalSet = pExtrudeObj->GetMergedItemSet();
+ const drawing::FillStyle eLocalFillStyle = rLocalSet.Get(XATTR_FILLSTYLE).GetValue();
+ const Color aLocalColor = rLocalSet.Get(XATTR_FILLCOLOR).GetColorValue();
+
+ // sort in ExtrudeObj
+ if(pLayer)
+ {
+ // do we have overlap with an object of this layer?
+ bool bOverlap(false);
+
+ for(const auto& rAct : pLayer->mvNeighbours)
+ {
+ // do rAct.mpObj and pExtrudeObj overlap? Check by
+ // using logical AND clipping
+ const basegfx::B2DPolyPolygon aAndPolyPolygon(
+ basegfx::utils::solvePolygonOperationAnd(
+ aExtrudePoly,
+ rAct.maPreparedPolyPolygon));
+
+ if(aAndPolyPolygon.count() != 0)
+ {
+ // second criteria: is another fillstyle or color used?
+ const SfxItemSet& rCompareSet = rAct.mpObj->GetMergedItemSet();
+
+ drawing::FillStyle eCompareFillStyle = rCompareSet.Get(XATTR_FILLSTYLE).GetValue();
+
+ if(eLocalFillStyle == eCompareFillStyle)
+ {
+ if(eLocalFillStyle == drawing::FillStyle_SOLID)
+ {
+ Color aCompareColor = rCompareSet.Get(XATTR_FILLCOLOR).GetColorValue();
+
+ if(aCompareColor == aLocalColor)
+ {
+ continue;
+ }
+ }
+ else if(eLocalFillStyle == drawing::FillStyle_NONE)
+ {
+ continue;
+ }
+ }
+
+ bOverlap = true;
+ break;
+ }
+ }
+
+ if(bOverlap)
+ {
+ // yes, start a new layer
+ pLayer->mpDown = new E3dDepthLayer;
+ pLayer = pLayer->mpDown;
+ nNumLayers++;
+ pLayer->mvNeighbours.emplace_back(pExtrudeObj, aExtrudePoly);
+ }
+ else
+ {
+ // no, add to current layer
+ pLayer->mvNeighbours.emplace(pLayer->mvNeighbours.begin(), pExtrudeObj, aExtrudePoly);
+ }
+ }
+ else
+ {
+ // first layer ever
+ pBaseLayer = new E3dDepthLayer;
+ pLayer = pBaseLayer;
+ nNumLayers++;
+ pLayer->mvNeighbours.emplace_back(pExtrudeObj, aExtrudePoly);
+ }
+ }
+ }
+
+ // number of layers is done
+ if(nNumLayers > 1)
+ {
+ // need to be arranged
+ double fMinDepth = fDepth * 0.8;
+ double fStep = (fDepth - fMinDepth) / static_cast<double>(nNumLayers);
+ pLayer = pBaseLayer;
+
+ while(pLayer)
+ {
+ // move along layer
+ for(auto& rAct : pLayer->mvNeighbours)
+ {
+ // adapt extrude value
+ rAct.mpObj->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH, sal_uInt32(fMinDepth + 0.5)));
+ }
+
+ // next layer
+ pLayer = pLayer->mpDown;
+ fMinDepth += fStep;
+ }
+ }
+
+ // cleanup
+ while(pBaseLayer)
+ {
+ pLayer = pBaseLayer->mpDown;
+ delete pBaseLayer;
+ pBaseLayer = pLayer;
+ }
+ }
+}
+
+// Start drag, create for 3D objects before possibly drag method
+
+bool E3dView::BegDragObj(const Point& rPnt, OutputDevice* pOut,
+ SdrHdl* pHdl, short nMinMov,
+ SdrDragMethod* pForcedMeth)
+{
+ if(Is3DRotationCreationActive() && GetMarkedObjectCount())
+ {
+ // Determine all selected polygons and return the mirrored helper overlay
+ mpMirrorOverlay->SetMirrorAxis(maRef1, maRef2);
+ }
+ else
+ {
+ bool bOwnActionNecessary;
+ if (pHdl == nullptr)
+ {
+ bOwnActionNecessary = true;
+ }
+ else if (pHdl->IsVertexHdl() || pHdl->IsCornerHdl())
+ {
+ bOwnActionNecessary = true;
+ }
+ else
+ {
+ bOwnActionNecessary = false;
+ }
+
+ if(bOwnActionNecessary && GetMarkedObjectCount() > 0)
+ {
+ E3dDragConstraint eConstraint = E3dDragConstraint::XYZ;
+ bool bThereAreRootScenes = false;
+ bool bThereAre3DObjects = false;
+ const size_t nCnt = GetMarkedObjectCount();
+ for(size_t nObjs = 0; nObjs < nCnt; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(pObj)
+ {
+ if(nullptr != dynamic_cast< const E3dScene* >(pObj) && static_cast< E3dScene* >(pObj)->getRootE3dSceneFromE3dObject() == pObj)
+ {
+ bThereAreRootScenes = true;
+ }
+
+ if(dynamic_cast< const E3dObject* >(pObj) != nullptr)
+ {
+ bThereAre3DObjects = true;
+ }
+ }
+ }
+ if( bThereAre3DObjects )
+ {
+ meDragHdl = ( pHdl == nullptr ? SdrHdlKind::Move : pHdl->GetKind() );
+ switch ( meDragMode )
+ {
+ case SdrDragMode::Rotate:
+ case SdrDragMode::Shear:
+ {
+ switch ( meDragHdl )
+ {
+ case SdrHdlKind::Left:
+ case SdrHdlKind::Right:
+ {
+ eConstraint = E3dDragConstraint::X;
+ }
+ break;
+
+ case SdrHdlKind::Upper:
+ case SdrHdlKind::Lower:
+ {
+ eConstraint = E3dDragConstraint::Y;
+ }
+ break;
+
+ case SdrHdlKind::UpperLeft:
+ case SdrHdlKind::UpperRight:
+ case SdrHdlKind::LowerLeft:
+ case SdrHdlKind::LowerRight:
+ {
+ eConstraint = E3dDragConstraint::Z;
+ }
+ break;
+ default: break;
+ }
+
+ // do not mask the allowed rotations
+ eConstraint &= E3dDragConstraint::XYZ;
+ pForcedMeth = new E3dDragRotate(*this, GetMarkedObjectList(), eConstraint, IsSolidDragging());
+ }
+ break;
+
+ case SdrDragMode::Move:
+ {
+ if(!bThereAreRootScenes)
+ {
+ pForcedMeth = new E3dDragMove(*this, GetMarkedObjectList(), meDragHdl, eConstraint, IsSolidDragging());
+ }
+ }
+ break;
+
+ // later on
+ case SdrDragMode::Mirror:
+ case SdrDragMode::Crook:
+ case SdrDragMode::Transparence:
+ case SdrDragMode::Gradient:
+ default:
+ {
+ }
+ break;
+ }
+ }
+ }
+ }
+ return SdrView::BegDragObj(rPnt, pOut, pHdl, nMinMov, pForcedMeth);
+}
+
+// Set current 3D drawing object, create the scene for this
+E3dScene* E3dView::SetCurrent3DObj(E3dObject* p3DObj)
+{
+ DBG_ASSERT(p3DObj != nullptr, "Who puts in a NULL-pointer here");
+
+ // get transformed BoundVolume of the object
+ basegfx::B3DRange aVolume(p3DObj->GetBoundVolume());
+ aVolume.transform(p3DObj->GetTransform());
+ double fW(aVolume.getWidth());
+ double fH(aVolume.getHeight());
+
+ tools::Rectangle aRect(0,0, static_cast<long>(fW), static_cast<long>(fH));
+
+ E3dScene* pScene = new E3dScene(p3DObj->getSdrModelFromSdrObject());
+
+ InitScene(pScene, fW, fH, aVolume.getMaxZ() + ((fW + fH) / 4.0));
+
+ pScene->InsertObject(p3DObj);
+ pScene->NbcSetSnapRect(aRect);
+
+ return pScene;
+}
+
+void E3dView::InitScene(E3dScene* pScene, double fW, double fH, double fCamZ)
+{
+ Camera3D aCam(pScene->GetCamera());
+
+ aCam.SetAutoAdjustProjection(false);
+ aCam.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
+ basegfx::B3DPoint aLookAt;
+
+ double fDefaultCamPosZ = GetDefaultCamPosZ();
+ basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
+
+ aCam.SetPosAndLookAt(aCamPos, aLookAt);
+ aCam.SetFocalLength(GetDefaultCamFocal());
+ pScene->SetCamera(aCam);
+}
+
+void E3dView::Start3DCreation()
+{
+ if (!GetMarkedObjectCount())
+ return;
+
+ //positioned
+ long nOutMin = 0;
+ long nOutMax = 0;
+ long nMinLen = 0;
+ long nObjDst = 0;
+ long nOutHgt = 0;
+ OutputDevice* pOut = GetFirstOutputDevice();
+
+ // first determine representation boundaries
+ if (pOut != nullptr)
+ {
+ nMinLen = pOut->PixelToLogic(Size(0,50)).Height();
+ nObjDst = pOut->PixelToLogic(Size(0,20)).Height();
+
+ long nDst = pOut->PixelToLogic(Size(0,10)).Height();
+
+ nOutMin = -pOut->GetMapMode().GetOrigin().Y();
+ nOutMax = pOut->GetOutputSize().Height() - 1 + nOutMin;
+ nOutMin += nDst;
+ nOutMax -= nDst;
+
+ if (nOutMax - nOutMin < nDst)
+ {
+ nOutMin += nOutMax + 1;
+ nOutMin /= 2;
+ nOutMin -= (nDst + 1) / 2;
+ nOutMax = nOutMin + nDst;
+ }
+
+ nOutHgt = nOutMax - nOutMin;
+
+ long nTemp = nOutHgt / 4;
+ if (nTemp > nMinLen) nMinLen = nTemp;
+ }
+
+ // and then attach the marks at the top and bottom of the object
+ basegfx::B2DRange aR;
+ for(size_t nMark = 0; nMark < GetMarkedObjectCount(); ++nMark)
+ {
+ SdrObject* pMark = GetMarkedObjectByIndex(nMark);
+ basegfx::B2DPolyPolygon aXPP(pMark->TakeXorPoly());
+ aR.expand(basegfx::utils::getRange(aXPP));
+ }
+
+ basegfx::B2DPoint aCenter(aR.getCenter());
+ long nMarkHgt = basegfx::fround(aR.getHeight()) - 1;
+ long nHgt = nMarkHgt + nObjDst * 2;
+
+ if (nHgt < nMinLen) nHgt = nMinLen;
+
+ long nY1 = basegfx::fround(aCenter.getY()) - (nHgt + 1) / 2;
+ long nY2 = nY1 + nHgt;
+
+ if (pOut && (nMinLen > nOutHgt)) nMinLen = nOutHgt;
+ if (pOut)
+ {
+ if (nY1 < nOutMin)
+ {
+ nY1 = nOutMin;
+ if (nY2 < nY1 + nMinLen) nY2 = nY1 + nMinLen;
+ }
+ if (nY2 > nOutMax)
+ {
+ nY2 = nOutMax;
+ if (nY1 > nY2 - nMinLen) nY1 = nY2 - nMinLen;
+ }
+ }
+
+ maRef1.setX( basegfx::fround(aR.getMinX()) ); // Initial move axis 2/100mm to the left
+ maRef1.setY( nY1 );
+ maRef2.setX( maRef1.X() );
+ maRef2.setY( nY2 );
+
+ // Turn on marks
+ SetMarkHandles(nullptr);
+
+ //HMHif (bVis) ShowMarkHdl();
+ if (AreObjectsMarked()) MarkListHasChanged();
+
+ // Show mirror polygon IMMEDIATELY
+ const SdrHdlList &aHdlList = GetHdlList();
+ mpMirrorOverlay.reset(new Impl3DMirrorConstructOverlay(*this));
+ mpMirrorOverlay->SetMirrorAxis(aHdlList.GetHdl(SdrHdlKind::Ref1)->GetPos(), aHdlList.GetHdl(SdrHdlKind::Ref2)->GetPos());
+}
+
+// what happens with a mouse movement when the object is created?
+
+void E3dView::MovAction(const Point& rPnt)
+{
+ if(Is3DRotationCreationActive())
+ {
+ SdrHdl* pHdl = GetDragHdl();
+
+ if (pHdl)
+ {
+ SdrHdlKind eHdlKind = pHdl->GetKind();
+
+ // reacts only due to a mirror axis
+ if ((eHdlKind == SdrHdlKind::Ref1) ||
+ (eHdlKind == SdrHdlKind::Ref2) ||
+ (eHdlKind == SdrHdlKind::MirrorAxis))
+ {
+ const SdrHdlList &aHdlList = GetHdlList ();
+
+ // delete the mirrored polygon, mirrors the original and draws
+ // it anew
+ SdrView::MovAction (rPnt);
+ mpMirrorOverlay->SetMirrorAxis(
+ aHdlList.GetHdl (SdrHdlKind::Ref1)->GetPos(),
+ aHdlList.GetHdl (SdrHdlKind::Ref2)->GetPos());
+ }
+ }
+ else
+ {
+ SdrView::MovAction (rPnt);
+ }
+ }
+ else
+ {
+ SdrView::MovAction (rPnt);
+ }
+}
+
+// The End. Create object and any child objects through ImpCreate3DLathe.
+// With the parameter value sal_True (SDefault: sal_False) is simply a
+// rotation body created, without letting the user set the position of the
+// axis. It is sufficient with this call, if an object is selected.
+// (No initialization necessary)
+
+void E3dView::End3DCreation(bool bUseDefaultValuesForMirrorAxes)
+{
+ ResetCreationActive();
+
+ if(AreObjectsMarked())
+ {
+ if(bUseDefaultValuesForMirrorAxes)
+ {
+ tools::Rectangle aRect = GetAllMarkedRect();
+ if(aRect.GetWidth() <= 1)
+ aRect.SetSize(Size(500, aRect.GetHeight()));
+ if(aRect.GetHeight() <= 1)
+ aRect.SetSize(Size(aRect.GetWidth(), 500));
+
+ basegfx::B2DPoint aPnt1(aRect.Left(), -aRect.Top());
+ basegfx::B2DPoint aPnt2(aRect.Left(), -aRect.Bottom());
+
+ ConvertMarkedObjTo3D(false, aPnt1, aPnt2);
+ }
+ else
+ {
+ // Turn off helper overlay
+ // Determine from the handle positions and the displacement of
+ // the points
+ const SdrHdlList &aHdlList = GetHdlList();
+ Point aMirrorRef1 = aHdlList.GetHdl(SdrHdlKind::Ref1)->GetPos();
+ Point aMirrorRef2 = aHdlList.GetHdl(SdrHdlKind::Ref2)->GetPos();
+
+ basegfx::B2DPoint aPnt1(aMirrorRef1.X(), -aMirrorRef1.Y());
+ basegfx::B2DPoint aPnt2(aMirrorRef2.X(), -aMirrorRef2.Y());
+
+ ConvertMarkedObjTo3D(false, aPnt1, aPnt2);
+ }
+ }
+}
+
+E3dView::~E3dView ()
+{
+}
+
+void E3dView::ResetCreationActive ()
+{
+ mpMirrorOverlay.reset();
+}
+
+void E3dView::InitView ()
+{
+ mpMirrorOverlay = nullptr;
+}
+
+bool E3dView::IsBreak3DObjPossible() const
+{
+ const size_t nCount = GetMarkedObjectCount();
+
+ if (nCount > 0)
+ {
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(i);
+
+ if (auto p3dObject = dynamic_cast< E3dObject* >(pObj))
+ {
+ if(!p3dObject->IsBreakObjPossible())
+ return false;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void E3dView::Break3DObj()
+{
+ if(IsBreak3DObjPossible())
+ {
+ // ALL selected objects are changed
+ const size_t nCount = GetMarkedObjectCount();
+
+ BegUndo(SvxResId(RID_SVX_3D_UNDO_BREAK_LATHE));
+ for(size_t a=0; a<nCount; ++a)
+ {
+ E3dObject* pObj = static_cast<E3dObject*>(GetMarkedObjectByIndex(a));
+ BreakSingle3DObj(pObj);
+ }
+ DeleteMarked();
+ EndUndo();
+ }
+}
+
+void E3dView::BreakSingle3DObj(E3dObject* pObj)
+{
+ if(dynamic_cast< const E3dScene* >(pObj) != nullptr)
+ {
+ SdrObjList* pSubList = pObj->GetSubList();
+ SdrObjListIter aIter(pSubList, SdrIterMode::Flat);
+
+ while(aIter.IsMore())
+ {
+ E3dObject* pSubObj = static_cast<E3dObject*>(aIter.Next());
+ BreakSingle3DObj(pSubObj);
+ }
+ }
+ else
+ {
+ SdrAttrObj* pNewObj = pObj->GetBreakObj().release();
+ if (pNewObj)
+ {
+ if (InsertObjectAtView(pNewObj, *GetSdrPageView(), SdrInsertFlags::DONTMARK))
+ {
+ pNewObj->SetChanged();
+ pNewObj->BroadcastObjectChange();
+ }
+ }
+ }
+}
+
+void E3dView::CheckPossibilities()
+{
+ // call parent
+ SdrView::CheckPossibilities();
+
+ // Set other flags
+ if(m_bGroupPossible || m_bUnGroupPossible || m_bGrpEnterPossible)
+ {
+ const size_t nMarkCnt = GetMarkedObjectCount();
+ bool bCoumpound = false;
+ bool b3DObject = false;
+ for(size_t nObjs = 0; (nObjs < nMarkCnt) && !bCoumpound; ++nObjs)
+ {
+ SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
+ if(dynamic_cast< const E3dCompoundObject* >(pObj))
+ bCoumpound = true;
+ if(dynamic_cast< const E3dObject* >(pObj))
+ b3DObject = true;
+ }
+
+ // So far: there are two or more of any objects selected. See if
+ // compound objects are involved. If yes, ban grouping.
+ if(m_bGroupPossible && bCoumpound)
+ m_bGroupPossible = false;
+
+ if(m_bUnGroupPossible && b3DObject)
+ m_bUnGroupPossible = false;
+
+ if(m_bGrpEnterPossible && bCoumpound)
+ m_bGrpEnterPossible = false;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/view3d1.cxx b/svx/source/engine3d/view3d1.cxx
new file mode 100644
index 000000000..7f0acf713
--- /dev/null
+++ b/svx/source/engine3d/view3d1.cxx
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <svx/svdpool.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svxids.hrc>
+#include <svx/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/lathe3d.hxx>
+#include <svx/scene3d.hxx>
+#include <svx/sphere3d.hxx>
+#include <extrud3d.hxx>
+#include <svx/view3d.hxx>
+#include <svx/cube3d.hxx>
+#include <svx/xlineit0.hxx>
+#include <com/sun/star/drawing/LineStyle.hpp>
+
+void E3dView::ConvertMarkedToPolyObj()
+{
+ SdrObject* pNewObj = nullptr;
+
+ if (GetMarkedObjectCount() == 1)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(0);
+
+ if (pObj)
+ {
+ auto pScene = dynamic_cast< const E3dScene* >(pObj);
+ if (pScene)
+ {
+ pNewObj = pScene->ConvertToPolyObj(false/*bBezier*/, false/*bLineToArea*/).release();
+ if (pNewObj)
+ {
+ BegUndo(SvxResId(RID_SVX_3D_UNDO_EXTRUDE));
+ ReplaceObjectAtView(pObj, *GetSdrPageView(), pNewObj);
+ EndUndo();
+ }
+ }
+ }
+ }
+
+ if (!pNewObj)
+ {
+ SdrView::ConvertMarkedToPolyObj();
+ }
+}
+
+static void Imp_E3dView_InorderRun3DObjects(const SdrObject* pObj, sal_uInt32& rMask)
+{
+ if(dynamic_cast< const E3dLatheObj* >(pObj) != nullptr)
+ {
+ rMask |= 0x0001;
+ }
+ else if(dynamic_cast< const E3dExtrudeObj* >(pObj) != nullptr)
+ {
+ rMask |= 0x0002;
+ }
+ else if(dynamic_cast< const E3dSphereObj* >(pObj) != nullptr)
+ {
+ rMask |= 0x0004;
+ }
+ else if(dynamic_cast< const E3dCubeObj* >(pObj) != nullptr)
+ {
+ rMask |= 0x0008;
+ }
+ else if(pObj->IsGroupObject())
+ {
+ SdrObjList* pList = pObj->GetSubList();
+ for(size_t a = 0; a < pList->GetObjCount(); ++a)
+ Imp_E3dView_InorderRun3DObjects(pList->GetObj(a), rMask);
+ }
+}
+
+SfxItemSet E3dView::Get3DAttributes() const
+{
+ // Creating itemset with corresponding field
+ SfxItemSet aSet(
+ mpModel->GetItemPool(),
+ svl::Items<SDRATTR_START, SDRATTR_END,
+ SID_ATTR_3D_INTERN, SID_ATTR_3D_INTERN>{});
+
+ sal_uInt32 nSelectedItems(0);
+
+ // get attributes from all selected objects
+ MergeAttrFromMarked(aSet, false);
+
+ // calc flags for SID_ATTR_3D_INTERN
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ const size_t nMarkCnt(rMarkList.GetMarkCount());
+
+ for(size_t a = 0; a < nMarkCnt; ++a)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(a);
+ Imp_E3dView_InorderRun3DObjects(pObj, nSelectedItems);
+ }
+
+ // Set SID_ATTR_3D_INTERN on the status of the selected objects
+ aSet.Put(SfxUInt32Item(SID_ATTR_3D_INTERN, nSelectedItems));
+
+ // maintain default values
+ if(!nSelectedItems)
+ {
+ // Get defaults and apply
+ SfxItemSet aDefaultSet(mpModel->GetItemPool(), svl::Items<SDRATTR_3D_FIRST, SDRATTR_3D_LAST>{});
+ GetAttributes(aDefaultSet);
+ aSet.Put(aDefaultSet);
+
+ // ... but no lines for 3D
+ aSet.Put(XLineStyleItem (css::drawing::LineStyle_NONE));
+
+ // new defaults for distance and focal length
+ aSet.Put(makeSvx3DDistanceItem(100));
+ aSet.Put(makeSvx3DFocalLengthItem(10000));
+ }
+
+ // return ItemSet
+ return aSet;
+}
+
+void E3dView::Set3DAttributes( const SfxItemSet& rAttr)
+{
+ sal_uInt32 nSelectedItems(0);
+
+ // #i94832# removed usage of E3DModifySceneSnapRectUpdater here.
+ // They are not needed here, they are already handled in SetAttrToMarked
+
+ // set at selected objects
+ SetAttrToMarked(rAttr, false/*bReplaceAll*/);
+
+ // old run
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ const size_t nMarkCnt(rMarkList.GetMarkCount());
+
+ for(size_t a = 0; a < nMarkCnt; ++a)
+ {
+ SdrObject* pObj = GetMarkedObjectByIndex(a);
+ Imp_E3dView_InorderRun3DObjects(pObj, nSelectedItems);
+ }
+
+ // Maintain default values
+ if(!nSelectedItems)
+ {
+ // Set defaults
+ SfxItemSet aDefaultSet(mpModel->GetItemPool(), svl::Items<SDRATTR_3D_FIRST, SDRATTR_3D_LAST>{});
+ aDefaultSet.Put(rAttr);
+ SetAttributes(aDefaultSet);
+ }
+}
+
+double E3dView::GetDefaultCamPosZ()
+{
+ return static_cast<double>(mpModel->GetItemPool().GetDefaultItem(SDRATTR_3DSCENE_DISTANCE).GetValue());
+}
+
+double E3dView::GetDefaultCamFocal()
+{
+ return static_cast<double>(mpModel->GetItemPool().GetDefaultItem(SDRATTR_3DSCENE_FOCAL_LENGTH).GetValue());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/engine3d/viewpt3d2.cxx b/svx/source/engine3d/viewpt3d2.cxx
new file mode 100644
index 000000000..660af6adf
--- /dev/null
+++ b/svx/source/engine3d/viewpt3d2.cxx
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/viewpt3d.hxx>
+
+Viewport3D::Viewport3D() :
+ aVRP(0, 0, 5),
+ aVPN(0, 0, 1),
+ aVUV(0, 1, 1),
+ aPRP(0, 0, 2),
+ eProjection(ProjectionType::Perspective),
+ aDeviceRect(Point(0,0), Size(-1,-1)),
+ aViewPoint (0, 0, 5000),
+ bTfValid(false)
+{
+ aViewWin.X = -1; aViewWin.Y = -1;
+ aViewWin.W = 2; aViewWin.H = 2;
+}
+
+// Set ViewWindow (in View coordinates)
+
+void Viewport3D::SetViewWindow(double fX, double fY, double fW, double fH)
+{
+ aViewWin.X = fX;
+ aViewWin.Y = fY;
+ if ( fW > 0 ) aViewWin.W = fW;
+ else aViewWin.W = 1.0;
+ if ( fH > 0 ) aViewWin.H = fH;
+ else aViewWin.H = 1.0;
+}
+
+// Returns observer position (PRP) in world coordinates
+
+const basegfx::B3DPoint& Viewport3D::GetViewPoint()
+{
+ // Calculate View transformations matrix
+ if ( !bTfValid )
+ {
+ double fV, fXupVp, fYupVp;
+ aViewPoint = aVRP + aVPN * aPRP.getZ();
+
+ // Reset to Identity matrix
+ aViewTf.identity();
+
+ // shift in the origin
+ aViewTf.translate(-aVRP.getX(), -aVRP.getY(), -aVRP.getZ());
+
+ // fV = Length of the projection of aVPN on the yz plane:
+ fV = aVPN.getYZLength();
+
+ if ( fV != 0 )
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(aVPN.getY() / fV);
+ const double fCos(aVPN.getZ() / fV);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(1, 1, fCos);
+ aTemp.set(2, 1, fSin);
+ aTemp.set(1, 2, -fSin);
+ aViewTf *= aTemp;
+ }
+
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(-aVPN.getX());
+ const double fCos(fV);
+ aTemp.set(2, 2, fCos);
+ aTemp.set(0, 0, fCos);
+ aTemp.set(0, 2, fSin);
+ aTemp.set(2, 0, -fSin);
+ aViewTf *= aTemp;
+ }
+
+ // Convert X- and Y- coordinates of the view up vector to the
+ // (preliminary) view coordinate system.
+ fXupVp = aViewTf.get(0, 0) * aVUV.getX() + aViewTf.get(0, 1) * aVUV.getY() + aViewTf.get(0, 2) * aVUV.getZ();
+ fYupVp = aViewTf.get(1, 0) * aVUV.getX() + aViewTf.get(1, 1) * aVUV.getY() + aViewTf.get(1, 2) * aVUV.getZ();
+ fV = sqrt(fXupVp * fXupVp + fYupVp * fYupVp);
+
+ if ( fV != 0 )
+ {
+ basegfx::B3DHomMatrix aTemp;
+ const double fSin(fXupVp / fV);
+ const double fCos(fYupVp / fV);
+ aTemp.set(1, 1, fCos);
+ aTemp.set(0, 0, fCos);
+ aTemp.set(1, 0, fSin);
+ aTemp.set(0, 1, -fSin);
+ aViewTf *= aTemp;
+ }
+
+ bTfValid = true;
+ }
+ return aViewPoint;
+}
+
+void Viewport3D::SetDeviceWindow(const tools::Rectangle& rRect)
+{
+ aDeviceRect = rRect;
+}
+
+// Set View Reference Point
+
+void Viewport3D::SetVRP(const basegfx::B3DPoint& rNewVRP)
+{
+ aVRP = rNewVRP;
+ bTfValid = false;
+}
+
+// Set View Plane Normal
+
+void Viewport3D::SetVPN(const basegfx::B3DVector& rNewVPN)
+{
+ aVPN = rNewVPN;
+ aVPN.normalize();
+ bTfValid = false;
+}
+
+// Set View Up Vector
+
+void Viewport3D::SetVUV(const basegfx::B3DVector& rNewVUV)
+{
+ aVUV = rNewVUV;
+ bTfValid = false;
+}
+
+// Set Center Of Projection
+
+void Viewport3D::SetPRP(const basegfx::B3DPoint& rNewPRP)
+{
+ aPRP = rNewPRP;
+ aPRP.setX(0.0);
+ aPRP.setY(0.0);
+ bTfValid = false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */