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 <tools/b3dtrans.hxx>
21 :
22 : // B3dTransformationSet --------------------------------------------------------
23 : // Transformations for all 3D output
24 :
25 1406 : B3dTransformationSet::B3dTransformationSet()
26 : {
27 1406 : Reset();
28 1406 : }
29 :
30 1406 : B3dTransformationSet::~B3dTransformationSet()
31 : {
32 1406 : }
33 :
34 7083 : void B3dTransformationSet::Orientation(basegfx::B3DHomMatrix& rTarget, basegfx::B3DPoint aVRP, basegfx::B3DVector aVPN, basegfx::B3DVector aVUP)
35 : {
36 7083 : rTarget.translate( -aVRP.getX(), -aVRP.getY(), -aVRP.getZ());
37 7083 : aVUP.normalize();
38 7083 : aVPN.normalize();
39 7083 : basegfx::B3DVector aRx(aVUP);
40 14166 : basegfx::B3DVector aRy(aVPN);
41 7083 : aRx = aRx.getPerpendicular(aRy);
42 7083 : aRx.normalize();
43 7083 : aRy = aRy.getPerpendicular(aRx);
44 7083 : aRy.normalize();
45 14166 : basegfx::B3DHomMatrix aTemp;
46 7083 : aTemp.set(0, 0, aRx.getX());
47 7083 : aTemp.set(0, 1, aRx.getY());
48 7083 : aTemp.set(0, 2, aRx.getZ());
49 7083 : aTemp.set(1, 0, aRy.getX());
50 7083 : aTemp.set(1, 1, aRy.getY());
51 7083 : aTemp.set(1, 2, aRy.getZ());
52 7083 : aTemp.set(2, 0, aVPN.getX());
53 7083 : aTemp.set(2, 1, aVPN.getY());
54 7083 : aTemp.set(2, 2, aVPN.getZ());
55 14166 : rTarget *= aTemp;
56 7083 : }
57 :
58 1406 : void B3dTransformationSet::Frustum(basegfx::B3DHomMatrix& rTarget, double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
59 : {
60 1406 : if(!(fNear > 0.0))
61 : {
62 0 : fNear = 0.001;
63 : }
64 1406 : if(!(fFar > 0.0))
65 : {
66 0 : fFar = 1.0;
67 : }
68 1406 : if(fNear == fFar)
69 : {
70 0 : fFar = fNear + 1.0;
71 : }
72 1406 : if(fLeft == fRight)
73 : {
74 0 : fLeft -= 1.0;
75 0 : fRight += 1.0;
76 : }
77 1406 : if(fTop == fBottom)
78 : {
79 0 : fBottom -= 1.0;
80 0 : fTop += 1.0;
81 : }
82 1406 : basegfx::B3DHomMatrix aTemp;
83 :
84 1406 : aTemp.set(0, 0, 2.0 * fNear / (fRight - fLeft));
85 1406 : aTemp.set(1, 1, 2.0 * fNear / (fTop - fBottom));
86 1406 : aTemp.set(0, 2, (fRight + fLeft) / (fRight - fLeft));
87 1406 : aTemp.set(1, 2, (fTop + fBottom) / (fTop - fBottom));
88 1406 : aTemp.set(2, 2, -1.0 * ((fFar + fNear) / (fFar - fNear)));
89 1406 : aTemp.set(3, 2, -1.0);
90 1406 : aTemp.set(2, 3, -1.0 * ((2.0 * fFar * fNear) / (fFar - fNear)));
91 1406 : aTemp.set(3, 3, 0.0);
92 :
93 1406 : rTarget *= aTemp;
94 1406 : }
95 :
96 0 : void B3dTransformationSet::Ortho(basegfx::B3DHomMatrix& rTarget,
97 : double fLeft, double fRight, double fBottom, double fTop,
98 : double fNear, double fFar)
99 : {
100 0 : if(fNear == fFar)
101 : {
102 : OSL_FAIL("Near and far clipping plane in Ortho definition are identical");
103 0 : fFar = fNear + 1.0;
104 : }
105 0 : if(fLeft == fRight)
106 : {
107 : OSL_FAIL("Left and right in Ortho definition are identical");
108 0 : fLeft -= 1.0;
109 0 : fRight += 1.0;
110 : }
111 0 : if(fTop == fBottom)
112 : {
113 : OSL_FAIL("Top and bottom in Ortho definition are identical");
114 0 : fBottom -= 1.0;
115 0 : fTop += 1.0;
116 : }
117 0 : basegfx::B3DHomMatrix aTemp;
118 :
119 0 : aTemp.set(0, 0, 2.0 / (fRight - fLeft));
120 0 : aTemp.set(1, 1, 2.0 / (fTop - fBottom));
121 0 : aTemp.set(2, 2, -1.0 * (2.0 / (fFar - fNear)));
122 0 : aTemp.set(0, 3, -1.0 * ((fRight + fLeft) / (fRight - fLeft)));
123 0 : aTemp.set(1, 3, -1.0 * ((fTop + fBottom) / (fTop - fBottom)));
124 0 : aTemp.set(2, 3, -1.0 * ((fFar + fNear) / (fFar - fNear)));
125 :
126 0 : rTarget *= aTemp;
127 0 : }
128 :
129 : /// reset values
130 1406 : void B3dTransformationSet::Reset()
131 : {
132 : // Reset matrices to identity matrices
133 1406 : maObjectTrans.identity();
134 1406 : PostSetObjectTrans();
135 :
136 1406 : Orientation(maOrientation);
137 1406 : PostSetOrientation();
138 :
139 1406 : maTexture.identity();
140 :
141 1406 : mfLeftBound = mfBottomBound = -1.0;
142 1406 : mfRightBound = mfTopBound = 1.0;
143 1406 : mfNearBound = 0.001;
144 1406 : mfFarBound = 1.001;
145 :
146 1406 : meRatio = Base3DRatioGrow;
147 1406 : mfRatio = 0.0;
148 :
149 1406 : maViewportRectangle = Rectangle(-1, -1, 2, 2);
150 1406 : maVisibleRectangle = maViewportRectangle;
151 :
152 1406 : mbPerspective = true;
153 :
154 1406 : mbProjectionValid = false;
155 1406 : mbObjectToDeviceValid = false;
156 1406 : mbWorldToViewValid = false;
157 :
158 1406 : CalcViewport();
159 1406 : }
160 :
161 : /// Object transformation
162 1406 : void B3dTransformationSet::PostSetObjectTrans()
163 : {
164 : // Assign and compute inverse
165 1406 : maInvObjectTrans = maObjectTrans;
166 1406 : maInvObjectTrans.invert();
167 1406 : }
168 :
169 5677 : void B3dTransformationSet::SetOrientation( basegfx::B3DPoint aVRP, basegfx::B3DVector aVPN, basegfx::B3DVector aVUP)
170 : {
171 5677 : maOrientation.identity();
172 5677 : Orientation(maOrientation, aVRP, aVPN, aVUP);
173 :
174 5677 : mbInvTransObjectToEyeValid = false;
175 5677 : mbObjectToDeviceValid = false;
176 5677 : mbWorldToViewValid = false;
177 :
178 5677 : PostSetOrientation();
179 5677 : }
180 :
181 7083 : void B3dTransformationSet::PostSetOrientation()
182 : {
183 : // Assign and compute inverse
184 7083 : maInvOrientation = maOrientation;
185 7083 : maInvOrientation.invert();
186 7083 : }
187 :
188 : /// Projections for transformations
189 1406 : void B3dTransformationSet::SetProjection(const basegfx::B3DHomMatrix& mProject)
190 : {
191 1406 : maProjection = mProject;
192 1406 : PostSetProjection();
193 1406 : }
194 :
195 1406 : const basegfx::B3DHomMatrix& B3dTransformationSet::GetProjection()
196 : {
197 1406 : if(!mbProjectionValid)
198 0 : CalcViewport();
199 1406 : return maProjection;
200 : }
201 :
202 1406 : void B3dTransformationSet::PostSetProjection()
203 : {
204 : // Assign and comptue inverse
205 1406 : maInvProjection = GetProjection();
206 1406 : maInvProjection.invert();
207 :
208 : // invalidate dependent matrices
209 1406 : mbObjectToDeviceValid = false;
210 1406 : mbWorldToViewValid = false;
211 1406 : }
212 :
213 : /// Transformations for viewport
214 1406 : void B3dTransformationSet::CalcViewport()
215 : {
216 : // Parameters for projection
217 1406 : double fLeft(mfLeftBound);
218 1406 : double fRight(mfRightBound);
219 1406 : double fBottom(mfBottomBound);
220 1406 : double fTop(mfTopBound);
221 :
222 : // Adjust projection to aspect ratio, if set
223 1406 : if(GetRatio() != 0.0)
224 : {
225 : // Compute current aspect ratio of boundaries
226 0 : double fBoundWidth = (double)(maViewportRectangle.GetWidth() + 1);
227 0 : double fBoundHeight = (double)(maViewportRectangle.GetHeight() + 1);
228 0 : double fActRatio = 1;
229 : double fFactor;
230 :
231 0 : if(fBoundWidth != 0.0)
232 0 : fActRatio = fBoundHeight / fBoundWidth;
233 : // FIXME else in this case has a lot of problems, should this return.
234 :
235 0 : switch(meRatio)
236 : {
237 : case Base3DRatioShrink :
238 : {
239 : // Dilate smaller part
240 0 : if(fActRatio > mfRatio)
241 : {
242 : // enlarge X
243 0 : fFactor = 1.0 / fActRatio;
244 0 : fRight *= fFactor;
245 0 : fLeft *= fFactor;
246 : }
247 : else
248 : {
249 : // enlarge Y
250 0 : fFactor = fActRatio;
251 0 : fTop *= fFactor;
252 0 : fBottom *= fFactor;
253 : }
254 0 : break;
255 : }
256 : case Base3DRatioGrow :
257 : {
258 : // scale down larger part
259 0 : if(fActRatio > mfRatio)
260 : {
261 : // scale down Y
262 0 : fFactor = fActRatio;
263 0 : fTop *= fFactor;
264 0 : fBottom *= fFactor;
265 : }
266 : else
267 : {
268 : // scale down X
269 0 : fFactor = 1.0 / fActRatio;
270 0 : fRight *= fFactor;
271 0 : fLeft *= fFactor;
272 : }
273 0 : break;
274 : }
275 : case Base3DRatioMiddle :
276 : {
277 : // averaging
278 0 : fFactor = ((1.0 / fActRatio) + 1.0) / 2.0;
279 0 : fRight *= fFactor;
280 0 : fLeft *= fFactor;
281 0 : fFactor = (fActRatio + 1.0) / 2.0;
282 0 : fTop *= fFactor;
283 0 : fBottom *= fFactor;
284 0 : break;
285 : }
286 : }
287 : }
288 :
289 : // Do projection and object areas overlap?
290 1406 : maSetBound = maViewportRectangle;
291 :
292 : // Reset projection with new values
293 1406 : basegfx::B3DHomMatrix aNewProjection;
294 :
295 : // #i36281#
296 : // OpenGL needs a little more rough additional size to not let
297 : // the front face vanish. Changed from SMALL_DVALUE to 0.000001,
298 : // which is 1/10000th, comared with 1/tenth of a million from SMALL_DVALUE.
299 1406 : const double fDistPart((mfFarBound - mfNearBound) * 0.0001);
300 :
301 : // To avoid critical clipping, set Near & Far generously
302 1406 : if(mbPerspective)
303 : {
304 1406 : Frustum(aNewProjection, fLeft, fRight, fBottom, fTop, mfNearBound - fDistPart, mfFarBound + fDistPart);
305 : }
306 : else
307 : {
308 0 : Ortho(aNewProjection, fLeft, fRight, fBottom, fTop, mfNearBound - fDistPart, mfFarBound + fDistPart);
309 : }
310 :
311 : // Set to true to guarantee loop termination
312 1406 : mbProjectionValid = true;
313 :
314 : // set new projection
315 1406 : SetProjection(aNewProjection);
316 :
317 : // fill parameters for ViewportTransformation
318 : // Translation
319 1406 : maTranslate.setX((double)maSetBound.Left() + ((maSetBound.GetWidth() - 1L) / 2.0));
320 1406 : maTranslate.setY((double)maSetBound.Top() + ((maSetBound.GetHeight() - 1L) / 2.0));
321 1406 : maTranslate.setZ(ZBUFFER_DEPTH_RANGE / 2.0);
322 :
323 : // Scaling
324 1406 : maScale.setX((maSetBound.GetWidth() - 1L) / 2.0);
325 1406 : maScale.setY((maSetBound.GetHeight() - 1L) / -2.0);
326 1406 : maScale.setZ(ZBUFFER_DEPTH_RANGE / 2.0);
327 :
328 : // React to change of viewport
329 1406 : PostSetViewport();
330 1406 : }
331 :
332 1459 : void B3dTransformationSet::SetRatio(double fNew)
333 : {
334 1459 : if(mfRatio != fNew)
335 : {
336 0 : mfRatio = fNew;
337 0 : mbProjectionValid = false;
338 0 : mbObjectToDeviceValid = false;
339 0 : mbWorldToViewValid = false;
340 : }
341 1459 : }
342 :
343 1406 : void B3dTransformationSet::SetDeviceRectangle(double fL, double fR, double fB, double fT,
344 : bool bBroadCastChange)
345 : {
346 1406 : if(fL != mfLeftBound || fR != mfRightBound || fB != mfBottomBound || fT != mfTopBound)
347 : {
348 1406 : mfLeftBound = fL;
349 1406 : mfRightBound = fR;
350 1406 : mfBottomBound = fB;
351 1406 : mfTopBound = fT;
352 :
353 1406 : mbProjectionValid = false;
354 1406 : mbObjectToDeviceValid = false;
355 1406 : mbWorldToViewValid = false;
356 :
357 : // Broadcast changes
358 1406 : if(bBroadCastChange)
359 1406 : DeviceRectangleChange();
360 : }
361 1406 : }
362 :
363 1406 : void B3dTransformationSet::DeviceRectangleChange()
364 : {
365 1406 : }
366 :
367 1459 : void B3dTransformationSet::SetPerspective(bool bNew)
368 : {
369 1459 : if(mbPerspective != bNew)
370 : {
371 16 : mbPerspective = bNew;
372 16 : mbProjectionValid = false;
373 16 : mbObjectToDeviceValid = false;
374 16 : mbWorldToViewValid = false;
375 : }
376 1459 : }
377 :
378 6152 : void B3dTransformationSet::SetViewportRectangle(Rectangle& rRect, Rectangle& rVisible)
379 : {
380 6152 : if(rRect != maViewportRectangle || rVisible != maVisibleRectangle)
381 : {
382 3287 : maViewportRectangle = rRect;
383 3287 : maVisibleRectangle = rVisible;
384 :
385 3287 : mbProjectionValid = false;
386 3287 : mbObjectToDeviceValid = false;
387 3287 : mbWorldToViewValid = false;
388 : }
389 6152 : }
390 :
391 1406 : void B3dTransformationSet::PostSetViewport()
392 : {
393 1406 : }
394 :
395 : // direct access to various transformations
396 :
397 2812 : const basegfx::B3DPoint B3dTransformationSet::WorldToEyeCoor(const basegfx::B3DPoint& rVec)
398 : {
399 2812 : basegfx::B3DPoint aVec(rVec);
400 2812 : aVec *= GetOrientation();
401 2812 : return aVec;
402 : }
403 :
404 0 : const basegfx::B3DPoint B3dTransformationSet::EyeToWorldCoor(const basegfx::B3DPoint& rVec)
405 : {
406 0 : basegfx::B3DPoint aVec(rVec);
407 0 : aVec *= GetInvOrientation();
408 0 : return aVec;
409 : }
410 :
411 : // B3dViewport -----------------------------------------------------------------
412 :
413 1406 : B3dViewport::B3dViewport()
414 : : B3dTransformationSet(),
415 : aVRP(0, 0, 0),
416 : aVPN(0, 0, 1),
417 1406 : aVUV(0, 1, 0)
418 : {
419 1406 : CalcOrientation();
420 1406 : }
421 :
422 1406 : B3dViewport::~B3dViewport()
423 : {
424 1406 : }
425 :
426 0 : void B3dViewport::SetVUV(const basegfx::B3DVector& rNewVUV)
427 : {
428 0 : aVUV = rNewVUV;
429 0 : CalcOrientation();
430 0 : }
431 :
432 4271 : void B3dViewport::SetViewportValues(
433 : const basegfx::B3DPoint& rNewVRP,
434 : const basegfx::B3DVector& rNewVPN,
435 : const basegfx::B3DVector& rNewVUV)
436 : {
437 4271 : aVRP = rNewVRP;
438 4271 : aVPN = rNewVPN;
439 4271 : aVUV = rNewVUV;
440 4271 : CalcOrientation();
441 4271 : }
442 :
443 5677 : void B3dViewport::CalcOrientation()
444 : {
445 5677 : SetOrientation(aVRP, aVPN, aVUV);
446 5677 : }
447 :
448 : // B3dCamera -------------------------------------------------------------------
449 :
450 1406 : B3dCamera::B3dCamera(
451 : const basegfx::B3DPoint& rPos, const basegfx::B3DVector& rLkAt,
452 : double fFocLen, double fBnkAng, bool bUseFocLen)
453 : : B3dViewport(),
454 : aPosition(rPos),
455 : aCorrectedPosition(rPos),
456 : aLookAt(rLkAt),
457 : fFocalLength(fFocLen),
458 : fBankAngle(fBnkAng),
459 1406 : bUseFocalLength(bUseFocLen)
460 : {
461 1406 : CalcNewViewportValues();
462 1406 : }
463 :
464 1406 : B3dCamera::~B3dCamera()
465 : {
466 1406 : }
467 :
468 1406 : void B3dCamera::DeviceRectangleChange()
469 : {
470 : // call parent
471 1406 : B3dViewport::DeviceRectangleChange();
472 :
473 : // react to changes
474 1406 : CalcNewViewportValues();
475 1406 : }
476 :
477 2812 : void B3dCamera::CalcNewViewportValues()
478 : {
479 2812 : basegfx::B3DVector aViewVector(aPosition - aLookAt);
480 5624 : basegfx::B3DVector aNewVPN(aViewVector);
481 :
482 5624 : basegfx::B3DVector aNewVUV(0.0, 1.0, 0.0);
483 2812 : if(aNewVPN.getLength() < aNewVPN.getY())
484 0 : aNewVUV.setX(0.5);
485 :
486 2812 : aNewVUV.normalize();
487 2812 : aNewVPN.normalize();
488 :
489 5624 : basegfx::B3DVector aNewToTheRight = aNewVPN;
490 2812 : aNewToTheRight = aNewToTheRight.getPerpendicular(aNewVUV);
491 2812 : aNewToTheRight.normalize();
492 2812 : aNewVUV = aNewToTheRight.getPerpendicular(aNewVPN);
493 2812 : aNewVUV.normalize();
494 :
495 2812 : SetViewportValues(aPosition, aNewVPN, aNewVUV);
496 2812 : if(CalcFocalLength())
497 0 : SetViewportValues(aCorrectedPosition, aNewVPN, aNewVUV);
498 :
499 2812 : if(fBankAngle != 0.0)
500 : {
501 0 : basegfx::B3DHomMatrix aRotMat;
502 0 : aRotMat.rotate(0.0, 0.0, fBankAngle);
503 0 : basegfx::B3DVector aUp(0.0, 1.0, 0.0);
504 0 : aUp *= aRotMat;
505 0 : aUp = EyeToWorldCoor(aUp);
506 0 : aUp.normalize();
507 0 : SetVUV(aUp);
508 2812 : }
509 2812 : }
510 :
511 2812 : bool B3dCamera::CalcFocalLength()
512 : {
513 2812 : double fWidth = GetDeviceRectangleWidth();
514 2812 : bool bRetval = false;
515 :
516 2812 : if(bUseFocalLength)
517 : {
518 : // Update position if focal length changes
519 0 : aCorrectedPosition = basegfx::B3DPoint(0.0, 0.0, fFocalLength * fWidth / 35.0);
520 0 : aCorrectedPosition = EyeToWorldCoor(aCorrectedPosition);
521 0 : bRetval = true;
522 : }
523 : else
524 : {
525 : // Adjust focal length based on given position
526 2812 : basegfx::B3DPoint aOldPosition;
527 2812 : aOldPosition = WorldToEyeCoor(aOldPosition);
528 2812 : if(fWidth != 0.0)
529 2812 : fFocalLength = aOldPosition.getZ() / fWidth * 35.0;
530 2812 : if(fFocalLength < 5.0)
531 2812 : fFocalLength = 5.0;
532 : }
533 2812 : return bRetval;
534 : }
535 :
536 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|