1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_drawinglayer.hxx"
30 
31 #include <drawinglayer/primitive3d/sdrsphereprimitive3d.hxx>
32 #include <basegfx/polygon/b3dpolypolygontools.hxx>
33 #include <basegfx/matrix/b2dhommatrix.hxx>
34 #include <basegfx/polygon/b3dpolygon.hxx>
35 #include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx>
36 #include <basegfx/tools/canvastools.hxx>
37 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
38 #include <drawinglayer/attribute/sdrfillattribute.hxx>
39 #include <drawinglayer/attribute/sdrlineattribute.hxx>
40 #include <drawinglayer/attribute/sdrshadowattribute.hxx>
41 
42 //////////////////////////////////////////////////////////////////////////////
43 
44 using namespace com::sun::star;
45 
46 //////////////////////////////////////////////////////////////////////////////
47 
48 namespace drawinglayer
49 {
50 	namespace primitive3d
51 	{
52 		Primitive3DSequence SdrSpherePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& /*rViewInformation*/) const
53 		{
54 			Primitive3DSequence aRetval;
55 			const basegfx::B3DRange aUnitRange(0.0, 0.0, 0.0, 1.0, 1.0, 1.0);
56 			const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == getSdr3DObjectAttribute().getNormalsKind()
57 				|| ::com::sun::star::drawing::NormalsKind_SPHERE == getSdr3DObjectAttribute().getNormalsKind());
58 
59 			// create unit geometry
60 			basegfx::B3DPolyPolygon aFill(basegfx::tools::createSphereFillPolyPolygonFromB3DRange(aUnitRange,
61 				getHorizontalSegments(), getVerticalSegments(), bCreateNormals));
62 
63 			// normal inversion
64 			if(!getSdrLFSAttribute().getFill().isDefault()
65 				&& bCreateNormals
66 				&& getSdr3DObjectAttribute().getNormalsInvert()
67 				&& aFill.areNormalsUsed())
68 			{
69 				// invert normals
70 				aFill = basegfx::tools::invertNormals(aFill);
71 			}
72 
73 			// texture coordinates
74 			if(!getSdrLFSAttribute().getFill().isDefault())
75 			{
76 				// handle texture coordinates X
77 				const bool bParallelX(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionX());
78 				const bool bObjectSpecificX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX());
79 				const bool bSphereX(::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionX());
80 
81 				// handle texture coordinates Y
82 				const bool bParallelY(::com::sun::star::drawing::TextureProjectionMode_PARALLEL == getSdr3DObjectAttribute().getTextureProjectionY());
83 				const bool bObjectSpecificY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY());
84 				const bool bSphereY(::com::sun::star::drawing::TextureProjectionMode_SPHERE == getSdr3DObjectAttribute().getTextureProjectionY());
85 
86 				if(bParallelX || bParallelY)
87 				{
88 					// apply parallel texture coordinates in X and/or Y
89 					const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill));
90 					aFill = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFill, aRange, bParallelX, bParallelY);
91 				}
92 
93 				if(bSphereX || bObjectSpecificX || bSphereY || bObjectSpecificY)
94 				{
95 					double fRelativeAngle(0.0);
96 
97 					if(bObjectSpecificX)
98 					{
99 						// Since the texture coordinates are (for historical reasons)
100 						// different from forced to sphere texture coordinates,
101 						// create a old version from it by rotating to old state before applying
102 						// the texture coordinates to emulate old behaviour
103 						fRelativeAngle = F_2PI * ((double)((getHorizontalSegments() >> 1L)  - 1L) / (double)getHorizontalSegments());
104 						basegfx::B3DHomMatrix aRot;
105 						aRot.rotate(0.0, fRelativeAngle, 0.0);
106 						aFill.transform(aRot);
107 					}
108 
109 					// apply spherical texture coordinates in X and/or Y
110 					const basegfx::B3DRange aRange(basegfx::tools::getRange(aFill));
111 					const basegfx::B3DPoint aCenter(aRange.getCenter());
112 					aFill = basegfx::tools::applyDefaultTextureCoordinatesSphere(aFill, aCenter,
113 						bSphereX || bObjectSpecificX, bSphereY || bObjectSpecificY);
114 
115 					if(bObjectSpecificX)
116 					{
117 						// rotate back again
118 						basegfx::B3DHomMatrix aRot;
119 						aRot.rotate(0.0, -fRelativeAngle, 0.0);
120 						aFill.transform(aRot);
121 					}
122 				}
123 
124 				// transform texture coordinates to texture size
125 				basegfx::B2DHomMatrix aTexMatrix;
126 				aTexMatrix.scale(getTextureSize().getX(), getTextureSize().getY());
127 				aFill.transformTextureCoordiantes(aTexMatrix);
128 			}
129 
130 			// build vector of PolyPolygons
131 			::std::vector< basegfx::B3DPolyPolygon > a3DPolyPolygonVector;
132 
133 			for(sal_uInt32 a(0L); a < aFill.count(); a++)
134 			{
135 				a3DPolyPolygonVector.push_back(basegfx::B3DPolyPolygon(aFill.getB3DPolygon(a)));
136 			}
137 
138 			if(!getSdrLFSAttribute().getFill().isDefault())
139 			{
140 				// add fill
141 				aRetval = create3DPolyPolygonFillPrimitives(
142 					a3DPolyPolygonVector,
143 					getTransform(),
144 					getTextureSize(),
145 					getSdr3DObjectAttribute(),
146 					getSdrLFSAttribute().getFill(),
147 					getSdrLFSAttribute().getFillFloatTransGradient());
148 			}
149 			else
150 			{
151 				// create simplified 3d hit test geometry
152                 aRetval = createHiddenGeometryPrimitives3D(
153 			        a3DPolyPolygonVector,
154 			        getTransform(),
155 			        getTextureSize(),
156 			        getSdr3DObjectAttribute());
157 			}
158 
159 			// add line
160 			if(!getSdrLFSAttribute().getLine().isDefault())
161 			{
162 				basegfx::B3DPolyPolygon aSphere(basegfx::tools::createSpherePolyPolygonFromB3DRange(aUnitRange, getHorizontalSegments(), getVerticalSegments()));
163 				const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives(
164                     aSphere, getTransform(), getSdrLFSAttribute().getLine()));
165 				appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines);
166 			}
167 
168 			// add shadow
169 			if(!getSdrLFSAttribute().getShadow().isDefault()
170                 && aRetval.hasElements())
171 			{
172 				const Primitive3DSequence aShadow(createShadowPrimitive3D(
173                     aRetval, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D()));
174 				appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow);
175 			}
176 
177 			return aRetval;
178 		}
179 
180 		SdrSpherePrimitive3D::SdrSpherePrimitive3D(
181 			const basegfx::B3DHomMatrix& rTransform,
182 			const basegfx::B2DVector& rTextureSize,
183 			const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute,
184 			const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute,
185 			sal_uInt32 nHorizontalSegments,
186 			sal_uInt32 nVerticalSegments)
187 		:	SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute),
188 			mnHorizontalSegments(nHorizontalSegments),
189 			mnVerticalSegments(nVerticalSegments)
190 		{
191 		}
192 
193 		bool SdrSpherePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const
194 		{
195 			if(SdrPrimitive3D::operator==(rPrimitive))
196 			{
197 				const SdrSpherePrimitive3D& rCompare = static_cast< const SdrSpherePrimitive3D& >(rPrimitive);
198 
199 				return (getHorizontalSegments() == rCompare.getHorizontalSegments()
200 					&& getVerticalSegments() == rCompare.getVerticalSegments());
201 			}
202 
203 			return false;
204 		}
205 
206 		basegfx::B3DRange SdrSpherePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const
207 		{
208 			// use defaut from sdrPrimitive3D which uses transformation expanded by line width/2
209 			// The parent implementation which uses the ranges of the decomposition would be more
210 			// corrcet, but for historical reasons it is necessary to do the old method: To get
211 			// the range of the non-transformed geometry and transform it then. This leads to different
212 			// ranges where the new method is more correct, but the need to keep the old behaviour
213 			// has priority here.
214 			return getStandard3DRange();
215 		}
216 
217 		// provide unique ID
218 		ImplPrimitrive3DIDBlock(SdrSpherePrimitive3D, PRIMITIVE3D_ID_SDRSPHEREPRIMITIVE3D)
219 
220 	} // end of namespace primitive3d
221 } // end of namespace drawinglayer
222 
223 //////////////////////////////////////////////////////////////////////////////
224 // eof
225