~ubuntu-branches/ubuntu/saucy/openexr/saucy

« back to all changes in this revision

Viewing changes to Imath/ImathFrustum.h

  • Committer: Bazaar Package Importer
  • Author(s): Adeodato Simó
  • Date: 2008-03-24 23:00:21 UTC
  • mfrom: (3.1.2 lenny)
  • Revision ID: james.westby@ubuntu.com-20080324230021-gnofz9mnvcj1xlv3
Tags: 1.6.1-3
Disable (hopefully temporarily) the test suite on arm and ia64.

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
 
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
 
 
63
 
 
64
 
template<class T>
65
 
class Frustum
66
 
{
67
 
  public:
68
 
    Frustum();
69
 
    Frustum(const Frustum &);
70
 
    Frustum(T near, T far, T left, T right, T top, T bottom, bool ortho=false);
71
 
    Frustum(T near, T far, T fovx, T fovy, T aspect);
72
 
    virtual ~Frustum();
73
 
 
74
 
    //--------------------
75
 
    // Assignment operator
76
 
    //--------------------
77
 
 
78
 
    const Frustum &operator     = (const Frustum &);
79
 
 
80
 
    //--------------------------------------------------------
81
 
    //  Set functions change the entire state of the Frustum
82
 
    //--------------------------------------------------------
83
 
 
84
 
    void                set(T near, T far, 
85
 
                            T left, T right, 
86
 
                            T top, T bottom, 
87
 
                            bool ortho=false);
88
 
 
89
 
    void                set(T near, T far, T fovx, T fovy, T aspect);
90
 
 
91
 
    //------------------------------------------------------
92
 
    //  These functions modify an already valid frustum state
93
 
    //------------------------------------------------------
94
 
 
95
 
    void                modifyNearAndFar(T near, T far);
96
 
    void                setOrthographic(bool);
97
 
 
98
 
    //--------------
99
 
    //  Access
100
 
    //--------------
101
 
 
102
 
    bool                orthographic() const    { return _orthographic; }
103
 
    T                   near() const            { return _near;         }
104
 
    T                   far() const             { return _far;          }
105
 
    T                   left() const            { return _left;         }
106
 
    T                   right() const           { return _right;        }
107
 
    T                   bottom() const          { return _bottom;       }
108
 
    T                   top() const             { return _top;          }
109
 
 
110
 
    //-----------------------------------------------------------------------
111
 
    //  Sets the planes in p to be the six bounding planes of the frustum, in
112
 
    //  the following order: top, right, bottom, left, near, far.
113
 
    //  Note that the planes have normals that point out of the frustum.
114
 
    //  The version of this routine that takes a matrix applies that matrix
115
 
    //  to transform the frustum before setting the planes.
116
 
    //-----------------------------------------------------------------------
117
 
 
118
 
    void                planes(Plane3<T> p[6]);
119
 
    void                planes(Plane3<T> p[6], const Matrix44<T> &M);
120
 
 
121
 
    //----------------------
122
 
    //  Derived Quantities
123
 
    //----------------------
124
 
 
125
 
    T                   fovx() const;
126
 
    T                   fovy() const;
127
 
    T                   aspect() const;
128
 
    Matrix44<T>         projectionMatrix() const;
129
 
 
130
 
    //-----------------------------------------------------------------------
131
 
    //  Takes a rectangle in the screen space (i.e., -1 <= left <= right <= 1 
132
 
    //  and -1 <= bottom <= top <= 1) of this Frustum, and returns a new
133
 
    //  Frustum whose near clipping-plane window is that rectangle in local
134
 
    //  space.  
135
 
    //-----------------------------------------------------------------------
136
 
 
137
 
    Frustum<T>          window(T left, T right, T top, T bottom) const;
138
 
 
139
 
    //----------------------------------------------------------
140
 
    // Projection is in screen space / Conversion from Z-Buffer
141
 
    //----------------------------------------------------------
142
 
 
143
 
    Line3<T>            projectScreenToRay( const Vec2<T> & ) const;
144
 
    Vec2<T>             projectPointToScreen( const Vec3<T> & ) const;
145
 
 
146
 
    T                   ZToDepth(long zval, long min, long max) const;
147
 
    T                   normalizedZToDepth(T zval) const;
148
 
    long                DepthToZ(T depth, long zmin, long zmax) const;
149
 
 
150
 
    T                   worldRadius(const Vec3<T> &p, T radius) const;
151
 
    T                   screenRadius(const Vec3<T> &p, T radius) const;
152
 
 
153
 
 
154
 
  protected:
155
 
 
156
 
    Vec2<T>             screenToLocal( const Vec2<T> & ) const;
157
 
    Vec2<T>             localToScreen( const Vec2<T> & ) const;
158
 
 
159
 
  protected:
160
 
    T                   _near;
161
 
    T                   _far;
162
 
    T                   _left;
163
 
    T                   _right;
164
 
    T                   _top;
165
 
    T                   _bottom;
166
 
    bool                _orthographic;
167
 
};
168
 
 
169
 
 
170
 
