1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tools/b3dtrans.hxx>
22 #include <osl/diagnose.h>
24 // B3dTransformationSet --------------------------------------------------------
25 // Transformations for all 3D output
27 B3dTransformationSet::B3dTransformationSet()
32 B3dTransformationSet::~B3dTransformationSet()
36 void B3dTransformationSet::Orientation(basegfx::B3DHomMatrix
& rTarget
, basegfx::B3DPoint aVRP
, basegfx::B3DVector aVPN
, basegfx::B3DVector aVUP
)
38 rTarget
.translate( -aVRP
.getX(), -aVRP
.getY(), -aVRP
.getZ());
41 basegfx::B3DVector
aRx(aVUP
);
42 basegfx::B3DVector
aRy(aVPN
);
43 aRx
= aRx
.getPerpendicular(aRy
);
45 aRy
= aRy
.getPerpendicular(aRx
);
47 basegfx::B3DHomMatrix aTemp
;
48 aTemp
.set(0, 0, aRx
.getX());
49 aTemp
.set(0, 1, aRx
.getY());
50 aTemp
.set(0, 2, aRx
.getZ());
51 aTemp
.set(1, 0, aRy
.getX());
52 aTemp
.set(1, 1, aRy
.getY());
53 aTemp
.set(1, 2, aRy
.getZ());
54 aTemp
.set(2, 0, aVPN
.getX());
55 aTemp
.set(2, 1, aVPN
.getY());
56 aTemp
.set(2, 2, aVPN
.getZ());
60 void B3dTransformationSet::Frustum(basegfx::B3DHomMatrix
& rTarget
, double fLeft
, double fRight
, double fBottom
, double fTop
, double fNear
, double fFar
)
84 basegfx::B3DHomMatrix aTemp
;
86 aTemp
.set(0, 0, 2.0 * fNear
/ (fRight
- fLeft
));
87 aTemp
.set(1, 1, 2.0 * fNear
/ (fTop
- fBottom
));
88 aTemp
.set(0, 2, (fRight
+ fLeft
) / (fRight
- fLeft
));
89 aTemp
.set(1, 2, (fTop
+ fBottom
) / (fTop
- fBottom
));
90 aTemp
.set(2, 2, -1.0 * ((fFar
+ fNear
) / (fFar
- fNear
)));
91 aTemp
.set(3, 2, -1.0);
92 aTemp
.set(2, 3, -1.0 * ((2.0 * fFar
* fNear
) / (fFar
- fNear
)));
98 void B3dTransformationSet::Ortho(basegfx::B3DHomMatrix
& rTarget
,
99 double fLeft
, double fRight
, double fBottom
, double fTop
,
100 double fNear
, double fFar
)
104 OSL_FAIL("Near and far clipping plane in Ortho definition are identical");
109 OSL_FAIL("Left and right in Ortho definition are identical");
115 OSL_FAIL("Top and bottom in Ortho definition are identical");
119 basegfx::B3DHomMatrix aTemp
;
121 aTemp
.set(0, 0, 2.0 / (fRight
- fLeft
));
122 aTemp
.set(1, 1, 2.0 / (fTop
- fBottom
));
123 aTemp
.set(2, 2, -1.0 * (2.0 / (fFar
- fNear
)));
124 aTemp
.set(0, 3, -1.0 * ((fRight
+ fLeft
) / (fRight
- fLeft
)));
125 aTemp
.set(1, 3, -1.0 * ((fTop
+ fBottom
) / (fTop
- fBottom
)));
126 aTemp
.set(2, 3, -1.0 * ((fFar
+ fNear
) / (fFar
- fNear
)));
132 void B3dTransformationSet::Reset()
134 // Reset matrices to identity matrices
135 maObjectTrans
.identity();
136 PostSetObjectTrans();
138 Orientation(maOrientation
);
139 PostSetOrientation();
141 maTexture
.identity();
143 mfLeftBound
= mfBottomBound
= -1.0;
144 mfRightBound
= mfTopBound
= 1.0;
148 meRatio
= Base3DRatioGrow
;
151 maViewportRectangle
= Rectangle(-1, -1, 2, 2);
152 maVisibleRectangle
= maViewportRectangle
;
154 mbPerspective
= true;
156 mbProjectionValid
= false;
157 mbObjectToDeviceValid
= false;
158 mbWorldToViewValid
= false;
163 /// Object transformation
164 void B3dTransformationSet::PostSetObjectTrans()
166 // Assign and compute inverse
167 maInvObjectTrans
= maObjectTrans
;
168 maInvObjectTrans
.invert();
171 void B3dTransformationSet::SetOrientation(const basegfx::B3DPoint
& rVRP
, const basegfx::B3DVector
& rVPN
, const basegfx::B3DVector
& rVUP
)
173 maOrientation
.identity();
174 Orientation(maOrientation
, rVRP
, rVPN
, rVUP
);
176 mbInvTransObjectToEyeValid
= false;
177 mbObjectToDeviceValid
= false;
178 mbWorldToViewValid
= false;
180 PostSetOrientation();
183 void B3dTransformationSet::PostSetOrientation()
185 // Assign and compute inverse
186 maInvOrientation
= maOrientation
;
187 maInvOrientation
.invert();
190 /// Projections for transformations
191 void B3dTransformationSet::SetProjection(const basegfx::B3DHomMatrix
& mProject
)
193 maProjection
= mProject
;
197 const basegfx::B3DHomMatrix
& B3dTransformationSet::GetProjection()
199 if(!mbProjectionValid
)
204 void B3dTransformationSet::PostSetProjection()
206 // Assign and comptue inverse
207 maInvProjection
= GetProjection();
208 maInvProjection
.invert();
210 // invalidate dependent matrices
211 mbObjectToDeviceValid
= false;
212 mbWorldToViewValid
= false;
215 /// Transformations for viewport
216 void B3dTransformationSet::CalcViewport()
218 // Parameters for projection
219 double fLeft(mfLeftBound
);
220 double fRight(mfRightBound
);
221 double fBottom(mfBottomBound
);
222 double fTop(mfTopBound
);
224 // Adjust projection to aspect ratio, if set
225 if(GetRatio() != 0.0)
227 // Compute current aspect ratio of boundaries
228 double fBoundWidth
= (double)(maViewportRectangle
.GetWidth() + 1);
229 double fBoundHeight
= (double)(maViewportRectangle
.GetHeight() + 1);
230 double fActRatio
= 1;
233 if(fBoundWidth
!= 0.0)
234 fActRatio
= fBoundHeight
/ fBoundWidth
;
235 // FIXME else in this case has a lot of problems, should this return.
239 case Base3DRatioShrink
:
241 // Dilate smaller part
242 if(fActRatio
> mfRatio
)
245 fFactor
= 1.0 / fActRatio
;
258 case Base3DRatioGrow
:
260 // scale down larger part
261 if(fActRatio
> mfRatio
)
271 fFactor
= 1.0 / fActRatio
;
277 case Base3DRatioMiddle
:
280 fFactor
= ((1.0 / fActRatio
) + 1.0) / 2.0;
283 fFactor
= (fActRatio
+ 1.0) / 2.0;
291 // Do projection and object areas overlap?
292 maSetBound
= maViewportRectangle
;
294 // Reset projection with new values
295 basegfx::B3DHomMatrix aNewProjection
;
298 // OpenGL needs a little more rough additional size to not let
299 // the front face vanish. Changed from SMALL_DVALUE to 0.000001,
300 // which is 1/10000th, comared with 1/tenth of a million from SMALL_DVALUE.
301 const double fDistPart((mfFarBound
- mfNearBound
) * 0.0001);
303 // To avoid critical clipping, set Near & Far generously
306 Frustum(aNewProjection
, fLeft
, fRight
, fBottom
, fTop
, mfNearBound
- fDistPart
, mfFarBound
+ fDistPart
);
310 Ortho(aNewProjection
, fLeft
, fRight
, fBottom
, fTop
, mfNearBound
- fDistPart
, mfFarBound
+ fDistPart
);
313 // Set to true to guarantee loop termination
314 mbProjectionValid
= true;
316 // set new projection
317 SetProjection(aNewProjection
);
319 // fill parameters for ViewportTransformation
321 maTranslate
.setX((double)maSetBound
.Left() + ((maSetBound
.GetWidth() - 1L) / 2.0));
322 maTranslate
.setY((double)maSetBound
.Top() + ((maSetBound
.GetHeight() - 1L) / 2.0));
323 maTranslate
.setZ(ZBUFFER_DEPTH_RANGE
/ 2.0);
326 maScale
.setX((maSetBound
.GetWidth() - 1L) / 2.0);
327 maScale
.setY((maSetBound
.GetHeight() - 1L) / -2.0);
328 maScale
.setZ(ZBUFFER_DEPTH_RANGE
/ 2.0);
331 void B3dTransformationSet::SetRatio(double fNew
)
336 mbProjectionValid
= false;
337 mbObjectToDeviceValid
= false;
338 mbWorldToViewValid
= false;
342 void B3dTransformationSet::SetDeviceRectangle(double fL
, double fR
, double fB
, double fT
,
343 bool bBroadCastChange
)
345 if(fL
!= mfLeftBound
|| fR
!= mfRightBound
|| fB
!= mfBottomBound
|| fT
!= mfTopBound
)
352 mbProjectionValid
= false;
353 mbObjectToDeviceValid
= false;
354 mbWorldToViewValid
= false;
358 DeviceRectangleChange();
362 void B3dTransformationSet::DeviceRectangleChange()
366 void B3dTransformationSet::SetPerspective(bool bNew
)
368 if(mbPerspective
!= bNew
)
370 mbPerspective
= bNew
;
371 mbProjectionValid
= false;
372 mbObjectToDeviceValid
= false;
373 mbWorldToViewValid
= false;
377 void B3dTransformationSet::SetViewportRectangle(Rectangle
& rRect
, Rectangle
& rVisible
)
379 if(rRect
!= maViewportRectangle
|| rVisible
!= maVisibleRectangle
)
381 maViewportRectangle
= rRect
;
382 maVisibleRectangle
= rVisible
;
384 mbProjectionValid
= false;
385 mbObjectToDeviceValid
= false;
386 mbWorldToViewValid
= false;
390 // direct access to various transformations
392 const basegfx::B3DPoint
B3dTransformationSet::WorldToEyeCoor(const basegfx::B3DPoint
& rVec
)
394 basegfx::B3DPoint
aVec(rVec
);
395 aVec
*= GetOrientation();
399 const basegfx::B3DPoint
B3dTransformationSet::EyeToWorldCoor(const basegfx::B3DPoint
& rVec
)
401 basegfx::B3DPoint
aVec(rVec
);
402 aVec
*= GetInvOrientation();
406 // B3dViewport -----------------------------------------------------------------
408 B3dViewport::B3dViewport()
409 : B3dTransformationSet(),
417 B3dViewport::~B3dViewport()
421 void B3dViewport::SetVUV(const basegfx::B3DVector
& rNewVUV
)
427 void B3dViewport::SetViewportValues(
428 const basegfx::B3DPoint
& rNewVRP
,
429 const basegfx::B3DVector
& rNewVPN
,
430 const basegfx::B3DVector
& rNewVUV
)
438 void B3dViewport::CalcOrientation()
440 SetOrientation(aVRP
, aVPN
, aVUV
);
443 // B3dCamera -------------------------------------------------------------------
445 B3dCamera::B3dCamera(
446 const basegfx::B3DPoint
& rPos
, const basegfx::B3DVector
& rLkAt
,
447 double fFocLen
, double fBnkAng
, bool bUseFocLen
)
450 aCorrectedPosition(rPos
),
452 fFocalLength(fFocLen
),
454 bUseFocalLength(bUseFocLen
)
456 CalcNewViewportValues();
459 B3dCamera::~B3dCamera()
463 void B3dCamera::DeviceRectangleChange()
466 B3dViewport::DeviceRectangleChange();
469 CalcNewViewportValues();
472 void B3dCamera::CalcNewViewportValues()
474 basegfx::B3DVector
aViewVector(aPosition
- aLookAt
);
475 basegfx::B3DVector
aNewVPN(aViewVector
);
477 basegfx::B3DVector
aNewVUV(0.0, 1.0, 0.0);
478 if(aNewVPN
.getLength() < aNewVPN
.getY())
484 basegfx::B3DVector aNewToTheRight
= aNewVPN
;
485 aNewToTheRight
= aNewToTheRight
.getPerpendicular(aNewVUV
);
486 aNewToTheRight
.normalize();
487 aNewVUV
= aNewToTheRight
.getPerpendicular(aNewVPN
);
490 SetViewportValues(aPosition
, aNewVPN
, aNewVUV
);
491 if(CalcFocalLength())
492 SetViewportValues(aCorrectedPosition
, aNewVPN
, aNewVUV
);
494 if(fBankAngle
!= 0.0)
496 basegfx::B3DHomMatrix aRotMat
;
497 aRotMat
.rotate(0.0, 0.0, fBankAngle
);
498 basegfx::B3DVector
aUp(0.0, 1.0, 0.0);
500 aUp
= EyeToWorldCoor(aUp
);
506 bool B3dCamera::CalcFocalLength()
508 double fWidth
= GetDeviceRectangleWidth();
509 bool bRetval
= false;
513 // Update position if focal length changes
514 aCorrectedPosition
= basegfx::B3DPoint(0.0, 0.0, fFocalLength
* fWidth
/ 35.0);
515 aCorrectedPosition
= EyeToWorldCoor(aCorrectedPosition
);
520 // Adjust focal length based on given position
521 basegfx::B3DPoint aOldPosition
;
522 aOldPosition
= WorldToEyeCoor(aOldPosition
);
524 fFocalLength
= aOldPosition
.getZ() / fWidth
* 35.0;
525 if(fFocalLength
< 5.0)
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */