Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <drawinglayer/processor3d/shadow3dextractor.hxx>
21 : #include <drawinglayer/primitive3d/shadowprimitive3d.hxx>
22 : #include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
23 : #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
24 : #include <drawinglayer/primitive3d/transformprimitive3d.hxx>
25 : #include <drawinglayer/primitive3d/polygonprimitive3d.hxx>
26 : #include <basegfx/polygon/b2dpolygontools.hxx>
27 : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
28 : #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx>
29 : #include <basegfx/polygon/b2dpolypolygontools.hxx>
30 : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
31 : #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
32 :
33 :
34 :
35 : using namespace com::sun::star;
36 :
37 :
38 :
39 : namespace drawinglayer
40 : {
41 : namespace processor3d
42 : {
43 : // as tooling, the process() implementation takes over API handling and calls this
44 : // virtual render method when the primitive implementation is BasePrimitive3D-based.
45 46805 : void Shadow3DExtractingProcessor::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate)
46 : {
47 : // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch
48 46805 : switch(rCandidate.getPrimitive3DID())
49 : {
50 : case PRIMITIVE3D_ID_SHADOWPRIMITIVE3D :
51 : {
52 : // shadow3d object. Call recursive with content and start conversion
53 0 : const primitive3d::ShadowPrimitive3D& rPrimitive = static_cast< const primitive3d::ShadowPrimitive3D& >(rCandidate);
54 :
55 : // set new target
56 0 : primitive2d::Primitive2DVector aNewSubList;
57 0 : primitive2d::Primitive2DVector* pLastTargetSequence = mpPrimitive2DSequence;
58 0 : mpPrimitive2DSequence = &aNewSubList;
59 :
60 : // activate convert
61 0 : const bool bLastConvert(mbConvert);
62 0 : mbConvert = true;
63 :
64 : // set projection flag
65 0 : const bool bLastUseProjection(mbUseProjection);
66 0 : mbUseProjection = rPrimitive.getShadow3D();
67 :
68 : // process content
69 0 : process(rPrimitive.getChildren());
70 :
71 : // restore values
72 0 : mbUseProjection = bLastUseProjection;
73 0 : mbConvert = bLastConvert;
74 0 : mpPrimitive2DSequence = pLastTargetSequence;
75 :
76 : // create 2d shadow primitive with result. This also fetches all entries
77 : // from aNewSubList, so there is no need to delete them
78 : primitive2d::BasePrimitive2D* pNew = new primitive2d::ShadowPrimitive2D(
79 : rPrimitive.getShadowTransform(),
80 : rPrimitive.getShadowColor(),
81 0 : primitive2d::Primitive2DVectorToPrimitive2DSequence(aNewSubList));
82 :
83 0 : if(basegfx::fTools::more(rPrimitive.getShadowTransparence(), 0.0))
84 : {
85 : // create simpleTransparencePrimitive, add created primitives
86 0 : const primitive2d::Primitive2DReference xRef(pNew);
87 0 : const primitive2d::Primitive2DSequence aNewTransPrimitiveVector(&xRef, 1);
88 :
89 : pNew = new primitive2d::UnifiedTransparencePrimitive2D(
90 : aNewTransPrimitiveVector,
91 0 : rPrimitive.getShadowTransparence());
92 : }
93 :
94 0 : mpPrimitive2DSequence->push_back(pNew);
95 :
96 0 : break;
97 : }
98 : case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D :
99 : {
100 : // transform group. Remember current transformations
101 5634 : const primitive3d::TransformPrimitive3D& rPrimitive = static_cast< const primitive3d::TransformPrimitive3D& >(rCandidate);
102 5634 : const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D());
103 :
104 : // create new transformation; add new object transform from right side
105 : const geometry::ViewInformation3D aNewViewInformation3D(
106 11268 : aLastViewInformation3D.getObjectTransformation() * rPrimitive.getTransformation(),
107 5634 : aLastViewInformation3D.getOrientation(),
108 5634 : aLastViewInformation3D.getProjection(),
109 5634 : aLastViewInformation3D.getDeviceToView(),
110 : aLastViewInformation3D.getViewTime(),
111 16902 : aLastViewInformation3D.getExtendedInformationSequence());
112 5634 : updateViewInformation(aNewViewInformation3D);
113 :
114 5634 : if(mbShadowProjectionIsValid)
115 : {
116 : // update buffered WorldToEye and EyeToView
117 5634 : maWorldToEye = getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation();
118 5634 : maEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection();
119 : }
120 :
121 : // let break down
122 5634 : process(rPrimitive.getChildren());
123 :
124 : // restore transformations
125 5634 : updateViewInformation(aLastViewInformation3D);
126 :
127 5634 : if(mbShadowProjectionIsValid)
128 : {
129 : // update buffered WorldToEye and EyeToView
130 5634 : maWorldToEye = getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation();
131 5634 : maEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection();
132 : }
133 11268 : break;
134 : }
135 : case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D :
136 : {
137 : // PolygonHairlinePrimitive3D
138 1958 : if(mbConvert)
139 : {
140 0 : const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rCandidate);
141 0 : basegfx::B2DPolygon a2DHairline;
142 :
143 0 : if(mbUseProjection)
144 : {
145 0 : if(mbShadowProjectionIsValid)
146 : {
147 0 : a2DHairline = impDoShadowProjection(rPrimitive.getB3DPolygon());
148 : }
149 : }
150 : else
151 : {
152 0 : a2DHairline = basegfx::tools::createB2DPolygonFromB3DPolygon(rPrimitive.getB3DPolygon(), getViewInformation3D().getObjectToView());
153 : }
154 :
155 0 : if(a2DHairline.count())
156 : {
157 0 : a2DHairline.transform(getObjectTransformation());
158 : mpPrimitive2DSequence->push_back(
159 : new primitive2d::PolygonHairlinePrimitive2D(
160 : a2DHairline,
161 0 : maPrimitiveColor));
162 0 : }
163 : }
164 1958 : break;
165 : }
166 : case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D :
167 : {
168 : // PolyPolygonMaterialPrimitive3D
169 37973 : if(mbConvert)
170 : {
171 0 : const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rCandidate);
172 0 : basegfx::B2DPolyPolygon a2DFill;
173 :
174 0 : if(mbUseProjection)
175 : {
176 0 : if(mbShadowProjectionIsValid)
177 : {
178 0 : a2DFill = impDoShadowProjection(rPrimitive.getB3DPolyPolygon());
179 : }
180 : }
181 : else
182 : {
183 0 : a2DFill = basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(rPrimitive.getB3DPolyPolygon(), getViewInformation3D().getObjectToView());
184 : }
185 :
186 0 : if(a2DFill.count())
187 : {
188 0 : a2DFill.transform(getObjectTransformation());
189 : mpPrimitive2DSequence->push_back(
190 : new primitive2d::PolyPolygonColorPrimitive2D(
191 : a2DFill,
192 0 : maPrimitiveColor));
193 0 : }
194 : }
195 37973 : break;
196 : }
197 : default :
198 : {
199 : // process recursively
200 1240 : process(rCandidate.get3DDecomposition(getViewInformation3D()));
201 1240 : break;
202 : }
203 : }
204 46805 : }
205 :
206 15 : Shadow3DExtractingProcessor::Shadow3DExtractingProcessor(
207 : const geometry::ViewInformation3D& rViewInformation,
208 : const basegfx::B2DHomMatrix& rObjectTransformation,
209 : const basegfx::B3DVector& rLightNormal,
210 : double fShadowSlant,
211 : const basegfx::B3DRange& rContained3DRange)
212 : : BaseProcessor3D(rViewInformation),
213 : maPrimitive2DSequence(),
214 : mpPrimitive2DSequence(&maPrimitive2DSequence),
215 : maObjectTransformation(rObjectTransformation),
216 : maWorldToEye(),
217 : maEyeToView(),
218 : maLightNormal(rLightNormal),
219 : maShadowPlaneNormal(),
220 : maPlanePoint(),
221 : mfLightPlaneScalar(0.0),
222 : maPrimitiveColor(),
223 : mbShadowProjectionIsValid(false),
224 : mbConvert(false),
225 15 : mbUseProjection(false)
226 : {
227 : // normalize light normal, get and normalize shadow plane normal and calculate scalar from it
228 15 : maLightNormal.normalize();
229 15 : maShadowPlaneNormal = basegfx::B3DVector(0.0, sin(fShadowSlant), cos(fShadowSlant));
230 15 : maShadowPlaneNormal.normalize();
231 15 : mfLightPlaneScalar = maLightNormal.scalar(maShadowPlaneNormal);
232 :
233 : // use only when scalar is > 0.0, so the light is in front of the object
234 15 : if(basegfx::fTools::more(mfLightPlaneScalar, 0.0))
235 : {
236 : // prepare buffered WorldToEye and EyeToView
237 15 : maWorldToEye = getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation();
238 15 : maEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection();
239 :
240 : // calculate range to get front edge around which to rotate the shadow's projection
241 15 : basegfx::B3DRange aContained3DRange(rContained3DRange);
242 15 : aContained3DRange.transform(getWorldToEye());
243 15 : maPlanePoint.setX(maShadowPlaneNormal.getX() < 0.0 ? aContained3DRange.getMinX() : aContained3DRange.getMaxX());
244 15 : maPlanePoint.setY(maShadowPlaneNormal.getY() > 0.0 ? aContained3DRange.getMinY() : aContained3DRange.getMaxY());
245 15 : maPlanePoint.setZ(aContained3DRange.getMinZ() - (aContained3DRange.getDepth() / 8.0));
246 :
247 : // set flag that shadow projection is prepared and allowed
248 15 : mbShadowProjectionIsValid = true;
249 : }
250 15 : }
251 :
252 30 : Shadow3DExtractingProcessor::~Shadow3DExtractingProcessor()
253 : {
254 : OSL_ENSURE(0 == maPrimitive2DSequence.size(),
255 : "OOps, someone used Shadow3DExtractingProcessor, but did not fetch the results (!)");
256 15 : for(size_t a(0); a < maPrimitive2DSequence.size(); a++)
257 : {
258 0 : delete maPrimitive2DSequence[a];
259 : }
260 15 : }
261 :
262 0 : basegfx::B2DPolygon Shadow3DExtractingProcessor::impDoShadowProjection(const basegfx::B3DPolygon& rSource)
263 : {
264 0 : basegfx::B2DPolygon aRetval;
265 :
266 0 : for(sal_uInt32 a(0L); a < rSource.count(); a++)
267 : {
268 : // get point, transform to eye coordinate system
269 0 : basegfx::B3DPoint aCandidate(rSource.getB3DPoint(a));
270 0 : aCandidate *= getWorldToEye();
271 :
272 : // we are in eye coordinates
273 : // ray is (aCandidate + fCut * maLightNormal)
274 : // plane is (maPlanePoint, maShadowPlaneNormal)
275 : // maLightNormal.scalar(maShadowPlaneNormal) is already in mfLightPlaneScalar and > 0.0
276 : // get cut point of ray with shadow plane
277 0 : const double fCut(basegfx::B3DVector(maPlanePoint - aCandidate).scalar(maShadowPlaneNormal) / mfLightPlaneScalar);
278 0 : aCandidate += maLightNormal * fCut;
279 :
280 : // transform to view, use 2d coordinates
281 0 : aCandidate *= getEyeToView();
282 0 : aRetval.append(basegfx::B2DPoint(aCandidate.getX(), aCandidate.getY()));
283 0 : }
284 :
285 : // copy closed flag
286 0 : aRetval.setClosed(rSource.isClosed());
287 :
288 0 : return aRetval;
289 : }
290 :
291 0 : basegfx::B2DPolyPolygon Shadow3DExtractingProcessor::impDoShadowProjection(const basegfx::B3DPolyPolygon& rSource)
292 : {
293 0 : basegfx::B2DPolyPolygon aRetval;
294 :
295 0 : for(sal_uInt32 a(0L); a < rSource.count(); a++)
296 : {
297 0 : aRetval.append(impDoShadowProjection(rSource.getB3DPolygon(a)));
298 : }
299 :
300 0 : return aRetval;
301 : }
302 :
303 15 : const primitive2d::Primitive2DSequence Shadow3DExtractingProcessor::getPrimitive2DSequence() const
304 : {
305 15 : return Primitive2DVectorToPrimitive2DSequence(maPrimitive2DSequence);
306 : }
307 :
308 : } // end of namespace processor3d
309 : } // end of namespace drawinglayer
310 :
311 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|