template<class T>
171
 
inline Frustum<T>::Frustum()
172
 
{
173
 
    set(T (0.1),
174
 
        T (1000.0),
175
 
        T (-1.0),
176
 
        T (1.0),
177
 
        T (1.0),
178
 
        T (-1.0),
179
 
        false);
180
 
}
181
 
 
182
 
template<class T>
183
 
inline Frustum<T>::Frustum(const Frustum &f)
184
 
{
185
 
    *this = f;
186
 
}
187
 
 
188
 
template<class T>
189
 
inline Frustum<T>::Frustum(T n, T f, T l, T r, T t, T b, bool o)
190
 
{
191
 
    set(n,f,l,r,t,b,o);
192
 
}
193
 
 
194
 
template<class T>
195
 
inline Frustum<T>::Frustum(T near, T far, T fovx, T fovy, T aspect)
196
 
{
197
 
    set(near,far,fovx,fovy,aspect);
198
 
}
199
 
 
200
 
template<class T>
201
 
Frustum<T>::~Frustum()
202
 
{
203
 
}
204
 
 
205
 
template<class T>
206
 
const Frustum<T> &
207
 
Frustum<T>::operator = (const Frustum &f)
208
 
{
209
 
    _near         = f._near;
210
 
    _far          = f._far;
211
 
    _left         = f._left;
212
 
    _right        = f._right;
213
 
    _top          = f._top;
214
 
    _bottom       = f._bottom;
215
 
    _orthographic = f._orthographic;
216
 
 
217
 
    return *this;
218
 
}
219
 
 
220
 
template<class T>
221
 
void Frustum<T>::set(T n, T f, T l, T r, T t, T b, bool o)
222
 
{
223
 
    _near           = n;
224
 
    _far            = f;
225
 
    _left           = l;
226
 
    _right          = r;
227
 
    _bottom         = b;
228
 
    _top            = t;
229
 
    _orthographic   = o;
230
 
}
231
 
 
232
 
template<class T>
233
 
void Frustum<T>::modifyNearAndFar(T n, T f)
234
 
{
235
 
    if ( _orthographic )
236
 
    {
237
 
        _near = n;
238
 
    }
239
 
    else
240
 
    {
241
 
        Line3<T>  lowerLeft( Vec3<T>(0,0,0), Vec3<T>(_left,_bottom,-_near) );
242
 
        Line3<T> upperRight( Vec3<T>(0,0,0), Vec3<T>(_right,_top,-_near) );
243
 
        Plane3<T> nearPlane( Vec3<T>(0,0,-1), n );
244
 
 
245
 
        Vec3<T> ll,ur;
246
 
        nearPlane.intersect(lowerLeft,ll);
247
 
        nearPlane.intersect(upperRight,ur);
248
 
 
249
 
        _left   = ll.x;
250
 
        _right  = ur.x;
251
 
        _top    = ur.y;
252
 
        _bottom = ll.y;
253
 
        _near   = n;
254
 
        _far    = f;
255
 
    }
256
 
 
257
 
    _far = f;
258
 
}
259
 
 
260
 
template<class T>
261
 
void Frustum<T>::setOrthographic(bool ortho)
262
 
{
263
 
    _orthographic   = ortho;
264
 
}
265
 
 
266
 
template<class T>
267
 
void Frustum<T>::set(T near, T far, T fovx, T fovy, T aspect)
268
 
{
269
 
    if (fovx != 0 && fovy != 0)
270
 
        throw Iex::ArgExc ("fovx and fovy cannot both be non-zero.");
271
 
 
272
 
    if (fovx != 0)
273
 
    {
274
 
        _right      = near * Math<T>::tan(fovx/2.0);
275
 
        _left       = -_right;
276
 
        _top        = ((_right - _left)/aspect)/2.0;
277
 
        _bottom     = -_top;
278
 
    }
279
 
    else
280
 
    {
281
 
        _top        = near * Math<T>::tan(fovy/2.0);
282
 
        _bottom     = -_top;
283
 
        _right      = (_top - _bottom) * aspect / 2.0;
284
 
        _left       = -_right;
285
 
    }
286
 
    _near           = near;
287
 
    _far            = far;
288
 
    _orthographic   = false;
289
 
}
290
 
 
291
 
template<class T>
292
 
T Frustum<T>::fovx() const
293
 
{
294
 
    return Math<T>::atan2(_right,_near) - Math<T>::atan2(_left,_near);
295
 
}
296
 
 
297
 
template<class T>
298
 
T Frustum<T>::fovy() const
299
 
{
300
 
    return Math<T>::atan2(_top,_near) - Math<T>::atan2(_bottom,_near);
301
 
}
302
 
 
303
 
template<class T>
304
 
T Frustum<T>::aspect() const
305
 
{
306
 
    T rightMinusLeft = _right-_left;
307
 
    T topMinusBottom = _top-_bottom;
308
 
 
309
 
    if (abs(topMinusBottom) < 1 &&
310
 
        abs(rightMinusLeft) > limits<T>::max() * abs(topMinusBottom))
311
 
    {
312
 
        throw Iex::DivzeroExc ("Bad viewing frustum: "
313
 
                               "aspect ratio cannot be computed.");
314
 
    }
315
 
 
316
 
    return rightMinusLeft / topMinusBottom;
317
 
}
318
 
 
319
 
template<class T>
320
 
Matrix44<T> Frustum<T>::projectionMatrix() const
321
 
