Avoid potential negative array index access to cached text.
[LibreOffice.git] / tools / source / generic / b3dtrans.cxx
blob0cae750da0dc241dc635073c8b9d96a037dbef2d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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()
34 Reset();
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());
44 aVUP.normalize();
45 aVPN.normalize();
46 basegfx::B3DVector aRx(aVUP);
47 basegfx::B3DVector aRy(aVPN);
48 aRx = aRx.getPerpendicular(aRy);
49 aRx.normalize();
50 aRy = aRy.getPerpendicular(aRx);
51 aRy.normalize();
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());
62 rTarget *= aTemp;
65 void B3dTransformationSet::Frustum(basegfx::B3DHomMatrix& rTarget, double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
67 if(!(fNear > 0.0))
69 fNear = 0.001;
71 if(!(fFar > 0.0))
73 fFar = 1.0;
75 if(fNear == fFar)
77 fFar = fNear + 1.0;
79 if(fLeft == fRight)
81 fLeft -= 1.0;
82 fRight += 1.0;
84 if(fTop == fBottom)
86 fBottom -= 1.0;
87 fTop += 1.0;
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)));
98 aTemp.set(3, 3, 0.0);
100 rTarget *= aTemp;
103 void B3dTransformationSet::Ortho(basegfx::B3DHomMatrix& rTarget,
104 double fLeft, double fRight, double fBottom, double fTop,
105 double fNear, double fFar)
107 if(fNear == fFar)
109 OSL_FAIL("Near and far clipping plane in Ortho definition are identical");
110 fFar = fNear + 1.0;
112 if(fLeft == fRight)
114 OSL_FAIL("Left and right in Ortho definition are identical");
115 fLeft -= 1.0;
116 fRight += 1.0;
118 if(fTop == fBottom)
120 OSL_FAIL("Top and bottom in Ortho definition are identical");
121 fBottom -= 1.0;
122 fTop += 1.0;
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)));
133 rTarget *= aTemp;
136 /// reset values
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;
151 mfRatio = 0.0;
153 maViewportRectangle = tools::Rectangle(-1, -1, 2, 2);
154 maVisibleRectangle = maViewportRectangle;
156 mbPerspective = true;
158 mbProjectionValid = false;
160 CalcViewport();
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;
190 PostSetProjection();
193 const basegfx::B3DHomMatrix& B3dTransformationSet::GetProjection()
195 if(!mbProjectionValid)
196 CalcViewport();
197 return maProjection;
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;
223 double fFactor;
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)
232 // scale down Y
233 fFactor = fActRatio;
234 fTop *= fFactor;
235 fBottom *= fFactor;
237 else
239 // scale down X
240 fFactor = 1.0 / fActRatio;
241 fRight *= fFactor;
242 fLeft *= fFactor;
246 // Do projection and object areas overlap?
247 maSetBound = maViewportRectangle;
249 // Reset projection with new values
250 basegfx::B3DHomMatrix aNewProjection;
252 // #i36281#
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
259 if(mbPerspective)
261 Frustum(aNewProjection, fLeft, fRight, fBottom, fTop, gfNearBound - fDistPart, gfFarBound + fDistPart);
263 else
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
275 // Translation
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);
280 // Scaling
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)
288 if(mfRatio != fNew)
290 mfRatio = 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)
299 mfLeftBound = fL;
300 mfRightBound = fR;
301 mfBottomBound = fB;
302 mfTopBound = fT;
304 mbProjectionValid = false;
306 // Broadcast changes
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;
341 return aVec;
344 basegfx::B3DPoint B3dTransformationSet::EyeToWorldCoor(const basegfx::B3DPoint& rVec)
346 basegfx::B3DPoint aVec(rVec);
347 aVec *= maInvOrientation;
348 return aVec;
351 // B3dViewport -----------------------------------------------------------------
353 B3dViewport::B3dViewport()
354 : aVRP(0, 0, 0),
355 aVPN(0, 0, 1),
356 aVUV(0, 1, 0)
358 CalcOrientation();
361 B3dViewport::~B3dViewport()
365 void B3dViewport::SetVUV(const basegfx::B3DVector& rNewVUV)
367 aVUV = rNewVUV;
368 CalcOrientation();
371 void B3dViewport::SetViewportValues(
372 const basegfx::B3DPoint& rNewVRP,
373 const basegfx::B3DVector& rNewVPN,
374 const basegfx::B3DVector& rNewVUV)
376 aVRP = rNewVRP;
377 aVPN = rNewVPN;
378 aVUV = rNewVUV;
379 CalcOrientation();
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)
392 : aPosition(rPos),
393 aLookAt(rLkAt),
394 fFocalLength(fFocLen),
395 fBankAngle(fBnkAng)
397 CalcNewViewportValues();
400 B3dCamera::~B3dCamera()
404 void B3dCamera::DeviceRectangleChange()
406 // call parent
407 B3dViewport::DeviceRectangleChange();
409 // react to changes
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())
419 aNewVUV.setX(0.5);
421 aNewVUV.normalize();
422 aNewVPN.normalize();
424 basegfx::B3DVector aNewToTheRight = aNewVPN.getPerpendicular(aNewVUV);
425 aNewToTheRight.normalize();
426 aNewVUV = aNewToTheRight.getPerpendicular(aNewVPN);
427 aNewVUV.normalize();
429 SetViewportValues(aPosition, aNewVPN, aNewVUV);
430 CalcFocalLength();
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);
437 aUp *= aRotMat;
438 aUp = EyeToWorldCoor(aUp);
439 aUp.normalize();
440 SetVUV(aUp);
444 void B3dCamera::CalcFocalLength()
446 double fWidth = GetDeviceRectangleWidth();
448 // Adjust focal length based on given position
449 basegfx::B3DPoint aOldPosition = WorldToEyeCoor({});
450 if(fWidth != 0.0)
451 fFocalLength = aOldPosition.getZ() / fWidth * 35.0;
452 if(fFocalLength < 5.0)
453 fFocalLength = 5.0;
456 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */