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 // Near and far clipping planes
25 constexpr double gfNearBound
= 0.001;
26 constexpr double gfFarBound
= 1.001;
29 // B3dTransformationSet --------------------------------------------------------
30 // Transformations for all 3D output
32 B3dTransformationSet::B3dTransformationSet()
37 B3dTransformationSet::~B3dTransformationSet()
41 void B3dTransformationSet::Orientation(basegfx::B3DHomMatrix
& rTarget
, const basegfx::B3DPoint
& aVRP
, basegfx::B3DVector aVPN
, basegfx::B3DVector aVUP
)
43 rTarget
.translate( -aVRP
.getX(), -aVRP
.getY(), -aVRP
.getZ());
46 basegfx::B3DVector
aRx(aVUP
);
47 basegfx::B3DVector
aRy(aVPN
);
48 aRx
= aRx
.getPerpendicular(aRy
);
50 aRy
= aRy
.getPerpendicular(aRx
);
52 basegfx::B3DHomMatrix aTemp
;
53 aTemp
.set(0, 0, aRx
.getX());
54 aTemp
.set(0, 1, aRx
.getY());
55 aTemp
.set(0, 2, aRx
.getZ());
56 aTemp
.set(1, 0, aRy
.getX());
57 aTemp
.set(1, 1, aRy
.getY());
58 aTemp
.set(1, 2, aRy
.getZ());
59 aTemp
.set(2, 0, aVPN
.getX());
60 aTemp
.set(2, 1, aVPN
.getY());
61 aTemp
.set(2, 2, aVPN
.getZ());
65 void B3dTransformationSet::Frustum(basegfx::B3DHomMatrix
& rTarget
, double fLeft
, double fRight
, double fBottom
, double fTop
, double fNear
, double fFar
)
89 basegfx::B3DHomMatrix aTemp
;
91 aTemp
.set(0, 0, 2.0 * fNear
/ (fRight
- fLeft
));
92 aTemp
.set(1, 1, 2.0 * fNear
/ (fTop
- fBottom
));
93 aTemp
.set(0, 2, (fRight
+ fLeft
) / (fRight
- fLeft
));
94 aTemp
.set(1, 2, (fTop
+ fBottom
) / (fTop
- fBottom
));
95 aTemp
.set(2, 2, -1.0 * ((fFar
+ fNear
) / (fFar
- fNear
)));
96 aTemp
.set(3, 2, -1.0);
97 aTemp
.set(2, 3, -1.0 * ((2.0 * fFar
* fNear
) / (fFar
- fNear
)));
103 void B3dTransformationSet::Ortho(basegfx::B3DHomMatrix
& rTarget
,
104 double fLeft
, double fRight
, double fBottom
, double fTop
,
105 double fNear
, double fFar
)
109 OSL_FAIL("Near and far clipping plane in Ortho definition are identical");
114 OSL_FAIL("Left and right in Ortho definition are identical");
120 OSL_FAIL("Top and bottom in Ortho definition are identical");
124 basegfx::B3DHomMatrix aTemp
;
126 aTemp
.set(0, 0, 2.0 / (fRight
- fLeft
));
127 aTemp
.set(1, 1, 2.0 / (fTop
- fBottom
));
128 aTemp
.set(2, 2, -1.0 * (2.0 / (fFar
- fNear
)));
129 aTemp
.set(0, 3, -1.0 * ((fRight
+ fLeft
) / (fRight
- fLeft
)));
130 aTemp
.set(1, 3, -1.0 * ((fTop
+ fBottom
) / (fTop
- fBottom
)));
131 aTemp
.set(2, 3, -1.0 * ((fFar
+ fNear
) / (fFar
- fNear
)));
137 void B3dTransformationSet::Reset()
139 // Reset matrices to identity matrices
140 maObjectTrans
.identity();
141 PostSetObjectTrans();
143 Orientation(maOrientation
);
144 PostSetOrientation();
146 maTexture
.identity();
148 mfLeftBound
= mfBottomBound
= -1.0;
149 mfRightBound
= mfTopBound
= 1.0;
153 maViewportRectangle
= tools::Rectangle(-1, -1, 2, 2);
154 maVisibleRectangle
= maViewportRectangle
;
156 mbPerspective
= true;
158 mbProjectionValid
= 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 PostSetOrientation();
179 void B3dTransformationSet::PostSetOrientation()
181 // Assign and compute inverse
182 maInvOrientation
= maOrientation
;
183 maInvOrientation
.invert();
186 /// Projections for transformations
187 void B3dTransformationSet::SetProjection(const basegfx::B3DHomMatrix
& mProject
)
189 maProjection
= mProject
;
193 const basegfx::B3DHomMatrix
& B3dTransformationSet::GetProjection()
195 if(!mbProjectionValid
)
200 void B3dTransformationSet::PostSetProjection()
202 // Assign and compute inverse
203 maInvProjection
= GetProjection();
204 maInvProjection
.invert();
207 /// Transformations for viewport
208 void B3dTransformationSet::CalcViewport()
210 // Parameters for projection
211 double fLeft(mfLeftBound
);
212 double fRight(mfRightBound
);
213 double fBottom(mfBottomBound
);
214 double fTop(mfTopBound
);
216 // Adjust projection to aspect ratio, if set
217 if(GetRatio() != 0.0)
219 // Compute current aspect ratio of boundaries
220 double fBoundWidth
= static_cast<double>(maViewportRectangle
.GetWidth() + 1);
221 double fBoundHeight
= static_cast<double>(maViewportRectangle
.GetHeight() + 1);
222 double fActRatio
= 1;
225 if(fBoundWidth
!= 0.0)
226 fActRatio
= fBoundHeight
/ fBoundWidth
;
227 // FIXME else in this case has a lot of problems, should this return.
229 // scale down larger part
230 if(fActRatio
> mfRatio
)
240 fFactor
= 1.0 / fActRatio
;
246 // Do projection and object areas overlap?
247 maSetBound
= maViewportRectangle
;
249 // Reset projection with new values
250 basegfx::B3DHomMatrix aNewProjection
;
253 // OpenGL needs a little more rough additional size to not let
254 // the front face vanish. Changed from SMALL_DVALUE to 0.000001,
255 // which is 1/10000th, compared with 1/tenth of a million from SMALL_DVALUE.
256 const double fDistPart((gfFarBound
- gfNearBound
) * 0.0001);
258 // To avoid critical clipping, set Near & Far generously
261 Frustum(aNewProjection
, fLeft
, fRight
, fBottom
, fTop
, gfNearBound
- fDistPart
, gfFarBound
+ fDistPart
);
265 Ortho(aNewProjection
, fLeft
, fRight
, fBottom
, fTop
, gfNearBound
- fDistPart
, gfFarBound
+ fDistPart
);
268 // Set to true to guarantee loop termination
269 mbProjectionValid
= true;
271 // set new projection
272 SetProjection(aNewProjection
);
274 // fill parameters for ViewportTransformation
276 maTranslate
.setX(static_cast<double>(maSetBound
.Left()) + ((maSetBound
.GetWidth() - 1) / 2.0));
277 maTranslate
.setY(static_cast<double>(maSetBound
.Top()) + ((maSetBound
.GetHeight() - 1) / 2.0));
278 maTranslate
.setZ(ZBUFFER_DEPTH_RANGE
/ 2.0);
281 maScale
.setX((maSetBound
.GetWidth() - 1) / 2.0);
282 maScale
.setY((maSetBound
.GetHeight() - 1) / -2.0);
283 maScale
.setZ(ZBUFFER_DEPTH_RANGE
/ 2.0);
286 void B3dTransformationSet::SetRatio(double fNew
)
291 mbProjectionValid
= false;
295 void B3dTransformationSet::SetDeviceRectangle(double fL
, double fR
, double fB
, double fT
)
297 if(fL
!= mfLeftBound
|| fR
!= mfRightBound
|| fB
!= mfBottomBound
|| fT
!= mfTopBound
)
304 mbProjectionValid
= false;
307 DeviceRectangleChange();
311 void B3dTransformationSet::DeviceRectangleChange()
315 void B3dTransformationSet::SetPerspective(bool bNew
)
317 if(mbPerspective
!= bNew
)
319 mbPerspective
= bNew
;
320 mbProjectionValid
= false;
324 void B3dTransformationSet::SetViewportRectangle(tools::Rectangle
const & rRect
, tools::Rectangle
const & rVisible
)
326 if(rRect
!= maViewportRectangle
|| rVisible
!= maVisibleRectangle
)
328 maViewportRectangle
= rRect
;
329 maVisibleRectangle
= rVisible
;
331 mbProjectionValid
= false;
335 // direct access to various transformations
337 basegfx::B3DPoint
B3dTransformationSet::WorldToEyeCoor(const basegfx::B3DPoint
& rVec
)
339 basegfx::B3DPoint
aVec(rVec
);
340 aVec
*= maOrientation
;
344 basegfx::B3DPoint
B3dTransformationSet::EyeToWorldCoor(const basegfx::B3DPoint
& rVec
)
346 basegfx::B3DPoint
aVec(rVec
);
347 aVec
*= maInvOrientation
;
351 // B3dViewport -----------------------------------------------------------------
353 B3dViewport::B3dViewport()
361 B3dViewport::~B3dViewport()
365 void B3dViewport::SetVUV(const basegfx::B3DVector
& rNewVUV
)
371 void B3dViewport::SetViewportValues(
372 const basegfx::B3DPoint
& rNewVRP
,
373 const basegfx::B3DVector
& rNewVPN
,
374 const basegfx::B3DVector
& rNewVUV
)
382 void B3dViewport::CalcOrientation()
384 SetOrientation(aVRP
, aVPN
, aVUV
);
387 // B3dCamera -------------------------------------------------------------------
389 B3dCamera::B3dCamera(
390 const basegfx::B3DPoint
& rPos
, const basegfx::B3DVector
& rLkAt
,
391 double fFocLen
, double fBnkAng
)
394 fFocalLength(fFocLen
),
397 CalcNewViewportValues();
400 B3dCamera::~B3dCamera()
404 void B3dCamera::DeviceRectangleChange()
407 B3dViewport::DeviceRectangleChange();
410 CalcNewViewportValues();
413 void B3dCamera::CalcNewViewportValues()
415 basegfx::B3DVector
aNewVPN(aPosition
- aLookAt
);
417 basegfx::B3DVector
aNewVUV(0.0, 1.0, 0.0);
418 if(aNewVPN
.getLength() < aNewVPN
.getY())
424 basegfx::B3DVector aNewToTheRight
= aNewVPN
.getPerpendicular(aNewVUV
);
425 aNewToTheRight
.normalize();
426 aNewVUV
= aNewToTheRight
.getPerpendicular(aNewVPN
);
429 SetViewportValues(aPosition
, aNewVPN
, aNewVUV
);
432 if(fBankAngle
!= 0.0)
434 basegfx::B3DHomMatrix aRotMat
;
435 aRotMat
.rotate(0.0, 0.0, fBankAngle
);
436 basegfx::B3DVector
aUp(0.0, 1.0, 0.0);
438 aUp
= EyeToWorldCoor(aUp
);
444 void B3dCamera::CalcFocalLength()
446 double fWidth
= GetDeviceRectangleWidth();
448 // Adjust focal length based on given position
449 basegfx::B3DPoint aOldPosition
= WorldToEyeCoor({});
451 fFocalLength
= aOldPosition
.getZ() / fWidth
* 35.0;
452 if(fFocalLength
< 5.0)
456 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */