/src/libreoffice/tools/source/generic/b3dtrans.cxx
Line | Count | Source |
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 | | #include <osl/diagnose.h> |
23 | | |
24 | | // Near and far clipping planes |
25 | | constexpr double gfNearBound = 0.001; |
26 | | constexpr double gfFarBound = 1.001; |
27 | | |
28 | | |
29 | | // B3dTransformationSet -------------------------------------------------------- |
30 | | // Transformations for all 3D output |
31 | | |
32 | | B3dTransformationSet::B3dTransformationSet() |
33 | 3.52k | { |
34 | 3.52k | Reset(); |
35 | 3.52k | } |
36 | | |
37 | | B3dTransformationSet::~B3dTransformationSet() |
38 | 3.52k | { |
39 | 3.52k | } |
40 | | |
41 | | void B3dTransformationSet::Orientation(basegfx::B3DHomMatrix& rTarget, const basegfx::B3DPoint& aVRP, basegfx::B3DVector aVPN, basegfx::B3DVector aVUP) |
42 | 21.1k | { |
43 | 21.1k | rTarget.translate( -aVRP.getX(), -aVRP.getY(), -aVRP.getZ()); |
44 | 21.1k | aVUP.normalize(); |
45 | 21.1k | aVPN.normalize(); |
46 | 21.1k | basegfx::B3DVector aRx(aVUP); |
47 | 21.1k | basegfx::B3DVector aRy(aVPN); |
48 | 21.1k | aRx = aRx.getPerpendicular(aRy); |
49 | 21.1k | aRx.normalize(); |
50 | 21.1k | aRy = aRy.getPerpendicular(aRx); |
51 | 21.1k | aRy.normalize(); |
52 | 21.1k | basegfx::B3DHomMatrix aTemp; |
53 | 21.1k | aTemp.set(0, 0, aRx.getX()); |
54 | 21.1k | aTemp.set(0, 1, aRx.getY()); |
55 | 21.1k | aTemp.set(0, 2, aRx.getZ()); |
56 | 21.1k | aTemp.set(1, 0, aRy.getX()); |
57 | 21.1k | aTemp.set(1, 1, aRy.getY()); |
58 | 21.1k | aTemp.set(1, 2, aRy.getZ()); |
59 | 21.1k | aTemp.set(2, 0, aVPN.getX()); |
60 | 21.1k | aTemp.set(2, 1, aVPN.getY()); |
61 | 21.1k | aTemp.set(2, 2, aVPN.getZ()); |
62 | 21.1k | rTarget *= aTemp; |
63 | 21.1k | } |
64 | | |
65 | | void B3dTransformationSet::Frustum(basegfx::B3DHomMatrix& rTarget, double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar) |
66 | 3.52k | { |
67 | 3.52k | if(!(fNear > 0.0)) |
68 | 0 | { |
69 | 0 | fNear = 0.001; |
70 | 0 | } |
71 | 3.52k | if(!(fFar > 0.0)) |
72 | 0 | { |
73 | 0 | fFar = 1.0; |
74 | 0 | } |
75 | 3.52k | if(fNear == fFar) |
76 | 0 | { |
77 | 0 | fFar = fNear + 1.0; |
78 | 0 | } |
79 | 3.52k | if(fLeft == fRight) |
80 | 0 | { |
81 | 0 | fLeft -= 1.0; |
82 | 0 | fRight += 1.0; |
83 | 0 | } |
84 | 3.52k | if(fTop == fBottom) |
85 | 0 | { |
86 | 0 | fBottom -= 1.0; |
87 | 0 | fTop += 1.0; |
88 | 0 | } |
89 | 3.52k | basegfx::B3DHomMatrix aTemp; |
90 | | |
91 | 3.52k | aTemp.set(0, 0, 2.0 * fNear / (fRight - fLeft)); |
92 | 3.52k | aTemp.set(1, 1, 2.0 * fNear / (fTop - fBottom)); |
93 | 3.52k | aTemp.set(0, 2, (fRight + fLeft) / (fRight - fLeft)); |
94 | 3.52k | aTemp.set(1, 2, (fTop + fBottom) / (fTop - fBottom)); |
95 | 3.52k | aTemp.set(2, 2, -1.0 * ((fFar + fNear) / (fFar - fNear))); |
96 | 3.52k | aTemp.set(3, 2, -1.0); |
97 | 3.52k | aTemp.set(2, 3, -1.0 * ((2.0 * fFar * fNear) / (fFar - fNear))); |
98 | 3.52k | aTemp.set(3, 3, 0.0); |
99 | | |
100 | 3.52k | rTarget *= aTemp; |
101 | 3.52k | } |
102 | | |
103 | | void B3dTransformationSet::Ortho(basegfx::B3DHomMatrix& rTarget, |
104 | | double fLeft, double fRight, double fBottom, double fTop, |
105 | | double fNear, double fFar) |
106 | 0 | { |
107 | 0 | if(fNear == fFar) |
108 | 0 | { |
109 | 0 | OSL_FAIL("Near and far clipping plane in Ortho definition are identical"); |
110 | 0 | fFar = fNear + 1.0; |
111 | 0 | } |
112 | 0 | if(fLeft == fRight) |
113 | 0 | { |
114 | 0 | OSL_FAIL("Left and right in Ortho definition are identical"); |
115 | 0 | fLeft -= 1.0; |
116 | 0 | fRight += 1.0; |
117 | 0 | } |
118 | 0 | if(fTop == fBottom) |
119 | 0 | { |
120 | 0 | OSL_FAIL("Top and bottom in Ortho definition are identical"); |
121 | 0 | fBottom -= 1.0; |
122 | 0 | fTop += 1.0; |
123 | 0 | } |
124 | 0 | basegfx::B3DHomMatrix aTemp; |
125 | |
|
126 | 0 | aTemp.set(0, 0, 2.0 / (fRight - fLeft)); |
127 | 0 | aTemp.set(1, 1, 2.0 / (fTop - fBottom)); |
128 | 0 | aTemp.set(2, 2, -1.0 * (2.0 / (fFar - fNear))); |
129 | 0 | aTemp.set(0, 3, -1.0 * ((fRight + fLeft) / (fRight - fLeft))); |
130 | 0 | aTemp.set(1, 3, -1.0 * ((fTop + fBottom) / (fTop - fBottom))); |
131 | 0 | aTemp.set(2, 3, -1.0 * ((fFar + fNear) / (fFar - fNear))); |
132 | |
|
133 | 0 | rTarget *= aTemp; |
134 | 0 | } |
135 | | |
136 | | /// reset values |
137 | | void B3dTransformationSet::Reset() |
138 | 3.52k | { |
139 | | // Reset matrices to identity matrices |
140 | 3.52k | maObjectTrans.identity(); |
141 | 3.52k | PostSetObjectTrans(); |
142 | | |
143 | 3.52k | Orientation(maOrientation); |
144 | 3.52k | PostSetOrientation(); |
145 | | |
146 | 3.52k | maTexture.identity(); |
147 | | |
148 | 3.52k | mfLeftBound = mfBottomBound = -1.0; |
149 | 3.52k | mfRightBound = mfTopBound = 1.0; |
150 | | |
151 | 3.52k | mfRatio = 0.0; |
152 | | |
153 | 3.52k | maViewportRectangle = tools::Rectangle(-1, -1, 2, 2); |
154 | 3.52k | maVisibleRectangle = maViewportRectangle; |
155 | | |
156 | 3.52k | mbPerspective = true; |
157 | | |
158 | 3.52k | mbProjectionValid = false; |
159 | | |
160 | 3.52k | CalcViewport(); |
161 | 3.52k | } |
162 | | |
163 | | /// Object transformation |
164 | | void B3dTransformationSet::PostSetObjectTrans() |
165 | 3.52k | { |
166 | | // Assign and compute inverse |
167 | 3.52k | maInvObjectTrans = maObjectTrans; |
168 | 3.52k | maInvObjectTrans.invert(); |
169 | 3.52k | } |
170 | | |
171 | | void B3dTransformationSet::SetOrientation(const basegfx::B3DPoint& rVRP, const basegfx::B3DVector& rVPN, const basegfx::B3DVector& rVUP) |
172 | 17.6k | { |
173 | 17.6k | maOrientation.identity(); |
174 | 17.6k | Orientation(maOrientation, rVRP, rVPN, rVUP); |
175 | | |
176 | 17.6k | PostSetOrientation(); |
177 | 17.6k | } |
178 | | |
179 | | void B3dTransformationSet::PostSetOrientation() |
180 | 21.1k | { |
181 | | // Assign and compute inverse |
182 | 21.1k | maInvOrientation = maOrientation; |
183 | 21.1k | maInvOrientation.invert(); |
184 | 21.1k | } |
185 | | |
186 | | /// Projections for transformations |
187 | | void B3dTransformationSet::SetProjection(const basegfx::B3DHomMatrix& mProject) |
188 | 3.52k | { |
189 | 3.52k | maProjection = mProject; |
190 | 3.52k | PostSetProjection(); |
191 | 3.52k | } |
192 | | |
193 | | const basegfx::B3DHomMatrix& B3dTransformationSet::GetProjection() |
194 | 3.52k | { |
195 | 3.52k | if(!mbProjectionValid) |
196 | 0 | CalcViewport(); |
197 | 3.52k | return maProjection; |
198 | 3.52k | } |
199 | | |
200 | | void B3dTransformationSet::PostSetProjection() |
201 | 3.52k | { |
202 | | // Assign and compute inverse |
203 | 3.52k | maInvProjection = GetProjection(); |
204 | 3.52k | maInvProjection.invert(); |
205 | 3.52k | } |
206 | | |
207 | | /// Transformations for viewport |
208 | | void B3dTransformationSet::CalcViewport() |
209 | 3.52k | { |
210 | | // Parameters for projection |
211 | 3.52k | double fLeft(mfLeftBound); |
212 | 3.52k | double fRight(mfRightBound); |
213 | 3.52k | double fBottom(mfBottomBound); |
214 | 3.52k | double fTop(mfTopBound); |
215 | | |
216 | | // Adjust projection to aspect ratio, if set |
217 | 3.52k | if(GetRatio() != 0.0) |
218 | 0 | { |
219 | | // Compute current aspect ratio of boundaries |
220 | 0 | double fBoundWidth = static_cast<double>(maViewportRectangle.GetWidth() + 1); |
221 | 0 | double fBoundHeight = static_cast<double>(maViewportRectangle.GetHeight() + 1); |
222 | 0 | double fActRatio = 1; |
223 | 0 | double fFactor; |
224 | |
|
225 | 0 | if(fBoundWidth != 0.0) |
226 | 0 | fActRatio = fBoundHeight / fBoundWidth; |
227 | | // FIXME else in this case has a lot of problems, should this return. |
228 | | |
229 | | // scale down larger part |
230 | 0 | if(fActRatio > mfRatio) |
231 | 0 | { |
232 | | // scale down Y |
233 | 0 | fFactor = fActRatio; |
234 | 0 | fTop *= fFactor; |
235 | 0 | fBottom *= fFactor; |
236 | 0 | } |
237 | 0 | else |
238 | 0 | { |
239 | | // scale down X |
240 | 0 | fFactor = 1.0 / fActRatio; |
241 | 0 | fRight *= fFactor; |
242 | 0 | fLeft *= fFactor; |
243 | 0 | } |
244 | 0 | } |
245 | | |
246 | | // Do projection and object areas overlap? |
247 | 3.52k | maSetBound = maViewportRectangle; |
248 | | |
249 | | // Reset projection with new values |
250 | 3.52k | basegfx::B3DHomMatrix aNewProjection; |
251 | | |
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 | 3.52k | const double fDistPart((gfFarBound - gfNearBound) * 0.0001); |
257 | | |
258 | | // To avoid critical clipping, set Near & Far generously |
259 | 3.52k | if(mbPerspective) |
260 | 3.52k | { |
261 | 3.52k | Frustum(aNewProjection, fLeft, fRight, fBottom, fTop, gfNearBound - fDistPart, gfFarBound + fDistPart); |
262 | 3.52k | } |
263 | 0 | else |
264 | 0 | { |
265 | 0 | Ortho(aNewProjection, fLeft, fRight, fBottom, fTop, gfNearBound - fDistPart, gfFarBound + fDistPart); |
266 | 0 | } |
267 | | |
268 | | // Set to true to guarantee loop termination |
269 | 3.52k | mbProjectionValid = true; |
270 | | |
271 | | // set new projection |
272 | 3.52k | SetProjection(aNewProjection); |
273 | | |
274 | | // fill parameters for ViewportTransformation |
275 | | // Translation |
276 | 3.52k | maTranslate.setX(static_cast<double>(maSetBound.Left()) + ((maSetBound.GetWidth() - 1) / 2.0)); |
277 | 3.52k | maTranslate.setY(static_cast<double>(maSetBound.Top()) + ((maSetBound.GetHeight() - 1) / 2.0)); |
278 | 3.52k | maTranslate.setZ(ZBUFFER_DEPTH_RANGE / 2.0); |
279 | | |
280 | | // Scaling |
281 | 3.52k | maScale.setX((maSetBound.GetWidth() - 1) / 2.0); |
282 | 3.52k | maScale.setY((maSetBound.GetHeight() - 1) / -2.0); |
283 | 3.52k | maScale.setZ(ZBUFFER_DEPTH_RANGE / 2.0); |
284 | 3.52k | } |
285 | | |
286 | | void B3dTransformationSet::SetRatio(double fNew) |
287 | 7.05k | { |
288 | 7.05k | if(mfRatio != fNew) |
289 | 0 | { |
290 | 0 | mfRatio = fNew; |
291 | 0 | mbProjectionValid = false; |
292 | 0 | } |
293 | 7.05k | } |
294 | | |
295 | | void B3dTransformationSet::SetDeviceRectangle(double fL, double fR, double fB, double fT) |
296 | 3.52k | { |
297 | 3.52k | if(fL != mfLeftBound || fR != mfRightBound || fB != mfBottomBound || fT != mfTopBound) |
298 | 3.52k | { |
299 | 3.52k | mfLeftBound = fL; |
300 | 3.52k | mfRightBound = fR; |
301 | 3.52k | mfBottomBound = fB; |
302 | 3.52k | mfTopBound = fT; |
303 | | |
304 | 3.52k | mbProjectionValid = false; |
305 | | |
306 | | // Broadcast changes |
307 | 3.52k | DeviceRectangleChange(); |
308 | 3.52k | } |
309 | 3.52k | } |
310 | | |
311 | | void B3dTransformationSet::DeviceRectangleChange() |
312 | 3.52k | { |
313 | 3.52k | } |
314 | | |
315 | | void B3dTransformationSet::SetPerspective(bool bNew) |
316 | 7.05k | { |
317 | 7.05k | if(mbPerspective != bNew) |
318 | 3.18k | { |
319 | 3.18k | mbPerspective = bNew; |
320 | 3.18k | mbProjectionValid = false; |
321 | 3.18k | } |
322 | 7.05k | } |
323 | | |
324 | | void B3dTransformationSet::SetViewportRectangle(tools::Rectangle const & rRect, tools::Rectangle const & rVisible) |
325 | 17.6k | { |
326 | 17.6k | if(rRect != maViewportRectangle || rVisible != maVisibleRectangle) |
327 | 14.1k | { |
328 | 14.1k | maViewportRectangle = rRect; |
329 | 14.1k | maVisibleRectangle = rVisible; |
330 | | |
331 | 14.1k | mbProjectionValid = false; |
332 | 14.1k | } |
333 | 17.6k | } |
334 | | |
335 | | // direct access to various transformations |
336 | | |
337 | | basegfx::B3DPoint B3dTransformationSet::WorldToEyeCoor(const basegfx::B3DPoint& rVec) |
338 | 7.05k | { |
339 | 7.05k | basegfx::B3DPoint aVec(rVec); |
340 | 7.05k | aVec *= maOrientation; |
341 | 7.05k | return aVec; |
342 | 7.05k | } |
343 | | |
344 | | basegfx::B3DPoint B3dTransformationSet::EyeToWorldCoor(const basegfx::B3DPoint& rVec) |
345 | 0 | { |
346 | 0 | basegfx::B3DPoint aVec(rVec); |
347 | 0 | aVec *= maInvOrientation; |
348 | 0 | return aVec; |
349 | 0 | } |
350 | | |
351 | | // B3dViewport ----------------------------------------------------------------- |
352 | | |
353 | | B3dViewport::B3dViewport() |
354 | 3.52k | : aVRP(0, 0, 0), |
355 | 3.52k | aVPN(0, 0, 1), |
356 | 3.52k | aVUV(0, 1, 0) |
357 | 3.52k | { |
358 | 3.52k | CalcOrientation(); |
359 | 3.52k | } |
360 | | |
361 | | B3dViewport::~B3dViewport() |
362 | | { |
363 | | } |
364 | | |
365 | | void B3dViewport::SetVUV(const basegfx::B3DVector& rNewVUV) |
366 | 0 | { |
367 | 0 | aVUV = rNewVUV; |
368 | 0 | CalcOrientation(); |
369 | 0 | } |
370 | | |
371 | | void B3dViewport::SetViewportValues( |
372 | | const basegfx::B3DPoint& rNewVRP, |
373 | | const basegfx::B3DVector& rNewVPN, |
374 | | const basegfx::B3DVector& rNewVUV) |
375 | 14.1k | { |
376 | 14.1k | aVRP = rNewVRP; |
377 | 14.1k | aVPN = rNewVPN; |
378 | 14.1k | aVUV = rNewVUV; |
379 | 14.1k | CalcOrientation(); |
380 | 14.1k | } |
381 | | |
382 | | void B3dViewport::CalcOrientation() |
383 | 17.6k | { |
384 | 17.6k | SetOrientation(aVRP, aVPN, aVUV); |
385 | 17.6k | } |
386 | | |
387 | | // B3dCamera ------------------------------------------------------------------- |
388 | | |
389 | | B3dCamera::B3dCamera( |
390 | | const basegfx::B3DPoint& rPos, const basegfx::B3DVector& rLkAt, |
391 | | double fFocLen, double fBnkAng) |
392 | 3.52k | : aPosition(rPos), |
393 | 3.52k | aLookAt(rLkAt), |
394 | 3.52k | fFocalLength(fFocLen), |
395 | 3.52k | fBankAngle(fBnkAng) |
396 | 3.52k | { |
397 | 3.52k | CalcNewViewportValues(); |
398 | 3.52k | } |
399 | | |
400 | | B3dCamera::~B3dCamera() |
401 | | { |
402 | | } |
403 | | |
404 | | void B3dCamera::DeviceRectangleChange() |
405 | 3.52k | { |
406 | | // call parent |
407 | 3.52k | B3dViewport::DeviceRectangleChange(); |
408 | | |
409 | | // react to changes |
410 | 3.52k | CalcNewViewportValues(); |
411 | 3.52k | } |
412 | | |
413 | | void B3dCamera::CalcNewViewportValues() |
414 | 7.05k | { |
415 | 7.05k | basegfx::B3DVector aNewVPN(aPosition - aLookAt); |
416 | | |
417 | 7.05k | basegfx::B3DVector aNewVUV(0.0, 1.0, 0.0); |
418 | 7.05k | if(aNewVPN.getLength() < aNewVPN.getY()) |
419 | 0 | aNewVUV.setX(0.5); |
420 | | |
421 | 7.05k | aNewVUV.normalize(); |
422 | 7.05k | aNewVPN.normalize(); |
423 | | |
424 | 7.05k | basegfx::B3DVector aNewToTheRight = aNewVPN.getPerpendicular(aNewVUV); |
425 | 7.05k | aNewToTheRight.normalize(); |
426 | 7.05k | aNewVUV = aNewToTheRight.getPerpendicular(aNewVPN); |
427 | 7.05k | aNewVUV.normalize(); |
428 | | |
429 | 7.05k | SetViewportValues(aPosition, aNewVPN, aNewVUV); |
430 | 7.05k | CalcFocalLength(); |
431 | | |
432 | 7.05k | if(fBankAngle != 0.0) |
433 | 0 | { |
434 | 0 | basegfx::B3DHomMatrix aRotMat; |
435 | 0 | aRotMat.rotate(0.0, 0.0, fBankAngle); |
436 | 0 | basegfx::B3DVector aUp(0.0, 1.0, 0.0); |
437 | 0 | aUp *= aRotMat; |
438 | 0 | aUp = EyeToWorldCoor(aUp); |
439 | 0 | aUp.normalize(); |
440 | 0 | SetVUV(aUp); |
441 | 0 | } |
442 | 7.05k | } |
443 | | |
444 | | void B3dCamera::CalcFocalLength() |
445 | 7.05k | { |
446 | 7.05k | double fWidth = GetDeviceRectangleWidth(); |
447 | | |
448 | | // Adjust focal length based on given position |
449 | 7.05k | basegfx::B3DPoint aOldPosition = WorldToEyeCoor({}); |
450 | 7.05k | if(fWidth != 0.0) |
451 | 7.05k | fFocalLength = aOldPosition.getZ() / fWidth * 35.0; |
452 | 7.05k | if(fFocalLength < 5.0) |
453 | 7.05k | fFocalLength = 5.0; |
454 | 7.05k | } |
455 | | |
456 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |