~ubuntu-branches/ubuntu/trusty/freeimage/trusty-proposed

« back to all changes in this revision

Viewing changes to Source/OpenEXR/Imath/ImathFrustum.h

  • Committer: Package Import Robot
  • Author(s): Scott Howard
  • Date: 2014-01-13 21:57:45 UTC
  • mfrom: (8.1.1 sid)
  • Revision ID: package-import@ubuntu.com-20140113215745-3y21c8ro0ih30hfg
Tags: 3.15.4-1
* QA Upload
* New upstream minor release 
  - Includes fix to build on !linux (Closes: #650485)
* Refreshed patches (line endings had to change)
  - Remove document-mode.patch (accepted upstream)
* Lintian fixes: S-V 3.9.5, DM-Upload-Allowed removed
* Remove document-mode.patch (accepted upstream)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
///////////////////////////////////////////////////////////////////////////
2
 
//
3
 
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
4
 
// Digital Ltd. LLC
5
 
// 
6
 
// All rights reserved.
7
 
// 
8
 
// Redistribution and use in source and binary forms, with or without
9
 
// modification, are permitted provided that the following conditions are
10
 
// met:
11
 
// *       Redistributions of source code must retain the above copyright
12
 
// notice, this list of conditions and the following disclaimer.
13
 
// *       Redistributions in binary form must reproduce the above
14
 
// copyright notice, this list of conditions and the following disclaimer
15
 
// in the documentation and/or other materials provided with the
16
 
// distribution.
17
 
// *       Neither the name of Industrial Light & Magic nor the names of
18
 
// its contributors may be used to endorse or promote products derived
19
 
// from this software without specific prior written permission. 
20
 
// 
21
 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
 
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
 
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
 
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
 
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
 
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
 
//
33
 
///////////////////////////////////////////////////////////////////////////
34
 
 
35
 
 
36
 
 
37
 
#ifndef INCLUDED_IMATHFRUSTUM_H
38
 
#define INCLUDED_IMATHFRUSTUM_H
39
 
 
40
 
 
41
 
#include "ImathVec.h"
42
 
#include "ImathPlane.h"
43
 
#include "ImathLine.h"
44
 
#include "ImathMatrix.h"
45
 
#include "ImathLimits.h"
46
 
#include "ImathFun.h"
47
 
#include "IexMathExc.h"
48
 
 
49
 
#if defined _WIN32 || defined _WIN64
50
 
    #ifdef near
51
 
        #define _redef_near
52
 
        #undef near
53
 
    #endif
54
 
    #ifdef far
55
 
        #define _redef_far
56
 
        #undef far
57
 
    #endif
58
 
#endif
59
 
 
60
 
namespace Imath {
61
 
 
62
 
//
63
 
//      template class Frustum<T>
64
 
//
65
 
//      The frustum is always located with the eye point at the
66
 
//      origin facing down -Z. This makes the Frustum class 
67
 
//      compatable with OpenGL (or anything that assumes a camera
68
 
//      looks down -Z, hence with a right-handed coordinate system) 
69
 
//      but not with RenderMan which assumes the camera looks down
70
 
//      +Z. Additional functions are provided for conversion from
71
 
//      and from various camera coordinate spaces.
72
 
//
73
 
 
74
 
 
75
 
template<class T>
76
 
class Frustum
77
 
{
78
 
  public:
79
 
    Frustum();
80
 
    Frustum(const Frustum &);
81
 
    Frustum(T near, T far, T left, T right, T top, T bottom, bool ortho=false);
82
 
    Frustum(T near, T far, T fovx, T fovy, T aspect);
83
 
    virtual ~Frustum();
84
 
 
85
 
    //--------------------
86
 
    // Assignment operator
87
 
    //--------------------
88
 
 
89
 
    const Frustum &operator     = (const Frustum &);
90
 
 
91
 
    //--------------------
92
 
    //  Operators:  ==, !=
93
 
    //--------------------
94
 
    
95
 
    bool                        operator == (const Frustum<T> &src) const;
96
 
    bool                        operator != (const Frustum<T> &src) const;
97
 
 
98
 
    //--------------------------------------------------------
99
 
    //  Set functions change the entire state of the Frustum
100
 
    //--------------------------------------------------------
101
 
 
102
 
    void                set(T near, T far, 
103
 
                            T left, T right, 
104
 
                            T top, T bottom, 
105
 
                            bool ortho=false);
106
 
 
107
 
    void                set(T near, T far, T fovx, T fovy, T aspect);
108
 
 
109
 
    //------------------------------------------------------
110
 
    //  These functions modify an already valid frustum state
111
 
    //------------------------------------------------------
112
 
 
113
 
    void                modifyNearAndFar(T near, T far);
114
 
    void                setOrthographic(bool);
115
 
 
116
 
    //--------------
117
 
    //  Access
118
 
    //--------------
119
 
 
120
 
    bool                orthographic() const    { return _orthographic; }
121
 
    T                   near() const            { return _near;         }
122
 
    T           hither() const      { return _near;     }
123
 
    T                   far() const             { return _far;          }
124
 
    T           yon() const     { return _far;      }
125
 
    T                   left() const            { return _left;         }
126
 
    T                   right() const           { return _right;        }
127
 
    T                   bottom() const          { return _bottom;       }
128
 
    T                   top() const             { return _top;          }
129
 
 
130
 
    //-----------------------------------------------------------------------
131
 
    //  Sets the planes in p to be the six bounding planes of the frustum, in
132
 
    //  the following order: top, right, bottom, left, near, far.
133
 
    //  Note that the planes have normals that point out of the frustum.
134
 
    //  The version of this routine that takes a matrix applies that matrix
135
 
    //  to transform the frustum before setting the planes.
136
 
    //-----------------------------------------------------------------------
137
 
 
138
 
    void                planes(Plane3<T> p[6]);
139
 
    void                planes(Plane3<T> p[6], const Matrix44<T> &M);
140
 
 
141
 
    //----------------------
142
 
    //  Derived Quantities
143
 
    //----------------------
144
 
 
145
 
    T                   fovx() const;
146
 
    T                   fovy() const;
147
 
    T                   aspect() const;
148
 
    Matrix44<T>         projectionMatrix() const;
149
 
 
150
 
    //-----------------------------------------------------------------------
151
 
    //  Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1 
152
 
    //  and -1 <= bottom <= top <= 1) of this Frustum, and returns a new
153
 
    //  Frustum whose near clipping-plane window is that rectangle in local
154
 
    //  space.  
155
 
    //-----------------------------------------------------------------------
156
 
 
157
 
    Frustum<T>          window(T left, T right, T top, T bottom) const;
158
 
 
159
 
    //----------------------------------------------------------
160
 
    // Projection is in screen space / Conversion from Z-Buffer
161
 
    //----------------------------------------------------------
162
 
 
163
 
    Line3<T>            projectScreenToRay( const Vec2<T> & ) const;
164
 
    Vec2<T>             projectPointToScreen( const Vec3<T> & ) const;
165
 
 
166
 
    T                   ZToDepth(long zval, long min, long max) const;
167
 
    T                   normalizedZToDepth(T zval) const;
168
 
    long                DepthToZ(T depth, long zmin, long zmax) const;
169
 
 
170
 
    T                   worldRadius(const Vec3<T> &p, T radius) const;
171
 
    T                   screenRadius(const Vec3<T> &p, T radius) const;
172
 
 
173
 
 
174
 
  protected:
175
 
 
176
 
    Vec2<T>             screenToLocal( const Vec2<T> & ) const;
177
 
    Vec2<T>             localToScreen( const Vec2<T> & ) const;
178
 
 
179
 
  protected:
180
 
    T                   _near;
181
 
    T                   _far;
182
 
    T                   _left;
183
 
    T                   _right;
184
 
    T                   _top;
185
 
    T                   _bottom;
186
 
    bool                _orthographic;
187
 
};
188
 
 
189
 
 
190
 
template<class T>
191
 
inline Frustum<T>::Frustum()
192
 
{
193
 
    set(T (0.1),
194
 
        T (1000.0),
195
 
        T (-1.0),
196
 
        T (1.0),
197
 
        T (1.0),
198
 
        T (-1.0),
199
 
        false);
200
 
}
201
 
 
202
 
template<class T>
203
 
inline Frustum<T>::Frustum(const Frustum &f)
204
 
{
205
 
    *this = f;
206
 
}
207
 
 
208
 
template<class T>
209
 
inline Frustum<T>::Frustum(T n, T f, T l, T r, T t, T b, bool o)
210
 
{
211
 
    set(n,f,l,r,t,b,o);
212
 
}
213
 
 
214
 
template<class T>
215
 
inline Frustum<T>::Frustum(T near, T far, T fovx, T fovy, T aspect)
216
 
{
217
 
    set(near,far,fovx,fovy,aspect);
218
 
}
219
 
 
220
 
template<class T>
221
 
Frustum<T>::~Frustum()
222
 
{
223
 
}
224
 
 
225
 
template<class T>
226
 
const Frustum<T> &
227
 
Frustum<T>::operator = (const Frustum &f)
228
 
{
229
 
    _near         = f._near;
230
 
    _far          = f._far;
231
 
    _left         = f._left;
232
 
    _right        = f._right;
233
 
    _top          = f._top;
234
 
    _bottom       = f._bottom;
235
 
    _orthographic = f._orthographic;
236
 
 
237
 
    return *this;
238
 
}
239
 
 
240
 
template <class T>
241
 
bool
242
 
Frustum<T>::operator == (const Frustum<T> &src) const
243
 
{
244
 
    return
245
 
        _near         == src._near   &&
246
 
        _far          == src._far    &&
247
 
        _left         == src._left   &&
248
 
        _right        == src._right  &&
249
 
        _top          == src._top    &&
250
 
        _bottom       == src._bottom &&
251
 
        _orthographic == src._orthographic;
252
 
}
253
 
 
254
 
template <class T>
255
 
inline bool
256
 
Frustum<T>::operator != (const Frustum<T> &src) const
257
 
{
258
 
    return !operator== (src);
259
 
}
260
 
 
261
 
template<class T>
262
 
void Frustum<T>::set(T n, T f, T l, T r, T t, T b, bool o)
263
 
{
264
 
    _near           = n;
265
 
    _far            = f;
266
 
    _left           = l;
267
 
    _right          = r;
268
 
    _bottom         = b;
269
 
    _top            = t;
270
 
    _orthographic   = o;
271
 
}
272
 
 
273
 
template<class T>
274
 
void Frustum<T>::modifyNearAndFar(T n, T f)
275
 
{
276
 
    if ( _orthographic )
277
 
    {
278
 
        _near = n;
279
 
    }
280
 
    else
281
 
    {
282
 
        Line3<T>  lowerLeft( Vec3<T>(0,0,0), Vec3<T>(_left,_bottom,-_near) );
283
 
        Line3<T> upperRight( Vec3<T>(0,0,0), Vec3<T>(_right,_top,-_near) );
284
 
        Plane3<T> nearPlane( Vec3<T>(0,0,-1), n );
285
 
 
286
 
        Vec3<T> ll,ur;
287
 
        nearPlane.intersect(lowerLeft,ll);
288
 
        nearPlane.intersect(upperRight,ur);
289
 
 
290
 
        _left   = ll.x;
291
 
        _right  = ur.x;
292
 
        _top    = ur.y;
293
 
        _bottom = ll.y;
294
 
        _near   = n;
295
 
        _far    = f;
296
 
    }
297
 
 
298
 
    _far = f;
299
 
}
300
 
 
301
 
template<class T>
302
 
void Frustum<T>::setOrthographic(bool ortho)
303
 
{
304
 
    _orthographic   = ortho;
305
 
}
306
 
 
307
 
template<class T>
308
 
void Frustum<T>::set(T near, T far, T fovx, T fovy, T aspect)
309
 
{
310
 
    if (fovx != 0 && fovy != 0)
311
 
        throw Iex::ArgExc ("fovx and fovy cannot both be non-zero.");
312
 
 
313
 
    if (fovx != 0)
314
 
    {
315
 
        _right      = near * Math<T>::tan (fovx / 2);
316
 
        _left       = -_right;
317
 
        _top        = ((_right - _left) / aspect) / 2;
318
 
        _bottom     = -_top;
319
 
    }
320
 
    else
321
 
    {
322
 
        _top        = near * Math<T>::tan (fovy / 2);
323
 
        _bottom     = -_top;
324
 
        _right      = (_top - _bottom) * aspect / 2;
325
 
        _left       = -_right;
326
 
    }
327
 
    _near           = near;
328
 
    _far            = far;
329
 
    _orthographic   = false;
330
 
}
331
 
 
332
 
template<class T>
333
 
T Frustum<T>::fovx() const
334
 
{
335
 
    return Math<T>::atan2(_right,_near) - Math<T>::atan2(_left,_near);
336
 
}
337
 
 
338
 
template<class T>
339
 
T Frustum<T>::fovy() const
340
 
{
341
 
    return Math<T>::atan2(_top,_near) - Math<T>::atan2(_bottom,_near);
342
 
}
343
 
 
344
 
template<class T>
345
 
T Frustum<T>::aspect() const
346
 
{
347
 
    T rightMinusLeft = _right-_left;
348
 
    T topMinusBottom = _top-_bottom;
349
 
 
350
 
    if (abs(topMinusBottom) < 1 &&
351
 
        abs(rightMinusLeft) > limits<T>::max() * abs(topMinusBottom))
352
 
    {
353
 
        throw Iex::DivzeroExc ("Bad viewing frustum: "
354
 
                               "aspect ratio cannot be computed.");
355
 
    }
356
 
 
357
 
    return rightMinusLeft / topMinusBottom;
358
 
}
359
 
 
360
 
template<class T>
361
 
Matrix44<T> Frustum<T>::projectionMatrix() const
362
 
{
363
 
    T rightPlusLeft  = _right+_left;
364
 
    T rightMinusLeft = _right-_left;
365
 
 
366
 
    T topPlusBottom  = _top+_bottom;
367
 
    T topMinusBottom = _top-_bottom;
368
 
 
369
 
    T farPlusNear    = _far+_near;
370
 
    T farMinusNear   = _far-_near;
371
 
 
372
 
    if ((abs(rightMinusLeft) < 1 &&
373
 
         abs(rightPlusLeft) > limits<T>::max() * abs(rightMinusLeft)) ||
374
 
        (abs(topMinusBottom) < 1 &&
375
 
         abs(topPlusBottom) > limits<T>::max() * abs(topMinusBottom)) ||
376
 
        (abs(farMinusNear) < 1 &&
377
 
         abs(farPlusNear) > limits<T>::max() * abs(farMinusNear)))
378
 
    {
379
 
        throw Iex::DivzeroExc ("Bad viewing frustum: "
380
 
                               "projection matrix cannot be computed.");
381
 
    }
382
 
 
383
 
    if ( _orthographic )
384
 
    {
385
 
        T tx = -rightPlusLeft / rightMinusLeft;
386
 
        T ty = -topPlusBottom / topMinusBottom;
387
 
        T tz = -farPlusNear   / farMinusNear;
388
 
 
389
 
        if ((abs(rightMinusLeft) < 1 &&
390
 
             2 > limits<T>::max() * abs(rightMinusLeft)) ||
391
 
            (abs(topMinusBottom) < 1 &&
392
 
             2 > limits<T>::max() * abs(topMinusBottom)) ||
393
 
            (abs(farMinusNear) < 1 &&
394
 
             2 > limits<T>::max() * abs(farMinusNear)))
395
 
        {
396
 
            throw Iex::DivzeroExc ("Bad viewing frustum: "
397
 
                                   "projection matrix cannot be computed.");
398
 
        }
399
 
 
400
 
        T A  =  2 / rightMinusLeft;
401
 
        T B  =  2 / topMinusBottom;
402
 
        T C  = -2 / farMinusNear;
403
 
 
404
 
        return Matrix44<T>( A,  0,  0,  0,
405
 
                            0,  B,  0,  0,
406
 
                            0,  0,  C,  0,
407
 
                            tx, ty, tz, 1.f );
408
 
    }
409
 
    else
410
 
    {
411
 
        T A =  rightPlusLeft / rightMinusLeft;
412
 
        T B =  topPlusBottom / topMinusBottom;
413
 
        T C = -farPlusNear   / farMinusNear;
414
 
 
415
 
        T farTimesNear = -2 * _far * _near;
416
 
        if (abs(farMinusNear) < 1 &&
417
 
            abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
418
 
        {
419
 
            throw Iex::DivzeroExc ("Bad viewing frustum: "
420
 
                                   "projection matrix cannot be computed.");
421
 
        }
422
 
 
423
 
        T D = farTimesNear / farMinusNear;
424
 
 
425
 
        T twoTimesNear = 2 * _near;
426
 
 
427
 
        if ((abs(rightMinusLeft) < 1 &&
428
 
             abs(twoTimesNear) > limits<T>::max() * abs(rightMinusLeft)) ||
429
 
            (abs(topMinusBottom) < 1 &&
430
 
             abs(twoTimesNear) > limits<T>::max() * abs(topMinusBottom)))
431
 
        {
432
 
            throw Iex::DivzeroExc ("Bad viewing frustum: "
433
 
                                   "projection matrix cannot be computed.");
434
 
        }
435
 
 
436
 
        T E = twoTimesNear / rightMinusLeft;
437
 
        T F = twoTimesNear / topMinusBottom;
438
 
 
439
 
        return Matrix44<T>( E,  0,  0,  0,
440
 
                            0,  F,  0,  0,
441
 
                            A,  B,  C, -1,
442
 
                            0,  0,  D,  0 );
443
 
    }
444
 
}
445
 
 
446
 
template<class T>
447
 
Frustum<T> Frustum<T>::window(T l, T r, T t, T b) const
448
 
{
449
 
    // move it to 0->1 space
450
 
 
451
 
    Vec2<T> bl = screenToLocal( Vec2<T>(l,b) );
452
 
    Vec2<T> tr = screenToLocal( Vec2<T>(r,t) );
453
 
 
454
 
    return Frustum<T>(_near, _far, bl.x, tr.x, tr.y, bl.y, _orthographic);
455
 
}
456
 
 
457
 
 
458
 
template<class T>
459
 
Vec2<T> Frustum<T>::screenToLocal(const Vec2<T> &s) const
460
 
{
461
 
    return Vec2<T>( _left + (_right-_left) * (1.f+s.x) / 2.f,
462
 
                    _bottom + (_top-_bottom) * (1.f+s.y) / 2.f );
463
 
}
464
 
 
465
 
template<class T>
466
 
Vec2<T> Frustum<T>::localToScreen(const Vec2<T> &p) const
467
 
{
468
 
    T leftPlusRight  = _left - 2 * p.x + _right;
469
 
    T leftMinusRight = _left-_right;
470
 
    T bottomPlusTop  = _bottom - 2 * p.y + _top;
471
 
    T bottomMinusTop = _bottom-_top;
472
 
 
473
 
    if ((abs(leftMinusRight) < 1 &&
474
 
         abs(leftPlusRight) > limits<T>::max() * abs(leftMinusRight)) ||
475
 
        (abs(bottomMinusTop) < 1 &&
476
 
         abs(bottomPlusTop) > limits<T>::max() * abs(bottomMinusTop)))
477
 
    {
478
 
        throw Iex::DivzeroExc
479
 
            ("Bad viewing frustum: "
480
 
             "local-to-screen transformation cannot be computed");
481
 
    }
482
 
 
483
 
    return Vec2<T>( leftPlusRight / leftMinusRight,
484
 
                    bottomPlusTop / bottomMinusTop );
485
 
}
486
 
 
487
 
template<class T>
488
 
Line3<T> Frustum<T>::projectScreenToRay(const Vec2<T> &p) const
489
 
{
490
 
    Vec2<T> point = screenToLocal(p);
491
 
    if (orthographic())
492
 
        return Line3<T>( Vec3<T>(point.x,point.y, 0.0),
493
 
                         Vec3<T>(point.x,point.y,-_near));
494
 
    else
495
 
        return Line3<T>( Vec3<T>(0, 0, 0), Vec3<T>(point.x,point.y,-_near));
496
 
}
497
 
 
498
 
template<class T>
499
 
Vec2<T> Frustum<T>::projectPointToScreen(const Vec3<T> &point) const
500
 
{
501
 
    if (orthographic() || point.z == 0)
502
 
        return localToScreen( Vec2<T>( point.x, point.y ) );
503
 
    else
504
 
        return localToScreen( Vec2<T>( point.x * _near / -point.z, 
505
 
                                       point.y * _near / -point.z ) );
506
 
}
507
 
 
508
 
template<class T>
509
 
T Frustum<T>::ZToDepth(long zval,long zmin,long zmax) const
510
 
{
511
 
    int zdiff = zmax - zmin;
512
 
 
513
 
    if (zdiff == 0)
514
 
    {
515
 
        throw Iex::DivzeroExc
516
 
            ("Bad call to Frustum::ZToDepth: zmax == zmin");
517
 
    }
518
 
 
519
 
    if ( zval > zmax+1 ) zval -= zdiff;
520
 
 
521
 
    T fzval = (T(zval) - T(zmin)) / T(zdiff);
522
 
    return normalizedZToDepth(fzval);
523
 
}
524
 
 
525
 
template<class T>
526
 
T Frustum<T>::normalizedZToDepth(T zval) const
527
 
{
528
 
    T Zp = zval * 2.0 - 1;
529
 
 
530
 
    if ( _orthographic )
531
 
    {
532
 
        return   -(Zp*(_far-_near) + (_far+_near))/2;
533
 
    }
534
 
    else 
535
 
    {
536
 
        T farTimesNear = 2 * _far * _near;
537
 
        T farMinusNear = Zp * (_far - _near) - _far - _near;
538
 
 
539
 
        if (abs(farMinusNear) < 1 &&
540
 
            abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
541
 
        {
542
 
            throw Iex::DivzeroExc
543
 
                ("Frustum::normalizedZToDepth cannot be computed.  The "
544
 
                 "near and far clipping planes of the viewing frustum "
545
 
                 "may be too close to each other");
546
 
        }
547
 
 
548
 
        return farTimesNear / farMinusNear;
549
 
    }
550
 
}
551
 
 
552
 
template<class T>
553
 
long Frustum<T>::DepthToZ(T depth,long zmin,long zmax) const
554
 
{
555
 
    long zdiff     = zmax - zmin;
556
 
    T farMinusNear = _far-_near;
557
 
 
558
 
    if ( _orthographic )
559
 
    {
560
 
        T farPlusNear = 2*depth + _far + _near;
561
 
 
562
 
        if (abs(farMinusNear) < 1 &&
563
 
            abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
564
 
        {
565
 
            throw Iex::DivzeroExc
566
 
                ("Bad viewing frustum: near and far clipping planes "
567
 
                 "are too close to each other");
568
 
        }
569
 
 
570
 
        T Zp = -farPlusNear/farMinusNear;
571
 
        return long(0.5*(Zp+1)*zdiff) + zmin;
572
 
    }
573
 
    else 
574
 
    { 
575
 
        // Perspective
576
 
 
577
 
        T farTimesNear = 2*_far*_near;
578
 
        if (abs(depth) < 1 &&
579
 
            abs(farTimesNear) > limits<T>::max() * abs(depth))
580
 
        {
581
 
            throw Iex::DivzeroExc
582
 
                ("Bad call to DepthToZ function: value of `depth' "
583
 
                 "is too small");
584
 
        }
585
 
 
586
 
        T farPlusNear = farTimesNear/depth + _far + _near;
587
 
        if (abs(farMinusNear) < 1 &&
588
 
            abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
589
 
        {
590
 
            throw Iex::DivzeroExc
591
 
                ("Bad viewing frustum: near and far clipping planes "
592
 
                 "are too close to each other");
593
 
        }
594
 
 
595
 
        T Zp = farPlusNear/farMinusNear;
596
 
        return long(0.5*(Zp+1)*zdiff) + zmin;
597
 
    }
598
 
}
599
 
 
600
 
template<class T>
601
 
T Frustum<T>::screenRadius(const Vec3<T> &p, T radius) const
602
 
{
603
 
    // Derivation:
604
 
    // Consider X-Z plane.
605
 
    // X coord of projection of p = xp = p.x * (-_near / p.z)
606
 
    // Let q be p + (radius, 0, 0).
607
 
    // X coord of projection of q = xq = (p.x - radius)  * (-_near / p.z)
608
 
    // X coord of projection of segment from p to q = r = xp - xq
609
 
    //         = radius * (-_near / p.z)
610
 
    // A similar analysis holds in the Y-Z plane.
611
 
    // So r is the quantity we want to return.
612
 
 
613
 
    if (abs(p.z) > 1 || abs(-_near) < limits<T>::max() * abs(p.z))
614
 
    {
615
 
        return radius * (-_near / p.z);
616
 
    }
617
 
    else
618
 
    {
619
 
        throw Iex::DivzeroExc
620
 
            ("Bad call to Frustum::screenRadius: the magnitude of `p' "
621
 
             "is too small");
622
 
    }
623
 
 
624
 
    return radius * (-_near / p.z);
625
 
}
626
 
 
627
 
template<class T>
628
 
T Frustum<T>::worldRadius(const Vec3<T> &p, T radius) const
629
 
{
630
 
    if (abs(-_near) > 1 || abs(p.z) < limits<T>::max() * abs(-_near))
631
 
    {
632
 
        return radius * (p.z / -_near);
633
 
    }
634
 
    else
635
 
    {
636
 
        throw Iex::DivzeroExc
637
 
            ("Bad viewing frustum: the near clipping plane is too "
638
 
             "close to zero");
639
 
    }
640
 
}
641
 
 
642
 
template<class T>
643
 
void Frustum<T>::planes(Plane3<T> p[6])
644
 
{
645
 
    //
646
 
    //  Plane order: Top, Right, Bottom, Left, Near, Far.
647
 
    //  Normals point outwards.
648
 
    //
649
 
 
650
 
    if (! _orthographic)
651
 
    {
652
 
        Vec3<T> a( _left,  _bottom, -_near);
653
 
        Vec3<T> b( _left,  _top,    -_near);
654
 
        Vec3<T> c( _right, _top,    -_near);
655
 
        Vec3<T> d( _right, _bottom, -_near);
656
 
        Vec3<T> o(0,0,0);
657
 
 
658
 
        p[0].set( o, c, b );
659
 
        p[1].set( o, d, c );
660
 
        p[2].set( o, a, d );
661
 
        p[3].set( o, b, a );
662
 
    }
663
 
    else
664
 
    {
665
 
        p[0].set( Vec3<T>( 0, 1, 0), _top );
666
 
        p[1].set( Vec3<T>( 1, 0, 0), _right );
667
 
        p[2].set( Vec3<T>( 0,-1, 0),-_bottom );
668
 
        p[3].set( Vec3<T>(-1, 0, 0),-_left );
669
 
    }
670
 
    p[4].set( Vec3<T>(0, 0, 1), -_near );
671
 
    p[5].set( Vec3<T>(0, 0,-1), _far );
672
 
}
673
 
 
674
 
 
675
 
template<class T>
676
 
void Frustum<T>::planes(Plane3<T> p[6], const Matrix44<T> &M)
677
 
{
678
 
    //
679
 
    //  Plane order: Top, Right, Bottom, Left, Near, Far.
680
 
    //  Normals point outwards.
681
 
    //
682
 
 
683
 
    Vec3<T> a   = Vec3<T>( _left,  _bottom, -_near) * M;
684
 
    Vec3<T> b   = Vec3<T>( _left,  _top,    -_near) * M;
685
 
    Vec3<T> c   = Vec3<T>( _right, _top,    -_near) * M;
686
 
    Vec3<T> d   = Vec3<T>( _right, _bottom, -_near) * M;
687
 
    if (! _orthographic)
688
 
    {
689
 
        double s    = _far / double(_near);
690
 
        T farLeft   = (T) (s * _left);
691
 
        T farRight  = (T) (s * _right);
692
 
        T farTop    = (T) (s * _top);
693
 
        T farBottom = (T) (s * _bottom);
694
 
        Vec3<T> e   = Vec3<T>( farLeft,  farBottom, -_far) * M;
695
 
        Vec3<T> f   = Vec3<T>( farLeft,  farTop,    -_far) * M;
696
 
        Vec3<T> g   = Vec3<T>( farRight, farTop,    -_far) * M;
697
 
        Vec3<T> o   = Vec3<T>(0,0,0) * M;
698
 
        p[0].set( o, c, b );
699
 
        p[1].set( o, d, c );
700
 
        p[2].set( o, a, d );
701
 
        p[3].set( o, b, a );
702
 
        p[4].set( a, d, c );
703
 
        p[5].set( e, f, g );
704
 
     }
705
 
    else
706
 
    {
707
 
        Vec3<T> e   = Vec3<T>( _left,  _bottom, -_far) * M;
708
 
        Vec3<T> f   = Vec3<T>( _left,  _top,    -_far) * M;
709
 
        Vec3<T> g   = Vec3<T>( _right, _top,    -_far) * M;
710
 
        Vec3<T> h   = Vec3<T>( _right, _bottom, -_far) * M;
711
 
        p[0].set( c, g, f );
712
 
        p[1].set( d, h, g );
713
 
        p[2].set( a, e, h );
714
 
        p[3].set( b, f, e );
715
 
        p[4].set( a, d, c );
716
 
        p[5].set( e, f, g );
717
 
    }
718
 
}
719
 
 
720
 
typedef Frustum<float>  Frustumf;
721
 
typedef Frustum<double> Frustumd;
722
 
 
723
 
 
724
 
} // namespace Imath
725
 
 
726
 
 
727
 
#if defined _WIN32 || defined _WIN64
728
 
    #ifdef _redef_near
729
 
        #define near
730
 
    #endif
731
 
    #ifdef _redef_far
732
 
        #define far
733
 
    #endif
734
 
#endif
735
 
 
736
 
#endif
 
1
///////////////////////////////////////////////////////////////////////////
 
2
//
 
3
// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
 
4
// Digital Ltd. LLC
 
5
// 
 
6
// All rights reserved.
 
7
// 
 
8
// Redistribution and use in source and binary forms, with or without
 
9
// modification, are permitted provided that the following conditions are
 
10
// met:
 
11
// *       Redistributions of source code must retain the above copyright
 
12
// notice, this list of conditions and the following disclaimer.
 
13
// *       Redistributions in binary form must reproduce the above
 
14
// copyright notice, this list of conditions and the following disclaimer
 
15
// in the documentation and/or other materials provided with the
 
16
// distribution.
 
17
// *       Neither the name of Industrial Light & Magic nor the names of
 
18
// its contributors may be used to endorse or promote products derived
 
19
// from this software without specific prior written permission. 
 
20
// 
 
21
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
22
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
23
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
24
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
25
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
26
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
27
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
28
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
29
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
30
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
31
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
32
//
 
33
///////////////////////////////////////////////////////////////////////////
 
34
 
 
35
 
 
36
 
 
37
#ifndef INCLUDED_IMATHFRUSTUM_H
 
38
#define INCLUDED_IMATHFRUSTUM_H
 
39
 
 
40
 
 
41
#include "ImathVec.h"
 
42
#include "ImathPlane.h"
 
43
#include "ImathLine.h"
 
44
#include "ImathMatrix.h"
 
45
#include "ImathLimits.h"
 
46
#include "ImathFun.h"
 
47
#include "IexMathExc.h"
 
48
 
 
49
namespace Imath {
 
50
 
 
51
//
 
52
//      template class Frustum<T>
 
53
//
 
54
//      The frustum is always located with the eye point at the
 
55
//      origin facing down -Z. This makes the Frustum class 
 
56
//      compatable with OpenGL (or anything that assumes a camera
 
57
//      looks down -Z, hence with a right-handed coordinate system) 
 
58
//      but not with RenderMan which assumes the camera looks down
 
59
//      +Z. Additional functions are provided for conversion from
 
60
//      and from various camera coordinate spaces.
 
61
//
 
62
//      nearPlane/farPlane: near/far are keywords used by Microsoft's
 
63
//      compiler, so we use nearPlane/farPlane instead to avoid
 
64
//      issues.  
 
65
 
 
66
 
 
67
template<class T>
 
68
class Frustum
 
69
{
 
70
  public:
 
71
    Frustum();
 
72
    Frustum(const Frustum &);
 
73
    Frustum(T nearPlane, T farPlane, T left, T right, T top, T bottom, bool ortho=false);
 
74
    Frustum(T nearPlane, T farPlane, T fovx, T fovy, T aspect);
 
75
    virtual ~Frustum();
 
76
 
 
77
    //--------------------
 
78
    // Assignment operator
 
79
    //--------------------
 
80
 
 
81
    const Frustum &operator     = (const Frustum &);
 
82
 
 
83
    //--------------------
 
84
    //  Operators:  ==, !=
 
85
    //--------------------
 
86
    
 
87
    bool                        operator == (const Frustum<T> &src) const;
 
88
    bool                        operator != (const Frustum<T> &src) const;
 
89
 
 
90
    //--------------------------------------------------------
 
91
    //  Set functions change the entire state of the Frustum
 
92
    //--------------------------------------------------------
 
93
 
 
94
    void                set(T nearPlane, T farPlane, 
 
95
                            T left, T right, 
 
96
                            T top, T bottom, 
 
97
                            bool ortho=false);
 
98
 
 
99
    void                set(T nearPlane, T farPlane, T fovx, T fovy, T aspect);
 
100
 
 
101
    //------------------------------------------------------
 
102
    //  These functions modify an already valid frustum state
 
103
    //------------------------------------------------------
 
104
 
 
105
    void                modifyNearAndFar(T nearPlane, T farPlane);
 
106
    void                setOrthographic(bool);
 
107
 
 
108
    //--------------
 
109
    //  Access
 
110
    //--------------
 
111
    
 
112
    bool                orthographic() const    { return _orthographic; }
 
113
    T                   nearPlane() const       { return _nearPlane;    }
 
114
    T                   hither() const          { return _nearPlane;    }
 
115
    T                   farPlane() const        { return _farPlane;     }
 
116
    T                   yon() const             { return _farPlane;     }
 
117
    T                   left() const            { return _left;         }
 
118
    T                   right() const           { return _right;        }
 
119
    T                   bottom() const          { return _bottom;       }
 
120
    T                   top() const             { return _top;          }
 
121
 
 
122
    //-----------------------------------------------------------------------
 
123
    //  Sets the planes in p to be the six bounding planes of the frustum, in
 
124
    //  the following order: top, right, bottom, left, near, far.
 
125
    //  Note that the planes have normals that point out of the frustum.
 
126
    //  The version of this routine that takes a matrix applies that matrix
 
127
    //  to transform the frustum before setting the planes.
 
128
    //-----------------------------------------------------------------------
 
129
 
 
130
    void                planes(Plane3<T> p[6]);
 
131
    void                planes(Plane3<T> p[6], const Matrix44<T> &M);
 
132
 
 
133
    //----------------------
 
134
    //  Derived Quantities
 
135
    //----------------------
 
136
 
 
137
    T                           fovx() const;
 
138
    T                           fovy() const;
 
139
    T                           aspect() const;
 
140
    Matrix44<T>                 projectionMatrix() const;
 
141
    bool                        degenerate() const;
 
142
 
 
143
    //-----------------------------------------------------------------------
 
144
    //  Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1 
 
145
    //  and -1 <= bottom <= top <= 1) of this Frustum, and returns a new
 
146
    //  Frustum whose near clipping-plane window is that rectangle in local
 
147
    //  space.  
 
148
    //-----------------------------------------------------------------------
 
149
 
 
150
    Frustum<T>          window(T left, T right, T top, T bottom) const;
 
151
 
 
152
    //----------------------------------------------------------
 
153
    // Projection is in screen space / Conversion from Z-Buffer
 
154
    //----------------------------------------------------------
 
155
 
 
156
    Line3<T>            projectScreenToRay( const Vec2<T> & ) const;
 
157
    Vec2<T>             projectPointToScreen( const Vec3<T> & ) const;
 
158
 
 
159
    T                   ZToDepth(long zval, long min, long max) const;
 
160
    T                   normalizedZToDepth(T zval) const;
 
161
    long                DepthToZ(T depth, long zmin, long zmax) const;
 
162
 
 
163
    T                   worldRadius(const Vec3<T> &p, T radius) const;
 
164
    T                   screenRadius(const Vec3<T> &p, T radius) const;
 
165
 
 
166
 
 
167
  protected:
 
168
 
 
169
    Vec2<T>             screenToLocal( const Vec2<T> & ) const;
 
170
    Vec2<T>             localToScreen( const Vec2<T> & ) const;
 
171
 
 
172
  protected:
 
173
    T                   _nearPlane;
 
174
    T                   _farPlane;
 
175
    T                   _left;
 
176
    T                   _right;
 
177
    T                   _top;
 
178
    T                   _bottom;
 
179
    bool                _orthographic;
 
180
};
 
181
 
 
182
 
 
183
template<class T>
 
184
inline Frustum<T>::Frustum()
 
185
{
 
186
    set(T (0.1),
 
187
        T (1000.0),
 
188
        T (-1.0),
 
189
        T (1.0),
 
190
        T (1.0),
 
191
        T (-1.0),
 
192
        false);
 
193
}
 
194
 
 
195
template<class T>
 
196
inline Frustum<T>::Frustum(const Frustum &f)
 
197
{
 
198
    *this = f;
 
199
}
 
200
 
 
201
template<class T>
 
202
inline Frustum<T>::Frustum(T n, T f, T l, T r, T t, T b, bool o)
 
203
{
 
204
    set(n,f,l,r,t,b,o);
 
205
}
 
206
 
 
207
template<class T>
 
208
inline Frustum<T>::Frustum(T nearPlane, T farPlane, T fovx, T fovy, T aspect)
 
209
{
 
210
    set(nearPlane,farPlane,fovx,fovy,aspect);
 
211
}
 
212
 
 
213
template<class T>
 
214
Frustum<T>::~Frustum()
 
215
{
 
216
}
 
217
 
 
218
template<class T>
 
219
const Frustum<T> &
 
220
Frustum<T>::operator = (const Frustum &f)
 
221
{
 
222
    _nearPlane    = f._nearPlane;
 
223
    _farPlane     = f._farPlane;
 
224
    _left         = f._left;
 
225
    _right        = f._right;
 
226
    _top          = f._top;
 
227
    _bottom       = f._bottom;
 
228
    _orthographic = f._orthographic;
 
229
 
 
230
    return *this;
 
231
}
 
232
 
 
233
template <class T>
 
234
bool
 
235
Frustum<T>::operator == (const Frustum<T> &src) const
 
236
{
 
237
    return
 
238
        _nearPlane    == src._nearPlane   &&
 
239
        _farPlane     == src._farPlane    &&
 
240
        _left         == src._left   &&
 
241
        _right        == src._right  &&
 
242
        _top          == src._top    &&
 
243
        _bottom       == src._bottom &&
 
244
        _orthographic == src._orthographic;
 
245
}
 
246
 
 
247
template <class T>
 
248
inline bool
 
249
Frustum<T>::operator != (const Frustum<T> &src) const
 
250
{
 
251
    return !operator== (src);
 
252
}
 
253
 
 
254
template<class T>
 
255
void Frustum<T>::set(T n, T f, T l, T r, T t, T b, bool o)
 
256
{
 
257
    _nearPlane      = n;
 
258
    _farPlane       = f;
 
259
    _left           = l;
 
260
    _right          = r;
 
261
    _bottom         = b;
 
262
    _top            = t;
 
263
    _orthographic   = o;
 
264
}
 
265
 
 
266
template<class T>
 
267
void Frustum<T>::modifyNearAndFar(T n, T f)
 
268
{
 
269
    if ( _orthographic )
 
270
    {
 
271
        _nearPlane = n;
 
272
    }
 
273
    else
 
274
    {
 
275
        Line3<T>  lowerLeft( Vec3<T>(0,0,0), Vec3<T>(_left,_bottom,-_nearPlane) );
 
276
        Line3<T> upperRight( Vec3<T>(0,0,0), Vec3<T>(_right,_top,-_nearPlane) );
 
277
        Plane3<T> nearPlane( Vec3<T>(0,0,-1), n );
 
278
 
 
279
        Vec3<T> ll,ur;
 
280
        nearPlane.intersect(lowerLeft,ll);
 
281
        nearPlane.intersect(upperRight,ur);
 
282
 
 
283
        _left      = ll.x;
 
284
        _right     = ur.x;
 
285
        _top       = ur.y;
 
286
        _bottom    = ll.y;
 
287
        _nearPlane = n;
 
288
        _farPlane  = f;
 
289
    }
 
290
 
 
291
    _farPlane = f;
 
292
}
 
293
 
 
294
template<class T>
 
295
void Frustum<T>::setOrthographic(bool ortho)
 
296
{
 
297
    _orthographic   = ortho;
 
298
}
 
299
 
 
300
template<class T>
 
301
void Frustum<T>::set(T nearPlane, T farPlane, T fovx, T fovy, T aspect)
 
302
{
 
303
    if (fovx != 0 && fovy != 0)
 
304
        throw Iex::ArgExc ("fovx and fovy cannot both be non-zero.");
 
305
 
 
306
    const T two = static_cast<T>(2);
 
307
 
 
308
    if (fovx != 0)
 
309
    {
 
310
        _right      = nearPlane * Math<T>::tan(fovx / two);
 
311
        _left       = -_right;
 
312
        _top        = ((_right - _left) / aspect) / two;
 
313
        _bottom     = -_top;
 
314
    }
 
315
    else
 
316
    {
 
317
        _top        = nearPlane * Math<T>::tan(fovy / two);
 
318
        _bottom     = -_top;
 
319
        _right      = (_top - _bottom) * aspect / two;
 
320
        _left       = -_right;
 
321
    }
 
322
    _nearPlane      = nearPlane;
 
323
    _farPlane       = farPlane;
 
324
    _orthographic   = false;
 
325
}
 
326
 
 
327
template<class T>
 
328
T Frustum<T>::fovx() const
 
329
{
 
330
    return Math<T>::atan2(_right,_nearPlane) - Math<T>::atan2(_left,_nearPlane);
 
331
}
 
332
 
 
333
template<class T>
 
334
T Frustum<T>::fovy() const
 
335
{
 
336
    return Math<T>::atan2(_top,_nearPlane) - Math<T>::atan2(_bottom,_nearPlane);
 
337
}
 
338
 
 
339
template<class T>
 
340
T Frustum<T>::aspect() const
 
341
{
 
342
    T rightMinusLeft = _right-_left;
 
343
    T topMinusBottom = _top-_bottom;
 
344
 
 
345
    if (abs(topMinusBottom) < 1 &&
 
346
        abs(rightMinusLeft) > limits<T>::max() * abs(topMinusBottom))
 
347
    {
 
348
        throw Iex::DivzeroExc ("Bad viewing frustum: "
 
349
                               "aspect ratio cannot be computed.");
 
350
    }
 
351
 
 
352
    return rightMinusLeft / topMinusBottom;
 
353
}
 
354
 
 
355
template<class T>
 
356
Matrix44<T> Frustum<T>::projectionMatrix() const
 
357
{
 
358
    T rightPlusLeft  = _right+_left;
 
359
    T rightMinusLeft = _right-_left;
 
360
 
 
361
    T topPlusBottom  = _top+_bottom;
 
362
    T topMinusBottom = _top-_bottom;
 
363
 
 
364
    T farPlusNear    = _farPlane+_nearPlane;
 
365
    T farMinusNear   = _farPlane-_nearPlane;
 
366
 
 
367
    if ((abs(rightMinusLeft) < 1 &&
 
368
         abs(rightPlusLeft) > limits<T>::max() * abs(rightMinusLeft)) ||
 
369
        (abs(topMinusBottom) < 1 &&
 
370
         abs(topPlusBottom) > limits<T>::max() * abs(topMinusBottom)) ||
 
371
        (abs(farMinusNear) < 1 &&
 
372
         abs(farPlusNear) > limits<T>::max() * abs(farMinusNear)))
 
373
    {
 
374
        throw Iex::DivzeroExc ("Bad viewing frustum: "
 
375
                               "projection matrix cannot be computed.");
 
376
    }
 
377
 
 
378
    if ( _orthographic )
 
379
    {
 
380
        T tx = -rightPlusLeft / rightMinusLeft;
 
381
        T ty = -topPlusBottom / topMinusBottom;
 
382
        T tz = -farPlusNear   / farMinusNear;
 
383
 
 
384
        if ((abs(rightMinusLeft) < 1 &&
 
385
             2 > limits<T>::max() * abs(rightMinusLeft)) ||
 
386
            (abs(topMinusBottom) < 1 &&
 
387
             2 > limits<T>::max() * abs(topMinusBottom)) ||
 
388
            (abs(farMinusNear) < 1 &&
 
389
             2 > limits<T>::max() * abs(farMinusNear)))
 
390
        {
 
391
            throw Iex::DivzeroExc ("Bad viewing frustum: "
 
392
                                   "projection matrix cannot be computed.");
 
393
        }
 
394
 
 
395
        T A  =  2 / rightMinusLeft;
 
396
        T B  =  2 / topMinusBottom;
 
397
        T C  = -2 / farMinusNear;
 
398
 
 
399
        return Matrix44<T>( A,  0,  0,  0,
 
400
                            0,  B,  0,  0,
 
401
                            0,  0,  C,  0,
 
402
                            tx, ty, tz, 1.f );
 
403
    }
 
404
    else
 
405
    {
 
406
        T A =  rightPlusLeft / rightMinusLeft;
 
407
        T B =  topPlusBottom / topMinusBottom;
 
408
        T C = -farPlusNear   / farMinusNear;
 
409
 
 
410
        T farTimesNear = -2 * _farPlane * _nearPlane;
 
411
        if (abs(farMinusNear) < 1 &&
 
412
            abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
 
413
        {
 
414
            throw Iex::DivzeroExc ("Bad viewing frustum: "
 
415
                                   "projection matrix cannot be computed.");
 
416
        }
 
417
 
 
418
        T D = farTimesNear / farMinusNear;
 
419
 
 
420
        T twoTimesNear = 2 * _nearPlane;
 
421
 
 
422
        if ((abs(rightMinusLeft) < 1 &&
 
423
             abs(twoTimesNear) > limits<T>::max() * abs(rightMinusLeft)) ||
 
424
            (abs(topMinusBottom) < 1 &&
 
425
             abs(twoTimesNear) > limits<T>::max() * abs(topMinusBottom)))
 
426
        {
 
427
            throw Iex::DivzeroExc ("Bad viewing frustum: "
 
428
                                   "projection matrix cannot be computed.");
 
429
        }
 
430
 
 
431
        T E = twoTimesNear / rightMinusLeft;
 
432
        T F = twoTimesNear / topMinusBottom;
 
433
 
 
434
        return Matrix44<T>( E,  0,  0,  0,
 
435
                            0,  F,  0,  0,
 
436
                            A,  B,  C, -1,
 
437
                            0,  0,  D,  0 );
 
438
    }
 
439
}
 
440
 
 
441
template<class T>
 
442
bool Frustum<T>::degenerate() const
 
443
{
 
444
    return (_nearPlane == _farPlane) ||
 
445
           (_left == _right) ||
 
446
           (_top == _bottom);
 
447
}
 
448
 
 
449
template<class T>
 
450
Frustum<T> Frustum<T>::window(T l, T r, T t, T b) const
 
451
{
 
452
    // move it to 0->1 space
 
453
 
 
454
    Vec2<T> bl = screenToLocal( Vec2<T>(l,b) );
 
455
    Vec2<T> tr = screenToLocal( Vec2<T>(r,t) );
 
456
 
 
457
    return Frustum<T>(_nearPlane, _farPlane, bl.x, tr.x, tr.y, bl.y, _orthographic);
 
458
}
 
459
 
 
460
 
 
461
template<class T>
 
462
Vec2<T> Frustum<T>::screenToLocal(const Vec2<T> &s) const
 
463
{
 
464
    return Vec2<T>( _left + (_right-_left) * (1.f+s.x) / 2.f,
 
465
                    _bottom + (_top-_bottom) * (1.f+s.y) / 2.f );
 
466
}
 
467
 
 
468
template<class T>
 
469
Vec2<T> Frustum<T>::localToScreen(const Vec2<T> &p) const
 
470
{
 
471
    T leftPlusRight  = _left - T (2) * p.x + _right;
 
472
    T leftMinusRight = _left-_right;
 
473
    T bottomPlusTop  = _bottom - T (2) * p.y + _top;
 
474
    T bottomMinusTop = _bottom-_top;
 
475
 
 
476
    if ((abs(leftMinusRight) < T (1) &&
 
477
         abs(leftPlusRight) > limits<T>::max() * abs(leftMinusRight)) ||
 
478
        (abs(bottomMinusTop) < T (1) &&
 
479
         abs(bottomPlusTop) > limits<T>::max() * abs(bottomMinusTop)))
 
480
    {
 
481
        throw Iex::DivzeroExc
 
482
            ("Bad viewing frustum: "
 
483
             "local-to-screen transformation cannot be computed");
 
484
    }
 
485
 
 
486
    return Vec2<T>( leftPlusRight / leftMinusRight,
 
487
                    bottomPlusTop / bottomMinusTop );
 
488
}
 
489
 
 
490
template<class T>
 
491
Line3<T> Frustum<T>::projectScreenToRay(const Vec2<T> &p) const
 
492
{
 
493
    Vec2<T> point = screenToLocal(p);
 
494
    if (orthographic())
 
495
        return Line3<T>( Vec3<T>(point.x,point.y, 0.0),
 
496
                         Vec3<T>(point.x,point.y,-_nearPlane));
 
497
    else
 
498
        return Line3<T>( Vec3<T>(0, 0, 0), Vec3<T>(point.x,point.y,-_nearPlane));
 
499
}
 
500
 
 
501
template<class T>
 
502
Vec2<T> Frustum<T>::projectPointToScreen(const Vec3<T> &point) const
 
503
{
 
504
    if (orthographic() || point.z == T (0))
 
505
        return localToScreen( Vec2<T>( point.x, point.y ) );
 
506
    else
 
507
        return localToScreen( Vec2<T>( point.x * _nearPlane / -point.z, 
 
508
                                       point.y * _nearPlane / -point.z ) );
 
509
}
 
510
 
 
511
template<class T>
 
512
T Frustum<T>::ZToDepth(long zval,long zmin,long zmax) const
 
513
{
 
514
    int zdiff = zmax - zmin;
 
515
 
 
516
    if (zdiff == 0)
 
517
    {
 
518
        throw Iex::DivzeroExc
 
519
            ("Bad call to Frustum::ZToDepth: zmax == zmin");
 
520
    }
 
521
 
 
522
    if ( zval > zmax+1 ) zval -= zdiff;
 
523
 
 
524
    T fzval = (T(zval) - T(zmin)) / T(zdiff);
 
525
    return normalizedZToDepth(fzval);
 
526
}
 
527
 
 
528
template<class T>
 
529
T Frustum<T>::normalizedZToDepth(T zval) const
 
530
{
 
531
    T Zp = zval * 2.0 - 1;
 
532
 
 
533
    if ( _orthographic )
 
534
    {
 
535
        return   -(Zp*(_farPlane-_nearPlane) + (_farPlane+_nearPlane))/2;
 
536
    }
 
537
    else 
 
538
    {
 
539
        T farTimesNear = 2 * _farPlane * _nearPlane;
 
540
        T farMinusNear = Zp * (_farPlane - _nearPlane) - _farPlane - _nearPlane;
 
541
 
 
542
        if (abs(farMinusNear) < 1 &&
 
543
            abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
 
544
        {
 
545
            throw Iex::DivzeroExc
 
546
                ("Frustum::normalizedZToDepth cannot be computed.  The "
 
547
                 "near and far clipping planes of the viewing frustum "
 
548
                 "may be too close to each other");
 
549
        }
 
550
 
 
551
        return farTimesNear / farMinusNear;
 
552
    }
 
553
}
 
554
 
 
555
template<class T>
 
556
long Frustum<T>::DepthToZ(T depth,long zmin,long zmax) const
 
557
{
 
558
    long zdiff     = zmax - zmin;
 
559
    T farMinusNear = _farPlane-_nearPlane;
 
560
 
 
561
    if ( _orthographic )
 
562
    {
 
563
        T farPlusNear = 2*depth + _farPlane + _nearPlane;
 
564
 
 
565
        if (abs(farMinusNear) < 1 &&
 
566
            abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
 
567
        {
 
568
            throw Iex::DivzeroExc
 
569
                ("Bad viewing frustum: near and far clipping planes "
 
570
                 "are too close to each other");
 
571
        }
 
572
 
 
573
        T Zp = -farPlusNear/farMinusNear;
 
574
        return long(0.5*(Zp+1)*zdiff) + zmin;
 
575
    }
 
576
    else 
 
577
    { 
 
578
        // Perspective
 
579
 
 
580
        T farTimesNear = 2*_farPlane*_nearPlane;
 
581
        if (abs(depth) < 1 &&
 
582
            abs(farTimesNear) > limits<T>::max() * abs(depth))
 
583
        {
 
584
            throw Iex::DivzeroExc
 
585
                ("Bad call to DepthToZ function: value of `depth' "
 
586
                 "is too small");
 
587
        }
 
588
 
 
589
        T farPlusNear = farTimesNear/depth + _farPlane + _nearPlane;
 
590
        if (abs(farMinusNear) < 1 &&
 
591
            abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
 
592
        {
 
593
            throw Iex::DivzeroExc
 
594
                ("Bad viewing frustum: near and far clipping planes "
 
595
                 "are too close to each other");
 
596
        }
 
597
 
 
598
        T Zp = farPlusNear/farMinusNear;
 
599
        return long(0.5*(Zp+1)*zdiff) + zmin;
 
600
    }
 
601
}
 
602
 
 
603
template<class T>
 
604
T Frustum<T>::screenRadius(const Vec3<T> &p, T radius) const
 
605
{
 
606
    // Derivation:
 
607
    // Consider X-Z plane.
 
608
    // X coord of projection of p = xp = p.x * (-_nearPlane / p.z)
 
609
    // Let q be p + (radius, 0, 0).
 
610
    // X coord of projection of q = xq = (p.x - radius)  * (-_nearPlane / p.z)
 
611
    // X coord of projection of segment from p to q = r = xp - xq
 
612
    //         = radius * (-_nearPlane / p.z)
 
613
    // A similar analysis holds in the Y-Z plane.
 
614
    // So r is the quantity we want to return.
 
615
 
 
616
    if (abs(p.z) > 1 || abs(-_nearPlane) < limits<T>::max() * abs(p.z))
 
617
    {
 
618
        return radius * (-_nearPlane / p.z);
 
619
    }
 
620
    else
 
621
    {
 
622
        throw Iex::DivzeroExc
 
623
            ("Bad call to Frustum::screenRadius: the magnitude of `p' "
 
624
             "is too small");
 
625
    }
 
626
 
 
627
    return radius * (-_nearPlane / p.z);
 
628
}
 
629
 
 
630
template<class T>
 
631
T Frustum<T>::worldRadius(const Vec3<T> &p, T radius) const
 
632
{
 
633
    if (abs(-_nearPlane) > 1 || abs(p.z) < limits<T>::max() * abs(-_nearPlane))
 
634
    {
 
635
        return radius * (p.z / -_nearPlane);
 
636
    }
 
637
    else
 
638
    {
 
639
        throw Iex::DivzeroExc
 
640
            ("Bad viewing frustum: the near clipping plane is too "
 
641
             "close to zero");
 
642
    }
 
643
}
 
644
 
 
645
template<class T>
 
646
void Frustum<T>::planes(Plane3<T> p[6])
 
647
{
 
648
    //
 
649
    //  Plane order: Top, Right, Bottom, Left, Near, Far.
 
650
    //  Normals point outwards.
 
651
    //
 
652
 
 
653
    if (! _orthographic)
 
654
    {
 
655
        Vec3<T> a( _left,  _bottom, -_nearPlane);
 
656
        Vec3<T> b( _left,  _top,    -_nearPlane);
 
657
        Vec3<T> c( _right, _top,    -_nearPlane);
 
658
        Vec3<T> d( _right, _bottom, -_nearPlane);
 
659
        Vec3<T> o(0,0,0);
 
660
 
 
661
        p[0].set( o, c, b );
 
662
        p[1].set( o, d, c );
 
663
        p[2].set( o, a, d );
 
664
        p[3].set( o, b, a );
 
665
    }
 
666
    else
 
667
    {
 
668
        p[0].set( Vec3<T>( 0, 1, 0), _top );
 
669
        p[1].set( Vec3<T>( 1, 0, 0), _right );
 
670
        p[2].set( Vec3<T>( 0,-1, 0),-_bottom );
 
671
        p[3].set( Vec3<T>(-1, 0, 0),-_left );
 
672
    }
 
673
    p[4].set( Vec3<T>(0, 0, 1), -_nearPlane );
 
674
    p[5].set( Vec3<T>(0, 0,-1), _farPlane );
 
675
}
 
676
 
 
677
 
 
678
template<class T>
 
679
void Frustum<T>::planes(Plane3<T> p[6], const Matrix44<T> &M)
 
680
{
 
681
    //
 
682
    //  Plane order: Top, Right, Bottom, Left, Near, Far.
 
683
    //  Normals point outwards.
 
684
    //
 
685
 
 
686
    Vec3<T> a   = Vec3<T>( _left,  _bottom, -_nearPlane) * M;
 
687
    Vec3<T> b   = Vec3<T>( _left,  _top,    -_nearPlane) * M;
 
688
    Vec3<T> c   = Vec3<T>( _right, _top,    -_nearPlane) * M;
 
689
    Vec3<T> d   = Vec3<T>( _right, _bottom, -_nearPlane) * M;
 
690
    if (! _orthographic)
 
691
    {
 
692
        double s    = _farPlane / double(_nearPlane);
 
693
        T farLeft   = (T) (s * _left);
 
694
        T farRight  = (T) (s * _right);
 
695
        T farTop    = (T) (s * _top);
 
696
        T farBottom = (T) (s * _bottom);
 
697
        Vec3<T> e   = Vec3<T>( farLeft,  farBottom, -_farPlane) * M;
 
698
        Vec3<T> f   = Vec3<T>( farLeft,  farTop,    -_farPlane) * M;
 
699
        Vec3<T> g   = Vec3<T>( farRight, farTop,    -_farPlane) * M;
 
700
        Vec3<T> o   = Vec3<T>(0,0,0) * M;
 
701
        p[0].set( o, c, b );
 
702
        p[1].set( o, d, c );
 
703
        p[2].set( o, a, d );
 
704
        p[3].set( o, b, a );
 
705
        p[4].set( a, d, c );
 
706
        p[5].set( e, f, g );
 
707
     }
 
708
    else
 
709
    {
 
710
        Vec3<T> e   = Vec3<T>( _left,  _bottom, -_farPlane) * M;
 
711
        Vec3<T> f   = Vec3<T>( _left,  _top,    -_farPlane) * M;
 
712
        Vec3<T> g   = Vec3<T>( _right, _top,    -_farPlane) * M;
 
713
        Vec3<T> h   = Vec3<T>( _right, _bottom, -_farPlane) * M;
 
714
        p[0].set( c, g, f );
 
715
        p[1].set( d, h, g );
 
716
        p[2].set( a, e, h );
 
717
        p[3].set( b, f, e );
 
718
        p[4].set( a, d, c );
 
719
        p[5].set( e, f, g );
 
720
    }
 
721
}
 
722
 
 
723
typedef Frustum<float>  Frustumf;
 
724
typedef Frustum<double> Frustumd;
 
725
 
 
726
 
 
727
} // namespace Imath
 
728
 
 
729
 
 
730
#if defined _WIN32 || defined _WIN64
 
731
    #ifdef _redef_near
 
732
        #define near
 
733
    #endif
 
734
    #ifdef _redef_far
 
735
        #define far
 
736
    #endif
 
737
#endif
 
738
 
 
739
#endif