{
322
 
    T rightPlusLeft  = _right+_left;
323
 
    T rightMinusLeft = _right-_left;
324
 
 
325
 
    T topPlusBottom  = _top+_bottom;
326
 
    T topMinusBottom = _top-_bottom;
327
 
 
328
 
    T farPlusNear    = _far+_near;
329
 
    T farMinusNear   = _far-_near;
330
 
 
331
 
    if ((abs(rightMinusLeft) < 1 &&
332
 
         abs(rightPlusLeft) > limits<T>::max() * abs(rightMinusLeft)) ||
333
 
        (abs(topMinusBottom) < 1 &&
334
 
         abs(topPlusBottom) > limits<T>::max() * abs(topMinusBottom)) ||
335
 
        (abs(farMinusNear) < 1 &&
336
 
         abs(farPlusNear) > limits<T>::max() * abs(farMinusNear)))
337
 
    {
338
 
        throw Iex::DivzeroExc ("Bad viewing frustum: "
339
 
                               "projection matrix cannot be computed.");
340
 
    }
341
 
 
342
 
    if ( _orthographic )
343
 
    {
344
 
        T tx = -rightPlusLeft / rightMinusLeft;
345
 
        T ty = -topPlusBottom / topMinusBottom;
346
 
        T tz = -farPlusNear   / farMinusNear;
347
 
 
348
 
        if ((abs(rightMinusLeft) < 1 &&
349
 
             2 > limits<T>::max() * abs(rightMinusLeft)) ||
350
 
            (abs(topMinusBottom) < 1 &&
351
 
             2 > limits<T>::max() * abs(topMinusBottom)) ||
352
 
            (abs(farMinusNear) < 1 &&
353
 
             2 > limits<T>::max() * abs(farMinusNear)))
354
 
        {
355
 
            throw Iex::DivzeroExc ("Bad viewing frustum: "
356
 
                                   "projection matrix cannot be computed.");
357
 
        }
358
 
 
359
 
        T A  =  2 / rightMinusLeft;
360
 
        T B  =  2 / topMinusBottom;
361
 
        T C  = -2 / farMinusNear;
362
 
 
363
 
        return Matrix44<T>( A,  0,  0,  0,
364
 
                            0,  B,  0,  0,
365
 
                            0,  0,  C,  0,
366
 
                            tx, ty, tz, 1.f );
367
 
    }
368
 
    else
369
 
    {
370
 
        T A =  rightPlusLeft / rightMinusLeft;
371
 
        T B =  topPlusBottom / topMinusBottom;
372
 
        T C = -farPlusNear   / farMinusNear;
373
 
 
374
 
        T farTimesNear = -2 * _far * _near;
375
 
        if (abs(farMinusNear) < 1 &&
376
 
            abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
377
 
        {
378
 
            throw Iex::DivzeroExc ("Bad viewing frustum: "
379
 
                                   "projection matrix cannot be computed.");
380
 
        }
381
 
 
382
 
        T D = farTimesNear / farMinusNear;
383
 
 
384
 
        T twoTimesNear = 2 * _near;
385
 
 
386
 
        if ((abs(rightMinusLeft) < 1 &&
387
 
             abs(twoTimesNear) > limits<T>::max() * abs(rightMinusLeft)) ||
388
 
            (abs(topMinusBottom) < 1 &&
389
 
             abs(twoTimesNear) > limits<T>::max() * abs(topMinusBottom)))
390
 
        {
391
 
            throw Iex::DivzeroExc ("Bad viewing frustum: "
392
 
                                   "projection matrix cannot be computed.");
393
 
        }
394
 
 
395
 
        T E = twoTimesNear / rightMinusLeft;
396
 
        T F = twoTimesNear / topMinusBottom;
397
 
 
398
 
        return Matrix44<T>( E,  0,  0,  0,
399
 
                            0,  F,  0,  0,
400
 
                            A,  B,  C, -1,
401
 
                            0,  0,  D,  0 );
402
 
    }
403
 
}
404
 
 
405
 
template<class T>
406
 
Frustum<T> Frustum<T>::window(T l, T r, T t, T b) const
407
 
{
408
 
    // move it to 0->1 space
409
 
 
410
 
    Vec2<T> bl = screenToLocal( Vec2<T>(l,b) );
411
 
    Vec2<T> tr = screenToLocal( Vec2<T>(r,t) );
412
 
 
413
 
    return Frustum<T>(_near, _far, bl.x, tr.x, tr.y, bl.y, _orthographic);
414
 
}
415
 
 
416
 
 
417
 
template<class T>
418
 
Vec2<T> Frustum<T>::screenToLocal(const Vec2<T> &s) const
419
 
{
420
 
    return Vec2<T>( _left + (_right-_left) * (1.f+s.x) / 2.f,
421
 
                    _bottom + (_top-_bottom) * (1.f+s.y) / 2.f );
422
 
}
423
 
 
424
 
template<class T>
425
 
Vec2<T> Frustum<T>::localToScreen(const Vec2<T> &p) const
426
 
{
427
 
    T leftPlusRight  = _left - 2 * p.x + _right;
428
 
    T leftMinusRight = _left-_right;
429
 
    T bottomPlusTop  = _bottom - 2 * p.y + _top;
430
 
    T bottomMinusTop = _bottom-_top;
431
 
 
432
 
    if ((abs(leftMinusRight) < 1 &&
433
 
         abs(leftPlusRight) > limits<T>::max() * abs(leftMinusRight)) ||
434
 
        (abs(bottomMinusTop) < 1 &&
435
 
         abs(bottomPlusTop) > limits<T>::max() * abs(bottomMinusTop)))
436
 
    {
437
 
        throw Iex::DivzeroExc
438
 
            ("Bad viewing frustum: "
439
 
             "local-to-screen transformation cannot be computed");
440
 
    }
441
 
 
442
 
    return Vec2<T>( leftPlusRight / leftMinusRight,
443
 
                    bottomPlusTop / bottomMinusTop );
444
 
}
445
 
 
446
 
template<class T>
447
 
Line3<T> Frustum<T>::projectScreenToRay(const Vec2<T> &p) const
448
 
{
449
 
    Vec2<T> point = screenToLocal(p);
450
 
    if (orthographic())
451
 
        return Line3<T>( Vec3<T>(point.x,point.y, 0.0),
452
 
                         Vec3<T>(point.x,point.y,-_near));
453
 
    else
454
 
        return Line3<T>( Vec3<T>(0, 0, 0), Vec3<T>(point.x,point.y,-_near));
455
 
}
456
 
 
457
 
template<class T>
458
 
Vec2<T> Frustum<T>::projectPointToScreen(const Vec3<T> &point) const
459
 
{
460
 
    if (orthographic() || point.z == 0)
461
 
        return localToScreen( Vec2<T>( point.x, point.y ) );
462
 
    else
463
 
        return localToScreen( Vec2<T>( point.x * _near / -point.z, 
464
 
                                       point.y * _near / -point.z ) );
465
 
}
466
 
 
467
 
template<class T>
468
 
T Frustum<T>::ZToDepth(long zval,long zmin,long zmax) const
469
 
{
470
 
    int zdiff = zmax - zmin;
471
 
 
472
 
    if (zdiff == 0)
473
 
    {
474
 
        throw Iex::DivzeroExc
475
 
            ("Bad call to Frustum::ZToDepth: zmax == zmin");
476
 
    }
477
 
 
478
 
    if ( zval > zmax+1 ) zval -= zdiff;
479
 
 
480
 
    T fzval = (T(zval) - T(zmin)) / T(zdiff);
481
 
    return normalizedZToDepth(fzval);
482
 
}
483
 
 
484
 
template<class T>
485
 
T Frustum<T>::normalizedZToDepth(T zval) const
486
 
{
487
 
    T Zp = zval * 2.0 - 1;
488
 
 
489
 
    if ( _orthographic )
490
 
    {
491
 
        return   -(Zp*(_far-_near) + (_far+_near))/2;
492
 
    }
493
 
    else 
494
 
    {
495
 
        T farTimesNear = 2 * _far * _near;
496
 
        T farMinusNear = Zp * (_far - _near) - _far - _near;
497
 
 
498
 
        if (abs(farMinusNear) < 1 &&
499
 
            abs(farTimesNear) > limits<T>::max() * abs(farMinusNear))
500
 
        {
501
 
            throw Iex::DivzeroExc
502
 
                ("Frustum::normalizedZToDepth cannot be computed.  The "
503
 
                 "near and far clipping planes of the viewing frustum "
504
 
                 "may be too close to each other");
505
 
        }
506
 
 
507
 
        return farTimesNear / farMinusNear;
508
 
    }
509
 
}
510
 
 
511
 
template<class T>
512
 
long Frustum<T>::DepthToZ(T depth,long zmin,long zmax) const
513
 
{
514
 
    long zdiff     = zmax - zmin;
515
 
    T farMinusNear = _far-_near;
516
 
 
517
 
    if ( _orthographic )
518
 
    {
519
 
        T farPlusNear = 2*depth + _far + _near;
520
 
 
521
 
        if (abs(farMinusNear) < 1 &&
522
 
            abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
523
 
        {
524
 
            throw Iex::DivzeroExc
525
 
                ("Bad viewing frustum: near and far clipping planes "
526
 
                 "are too close to each other");
527
 
        }
528
 
 
529
 
        T Zp = -farPlusNear/farMinusNear;
530
 
        return long(0.5*(Zp+1)*zdiff) + zmin;
531
 
    }
532
 
    else 
533
 
    { 
534
 
        // Perspective
535
 
 
536
 
        T farTimesNear = 2*_far*_near;
537
 
        if (abs(depth) < 1 &&
538
 
            abs(farTimesNear) > limits<T>::max() * abs(depth))
539
 
        {
540
 
            throw Iex::DivzeroExc
541
 
                ("Bad call to DepthToZ function: value of `depth' "
542
 
                 "is too small");
543
 
        }
544
 
 
545
 
        T farPlusNear = farTimesNear/depth + _far + _near;
546
 
        if (abs(farMinusNear) < 1 &&
547
 
            abs(farPlusNear) > limits<T>::max() * abs(farMinusNear))
548
 
        {
549
 
            throw Iex::DivzeroExc
550
 
                ("Bad viewing frustum: near and far clipping planes "
551
 
                 "are too close to each other");
552
 
        }
553
 
 
554
 
        T Zp = farPlusNear/farMinusNear;
555
 
        return long(0.5*(Zp+1)*zdiff) + zmin;
556
 
    }
557
 
}
558
 
 
559
 
template<class T>
560
 
T Frustum<T>::screenRadius(const Vec3<T> &p, T radius) const
561
 
{
562
 
    // Derivation:
563
 
    // Consider X-Z plane.
564
 
    // X coord of projection of p = xp = p.x * (-_near / p.z)
565
 
    // Let q be p + (radius, 0, 0).
566
 
    // X coord of projection of q = xq = (p.x - radius)  * (-_near / p.z)
567
 
    // X coord of projection of segment from p to q = r = xp - xq
568
 
    //         = radius * (-_near / p.z)
569
 
    // A similar analysis holds in the Y-Z plane.
570
 
    // So r is the quantity we want to return.
571
 
 
572
 
    if (abs(p.z) > 1 || abs(-_near) < limits<T>::max() * abs(p.z))
573
 
    {
574
 
        return radius * (-_near / p.z);
575
 
    }
576
 
    else
577
 
    {
578
 
        throw Iex::DivzeroExc
579
 
            ("Bad call to Frustum::screenRadius: the magnitude of `p' "
580
 
             "is too small");
581
 
    }
582
 
 
583
 
    return radius * (-_near / p.z);
584
 
}
585
 
 
586
 
template<class T>
587
 
T Frustum<T>::worldRadius(const Vec3<T> &p, T radius) const
588
 
{
589
 
    if (abs(-_near) > 1 || abs(p.z) < limits<T>::max() * abs(-_near))
590
 
    {
591
 
        return radius * (p.z / -_near);
592
 
    }
593
 
    else
594
 
    {
595
 
        throw Iex::DivzeroExc
596
 
            ("Bad viewing frustum: the near clipping plane is too "
597
 
             "close to zero");
598
 
    }
599
 
}
600
 
 
601
 
template<class T>
602
 
void Frustum<T>::planes(Plane3<T> p[6])
603
 
{
604
 
    //
605
 
    //  Plane order: Top, Right, Bottom, Left, Near, Far.
606
 
    //  Normals point outwards.
607
 
    //
608
 
 
609
 
    Vec3<T> a( _left,  _bottom, -_near);
610
 
    Vec3<T> b( _left,  _top,    -_near);
611
 
    Vec3<T> c( _right, _top,    -_near);
612
 
    Vec3<T> d( _right, _bottom, -_near);
613
 
    Vec3<T> o(0,0,0);
614
 
 
615
 
    p[0].set( o, c, b );
616
 
    p[1].set( o, d, c );
617
 
    p[2].set( o, a, d );
618
 
    p[3].set( o, b, a );
619
 
    p[4].set( Vec3<T>(0, 0, 1), -_near );
620
 
    p[5].set( Vec3<T>(0, 0,-1), _far );
621
 
}
622
 
 
623
 
 
624
 
template<class T>
625
 
void Frustum<T>::planes(Plane3<T> p[6], const Matrix44<T> &M)
626
 
{
627
 
    //
628
 
    //  Plane order: Top, Right, Bottom, Left, Near, Far.
629
 
    //  Normals point outwards.
630
 
    //
631
 
 
632
 
    Vec3<T> a   = Vec3<T>( _left,  _bottom, -_near) * M;
633
 
    Vec3<T> b   = Vec3<T>( _left,  _top,    -_near) * M;
634
 
    Vec3<T> c   = Vec3<T>( _right, _top,    -_near) * M;
635
 
    Vec3<T> d   = Vec3<T>( _right, _bottom, -_near) * M;
636
 
    double s    = _far / double(_near);
637
 
    T farLeft   = (T) (s * _left);
638
 
    T farRight  = (T) (s * _right);
639
 
    T farTop    = (T) (s * _top);
640
 
    T farBottom = (T) (s * _bottom);
641
 
    Vec3<T> e   = Vec3<T>( farLeft,  farBottom, -_far) * M;
642
 
    Vec3<T> f   = Vec3<T>( farLeft,  farTop,    -_far) * M;
643
 
    Vec3<T> g   = Vec3<T>( farRight, farTop,    -_far) * M;
644
 
    Vec3<T> o   = Vec3<T>(0,0,0) * M;
645
 
 
646
 
    p[0].set( o, c, b );
647
 
    p[1].set( o, d, c );
648
 
    p[2].set( o, a, d );
649
 
    p[3].set( o, b, a );
650
 
    p[4].set( a, d, c );
651
 
    p[5].set( e, f, g );
652
 
}
653
 
 
654
 
typedef Frustum<float>  Frustumf;
655
 
typedef Frustum<double> Frustumd;
656
 
 
657
 
 
658
 
} // namespace Imath
659
 
 
660
 
#endif