os/graphics/m3g/m3gcore11/src/m3g_camera.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/*
sl@0
     2
* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
* All rights reserved.
sl@0
     4
* This component and the accompanying materials are made available
sl@0
     5
* under the terms of the License "Eclipse Public License v1.0"
sl@0
     6
* which accompanies this distribution, and is available
sl@0
     7
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
*
sl@0
     9
* Initial Contributors:
sl@0
    10
* Nokia Corporation - initial contribution.
sl@0
    11
*
sl@0
    12
* Contributors:
sl@0
    13
*
sl@0
    14
* Description: Camera implementation
sl@0
    15
*
sl@0
    16
*/
sl@0
    17
sl@0
    18
sl@0
    19
/*!
sl@0
    20
 * \internal
sl@0
    21
 * \file
sl@0
    22
 * \brief Camera implementation
sl@0
    23
 */
sl@0
    24
sl@0
    25
#ifndef M3G_CORE_INCLUDE
sl@0
    26
#   error included by m3g_core.c; do not compile separately.
sl@0
    27
#endif
sl@0
    28
sl@0
    29
#include "m3g_camera.h"
sl@0
    30
sl@0
    31
/* Internal frustum plane enumeration (and testing order!) */
sl@0
    32
sl@0
    33
#define NEAR_PLANE      0
sl@0
    34
#define FAR_PLANE       1
sl@0
    35
#define LEFT_PLANE      2
sl@0
    36
#define RIGHT_PLANE     3
sl@0
    37
#define BOTTOM_PLANE    4
sl@0
    38
#define TOP_PLANE       5
sl@0
    39
sl@0
    40
/*----------------------------------------------------------------------
sl@0
    41
 * Private functions
sl@0
    42
 *--------------------------------------------------------------------*/
sl@0
    43
sl@0
    44
/*!
sl@0
    45
 * \internal
sl@0
    46
 * \brief Makes sure that the internal projection matrix is up-to-date
sl@0
    47
 *        and checks if the camera has a zero view volume.
sl@0
    48
 */
sl@0
    49
static void m3gValidateProjectionMatrix(Camera *camera)
sl@0
    50
{
sl@0
    51
    M3Gint projType = camera->projType;
sl@0
    52
sl@0
    53
    /* The generic matrix is always valid, but for perspective and
sl@0
    54
     * parallel we must regenerate the matrix */
sl@0
    55
    
sl@0
    56
    if (projType != M3G_GENERIC) {
sl@0
    57
        M3Gfloat m[16];
sl@0
    58
sl@0
    59
        M3Gfloat clipNear = camera->clipNear;
sl@0
    60
        M3Gfloat clipFar = camera->clipFar;
sl@0
    61
sl@0
    62
        if (projType == M3G_PERSPECTIVE) {
sl@0
    63
            
sl@0
    64
            M3Gfloat height = m3gTan(m3gMul(M3G_DEG2RAD * 0.5f,
sl@0
    65
                                            camera->heightFov));
sl@0
    66
            
sl@0
    67
            m[0] = m3gRcp(m3gMul(camera->aspect, height));
sl@0
    68
            m[1] = m[2] = m[3] = 0.f;
sl@0
    69
            
sl@0
    70
            m[4] = 0.f;
sl@0
    71
            m[5] = m3gRcp(height);
sl@0
    72
            m[6] = m[7] = 0.f;
sl@0
    73
            
sl@0
    74
            m[8] = m[9] = 0.f;
sl@0
    75
            m[10] = m3gDiv(-m3gAdd(clipFar, clipNear),
sl@0
    76
                           m3gSub(clipFar, clipNear));
sl@0
    77
            m[11] = -1.f;
sl@0
    78
            
sl@0
    79
            m[12] = m[13] = 0.f;
sl@0
    80
            m[14] = m3gDiv(m3gMul(m3gMul(-2.f, clipFar), clipNear),
sl@0
    81
                           m3gSub(clipFar, clipNear));
sl@0
    82
            m[15] = 0.f;
sl@0
    83
        }
sl@0
    84
        else if (projType == M3G_PARALLEL) {
sl@0
    85
sl@0
    86
            M3Gfloat height = camera->heightFov;
sl@0
    87
            
sl@0
    88
            m[0] = m3gDiv(2.f, m3gMul(camera->aspect, height));
sl@0
    89
            m[1] = m[2] = m[3] = 0.f;
sl@0
    90
sl@0
    91
            m[4] = 0.f;
sl@0
    92
            m[5] = m3gDiv(2.f, height);
sl@0
    93
            m[6] = m[7] = 0;
sl@0
    94
            
sl@0
    95
            m[8] = m[9] = 0;
sl@0
    96
            m[10] = m3gDiv(-2.f, m3gSub(clipFar, clipNear));
sl@0
    97
            m[11] = 0.f;
sl@0
    98
            
sl@0
    99
            m[12] = m[13] = 0.f;
sl@0
   100
            m[14] = m3gDiv(-m3gAdd(clipFar, clipNear),
sl@0
   101
                           m3gSub(clipFar, clipNear));
sl@0
   102
            m[15] = 1.f;
sl@0
   103
        }
sl@0
   104
        else {
sl@0
   105
            M3G_ASSERT(M3G_FALSE); /* unknown projection type! */
sl@0
   106
        }
sl@0
   107
        m3gSetMatrixColumns(&camera->projMatrix, m); 
sl@0
   108
    }
sl@0
   109
sl@0
   110
    {
sl@0
   111
        M3GMatrix im;
sl@0
   112
        if (!m3gMatrixInverse(&im, &camera->projMatrix)) {
sl@0
   113
            camera->zeroViewVolume = M3G_TRUE;
sl@0
   114
        }
sl@0
   115
        else {
sl@0
   116
            camera->zeroViewVolume = M3G_FALSE;
sl@0
   117
        }
sl@0
   118
    }
sl@0
   119
sl@0
   120
    camera->frustumPlanesValid = M3G_FALSE;
sl@0
   121
}
sl@0
   122
sl@0
   123
/*!
sl@0
   124
 * \internal
sl@0
   125
 * \brief Validates the cached view frustum planes
sl@0
   126
 */
sl@0
   127
static void m3gValidateFrustumPlanes(Camera *camera) 
sl@0
   128
{
sl@0
   129
    if (!camera->frustumPlanesValid) {
sl@0
   130
        Vec4 *plane;
sl@0
   131
        Vec4 rows[4];
sl@0
   132
        
sl@0
   133
        m3gGetMatrixRows(&camera->projMatrix, (M3Gfloat*) rows);
sl@0
   134
sl@0
   135
        plane = &camera->frustumPlanes[LEFT_PLANE];
sl@0
   136
        *plane = rows[3];
sl@0
   137
        m3gAddVec4(plane, &rows[0]);
sl@0
   138
sl@0
   139
        plane = &camera->frustumPlanes[RIGHT_PLANE];
sl@0
   140
        *plane = rows[3];
sl@0
   141
        m3gSubVec4(plane, &rows[0]);
sl@0
   142
sl@0
   143
        plane = &camera->frustumPlanes[BOTTOM_PLANE];
sl@0
   144
        *plane = rows[3];
sl@0
   145
        m3gAddVec4(plane, &rows[1]);
sl@0
   146
sl@0
   147
        plane = &camera->frustumPlanes[TOP_PLANE];
sl@0
   148
        *plane = rows[3];
sl@0
   149
        m3gSubVec4(plane, &rows[1]);
sl@0
   150
sl@0
   151
        plane = &camera->frustumPlanes[NEAR_PLANE];
sl@0
   152
        *plane = rows[3];
sl@0
   153
        m3gAddVec4(plane, &rows[2]);
sl@0
   154
sl@0
   155
        plane = &camera->frustumPlanes[FAR_PLANE];
sl@0
   156
        *plane = rows[3];
sl@0
   157
        m3gSubVec4(plane, &rows[2]);
sl@0
   158
sl@0
   159
        camera->frustumPlanesValid = M3G_TRUE;
sl@0
   160
    }
sl@0
   161
}
sl@0
   162
sl@0
   163
#undef NEAR_PLANE
sl@0
   164
#undef FAR_PLANE
sl@0
   165
#undef LEFT_PLANE
sl@0
   166
#undef RIGHT_PLANE
sl@0
   167
#undef BOTTOM_PLANE
sl@0
   168
#undef TOP_PLANE
sl@0
   169
sl@0
   170
/*----------------------------------------------------------------------
sl@0
   171
 * Internal functions
sl@0
   172
 *--------------------------------------------------------------------*/
sl@0
   173
sl@0
   174
/*!
sl@0
   175
 * \internal
sl@0
   176
 * \brief Overloaded Object3D method.
sl@0
   177
 *
sl@0
   178
 * \param property      animation property
sl@0
   179
 * \retval M3G_TRUE     property supported
sl@0
   180
 * \retval M3G_FALSE    property not supported
sl@0
   181
 */
sl@0
   182
static M3Gbool m3gCameraIsCompatible(M3Gint property)
sl@0
   183
{
sl@0
   184
    switch (property) {
sl@0
   185
    case M3G_ANIM_FAR_DISTANCE:
sl@0
   186
    case M3G_ANIM_FIELD_OF_VIEW:
sl@0
   187
    case M3G_ANIM_NEAR_DISTANCE:
sl@0
   188
        return M3G_TRUE;
sl@0
   189
    default:
sl@0
   190
        return m3gNodeIsCompatible(property);
sl@0
   191
    }
sl@0
   192
}
sl@0
   193
sl@0
   194
/*!
sl@0
   195
 * \internal
sl@0
   196
 * \brief Overloaded Object3D method.
sl@0
   197
 *
sl@0
   198
 * \param obj          Camera object
sl@0
   199
 * \param property      animation property
sl@0
   200
 * \param valueSize     size of value array
sl@0
   201
 * \param value         value array
sl@0
   202
 */
sl@0
   203
static void m3gCameraUpdateProperty(Object *obj,
sl@0
   204
                                    M3Gint property,
sl@0
   205
                                    M3Gint valueSize,
sl@0
   206
                                    const M3Gfloat *value)
sl@0
   207
{
sl@0
   208
    Camera *camera = (Camera *) obj;
sl@0
   209
    M3G_VALIDATE_OBJECT(camera);
sl@0
   210
    M3G_ASSERT_PTR(value);
sl@0
   211
sl@0
   212
    switch (property) {
sl@0
   213
    case M3G_ANIM_FAR_DISTANCE:
sl@0
   214
        M3G_ASSERT(valueSize >= 1);
sl@0
   215
        camera->clipFar =   (camera->projType == M3G_PERSPECTIVE)
sl@0
   216
                            ? m3gClampFloatPositive(value[0])
sl@0
   217
                            : value[0];
sl@0
   218
        break;
sl@0
   219
    case M3G_ANIM_FIELD_OF_VIEW:
sl@0
   220
        M3G_ASSERT(valueSize >= 1);
sl@0
   221
        camera->heightFov = (camera->projType == M3G_PERSPECTIVE)
sl@0
   222
                            ? m3gClampFloat(value[0], 0.f, 180.f)
sl@0
   223
                            : m3gClampFloatPositive(value[0]);
sl@0
   224
        break;
sl@0
   225
    case M3G_ANIM_NEAR_DISTANCE:
sl@0
   226
        M3G_ASSERT(valueSize >= 1);
sl@0
   227
        camera->clipNear =  (camera->projType == M3G_PERSPECTIVE)
sl@0
   228
                            ? m3gClampFloatPositive(value[0])
sl@0
   229
                            : value[0];
sl@0
   230
        break;
sl@0
   231
    default:
sl@0
   232
        m3gNodeUpdateProperty(obj, property, valueSize, value);
sl@0
   233
        return; /* don't invalidate the matrix */
sl@0
   234
    }
sl@0
   235
sl@0
   236
    /* Validate the projection matrix if we changed any of the
sl@0
   237
     * camera parameters */
sl@0
   238
sl@0
   239
    m3gValidateProjectionMatrix(camera);
sl@0
   240
}
sl@0
   241
sl@0
   242
/*!
sl@0
   243
 * \internal
sl@0
   244
 * \brief Overloaded Node method.
sl@0
   245
 *
sl@0
   246
 * Start render setup scene traversal.
sl@0
   247
 *
sl@0
   248
 * \param node Camera object
sl@0
   249
 * \param toCamera transform to camera
sl@0
   250
 * \param alphaFactor total alpha factor
sl@0
   251
 * \param caller caller node
sl@0
   252
 * \param renderQueue RenderQueue
sl@0
   253
 *
sl@0
   254
 * \retval M3G_TRUE continue render setup
sl@0
   255
 * \retval M3G_FALSE abort render setup
sl@0
   256
 */
sl@0
   257
static M3Gbool m3gCameraSetupRender(Node *self,
sl@0
   258
                                    const Node *caller,
sl@0
   259
                                    SetupRenderState *s,
sl@0
   260
                                    RenderQueue *renderQueue)
sl@0
   261
{
sl@0
   262
    Node *parent;
sl@0
   263
    M3Gbool success = M3G_TRUE;
sl@0
   264
sl@0
   265
    /* Just do the parent node.  Note that we won't be needing the old
sl@0
   266
     * state back after going up the tree, so we can overwrite it. */
sl@0
   267
    
sl@0
   268
    parent = self->parent;
sl@0
   269
sl@0
   270
    if (caller != parent && parent != NULL) {
sl@0
   271
        Matrix t;
sl@0
   272
        
sl@0
   273
        M3G_BEGIN_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
sl@0
   274
        if (!m3gGetInverseNodeTransform(self, &t)) {
sl@0
   275
            return M3G_FALSE;
sl@0
   276
        }
sl@0
   277
        m3gMulMatrix(&s->toCamera, &t);
sl@0
   278
        M3G_END_PROFILE(M3G_INTERFACE(self), M3G_PROFILE_SETUP_TRANSFORMS);
sl@0
   279
sl@0
   280
        /* The parent node will update the alpha factor and culling
sl@0
   281
         * mask if necessary, so we need not touch those */
sl@0
   282
        
sl@0
   283
        success = M3G_VFUNC(Node, parent, setupRender)(parent,
sl@0
   284
                                                       self, s, renderQueue);
sl@0
   285
    }
sl@0
   286
sl@0
   287
    return success;
sl@0
   288
}
sl@0
   289
sl@0
   290
/*!
sl@0
   291
 * \internal
sl@0
   292
 * \brief Overloaded Object3D method.
sl@0
   293
 *
sl@0
   294
 * \param originalObj original Camera object
sl@0
   295
 * \param cloneObj pointer to cloned Camera object
sl@0
   296
 * \param pairs array for all object-duplicate pairs
sl@0
   297
 * \param numPairs number of pairs
sl@0
   298
 */
sl@0
   299
static M3Gbool m3gCameraDuplicate(const Object *originalObj,
sl@0
   300
                                  Object **cloneObj,
sl@0
   301
                                  Object **pairs,
sl@0
   302
                                  M3Gint *numPairs)
sl@0
   303
{
sl@0
   304
    Camera *original = (Camera *)originalObj;
sl@0
   305
    Camera *clone = (Camera *)m3gCreateCamera(originalObj->interface);
sl@0
   306
    *cloneObj = (Object *)clone;
sl@0
   307
    if (*cloneObj == NULL) {
sl@0
   308
        return M3G_FALSE;
sl@0
   309
    }
sl@0
   310
sl@0
   311
    if (m3gNodeDuplicate(originalObj, cloneObj, pairs, numPairs)) {
sl@0
   312
        clone->projType = original->projType;
sl@0
   313
        clone->projMatrix = original->projMatrix;
sl@0
   314
        clone->heightFov = original->heightFov;
sl@0
   315
        clone->aspect = original->aspect;
sl@0
   316
        clone->clipNear = original->clipNear;
sl@0
   317
        clone->clipFar = original->clipFar;
sl@0
   318
        clone->zeroViewVolume = original->zeroViewVolume;
sl@0
   319
        return M3G_TRUE;
sl@0
   320
    }
sl@0
   321
    else {
sl@0
   322
        return M3G_FALSE;
sl@0
   323
    }
sl@0
   324
}
sl@0
   325
sl@0
   326
/*!
sl@0
   327
 * \internal
sl@0
   328
 * \brief Initializes a Camera object. See specification
sl@0
   329
 * for default values.
sl@0
   330
 *
sl@0
   331
 * \param m3g           M3G interface
sl@0
   332
 * \param camera        Camera object
sl@0
   333
 */
sl@0
   334
static void m3gInitCamera(Interface *m3g, Camera *camera)
sl@0
   335
{
sl@0
   336
    M3GMatrix m;
sl@0
   337
sl@0
   338
    /* Camera is derived from node */
sl@0
   339
    m3gInitNode(m3g, &camera->node, M3G_CLASS_CAMERA);
sl@0
   340
sl@0
   341
    /* GENERIC, Identity */
sl@0
   342
    m3gIdentityMatrix(&m);
sl@0
   343
    m3gSetProjectionMatrix(camera, (const M3GMatrix *)&m);
sl@0
   344
}
sl@0
   345
sl@0
   346
/*!
sl@0
   347
 * \internal
sl@0
   348
 * \brief Sets camera matrix to OpenGL
sl@0
   349
 * projection matrix.
sl@0
   350
 *
sl@0
   351
 * \param camera Camera object
sl@0
   352
 */
sl@0
   353
static void m3gApplyProjection(const Camera *camera)
sl@0
   354
{
sl@0
   355
    M3Gfloat t[16];
sl@0
   356
sl@0
   357
    m3gGetMatrixColumns(&camera->projMatrix, t);
sl@0
   358
    
sl@0
   359
    glMatrixMode(GL_PROJECTION);
sl@0
   360
    glLoadMatrixf(t);
sl@0
   361
    glMatrixMode(GL_MODELVIEW);
sl@0
   362
}
sl@0
   363
sl@0
   364
/*!
sl@0
   365
 * \internal
sl@0
   366
 * \brief Returns a pointer to the camera projection matrix
sl@0
   367
 *
sl@0
   368
 * The matrix <em>must not</em> be accessed directly, as only this
sl@0
   369
 * function will ensure that the returned matrix has valid values in
sl@0
   370
 * it.
sl@0
   371
 * 
sl@0
   372
 * \param camera Camera object
sl@0
   373
 * \return a pointer to the projection matrix
sl@0
   374
 */
sl@0
   375
static const Matrix *m3gProjectionMatrix(const Camera *camera)
sl@0
   376
{
sl@0
   377
    M3G_VALIDATE_OBJECT(camera);
sl@0
   378
sl@0
   379
    return &camera->projMatrix;
sl@0
   380
}
sl@0
   381
sl@0
   382
/*!
sl@0
   383
 * \internal
sl@0
   384
 * \brief Retrieves a pointer to the six camera space view frustum planes
sl@0
   385
 */
sl@0
   386
static const Vec4 *m3gFrustumPlanes(const Camera *camera)
sl@0
   387
{
sl@0
   388
    M3G_VALIDATE_OBJECT(camera);
sl@0
   389
    m3gValidateFrustumPlanes((Camera*) camera);
sl@0
   390
    return camera->frustumPlanes;
sl@0
   391
}
sl@0
   392
sl@0
   393
/*----------------------------------------------------------------------
sl@0
   394
 * Virtual function table
sl@0
   395
 *--------------------------------------------------------------------*/
sl@0
   396
sl@0
   397
static const NodeVFTable m3gvf_Camera = {
sl@0
   398
    {
sl@0
   399
        {
sl@0
   400
            m3gObjectApplyAnimation,
sl@0
   401
            m3gCameraIsCompatible,
sl@0
   402
            m3gCameraUpdateProperty,
sl@0
   403
            m3gObjectDoGetReferences,
sl@0
   404
            m3gObjectFindID,
sl@0
   405
            m3gCameraDuplicate,
sl@0
   406
            m3gDestroyNode /* no extra clean-up for Camera */
sl@0
   407
        }
sl@0
   408
    },
sl@0
   409
    m3gNodeAlign,
sl@0
   410
    NULL, /* pure virtual DoRender */
sl@0
   411
    m3gNodeGetBBox,
sl@0
   412
    m3gNodeRayIntersect,
sl@0
   413
    m3gCameraSetupRender,
sl@0
   414
    m3gNodeUpdateDuplicateReferences,
sl@0
   415
    m3gNodeValidate
sl@0
   416
};
sl@0
   417
sl@0
   418
sl@0
   419
/*----------------------------------------------------------------------
sl@0
   420
 * Public API functions
sl@0
   421
 *--------------------------------------------------------------------*/
sl@0
   422
sl@0
   423
/*!
sl@0
   424
 * \brief Creates a Camera object.
sl@0
   425
 *
sl@0
   426
 * \param interface     M3G interface
sl@0
   427
 * \retval Camera new Camera object
sl@0
   428
 * \retval NULL Camera creating failed
sl@0
   429
 */
sl@0
   430
M3G_API M3GCamera m3gCreateCamera(M3GInterface interface)
sl@0
   431
{
sl@0
   432
    Interface *m3g = (Interface *) interface;
sl@0
   433
    M3G_VALIDATE_INTERFACE(m3g);
sl@0
   434
sl@0
   435
    {
sl@0
   436
        Camera *camera =  m3gAllocZ(m3g, sizeof(Camera));
sl@0
   437
sl@0
   438
        if (camera != NULL) {
sl@0
   439
            m3gInitCamera(m3g, camera);
sl@0
   440
        }
sl@0
   441
sl@0
   442
        return (M3GCamera) camera;
sl@0
   443
    }
sl@0
   444
}
sl@0
   445
sl@0
   446
/*!
sl@0
   447
 * \brief Sets a parallel projection.
sl@0
   448
 *
sl@0
   449
 * \param handle        Camera object
sl@0
   450
 * \param height        height (=fovy)
sl@0
   451
 * \param aspectRatio   viewport aspect ratio
sl@0
   452
 * \param clipNear      near clipping plane
sl@0
   453
 * \param clipFar       far clipping plane
sl@0
   454
 */
sl@0
   455
M3G_API void m3gSetParallel(M3GCamera handle,
sl@0
   456
                            M3Gfloat height,
sl@0
   457
                            M3Gfloat aspectRatio,
sl@0
   458
                            M3Gfloat clipNear, M3Gfloat clipFar)
sl@0
   459
{
sl@0
   460
    Camera *camera = (Camera *) handle;
sl@0
   461
    M3G_VALIDATE_OBJECT(camera);
sl@0
   462
sl@0
   463
    if (height <= 0 || aspectRatio <= 0.0f) {
sl@0
   464
        m3gRaiseError(M3G_INTERFACE(camera), M3G_INVALID_VALUE);
sl@0
   465
        return;
sl@0
   466
    }
sl@0
   467
sl@0
   468
    camera->projType   = M3G_PARALLEL;
sl@0
   469
    camera->heightFov  = height;
sl@0
   470
    camera->aspect     = aspectRatio;
sl@0
   471
    camera->clipNear   = clipNear;
sl@0
   472
    camera->clipFar    = clipFar;
sl@0
   473
sl@0
   474
    m3gValidateProjectionMatrix(camera);
sl@0
   475
}
sl@0
   476
sl@0
   477
/*!
sl@0
   478
 * \brief Sets a perspective projection.
sl@0
   479
 *
sl@0
   480
 * \param handle        Camera object
sl@0
   481
 * \param fovy          fovy
sl@0
   482
 * \param aspectRatio   viewport aspect ratio
sl@0
   483
 * \param clipNear      near clipping plane
sl@0
   484
 * \param clipFar       far clipping plane
sl@0
   485
 */
sl@0
   486
M3G_API void m3gSetPerspective(M3GCamera handle,
sl@0
   487
                               M3Gfloat fovy,
sl@0
   488
                               M3Gfloat aspectRatio,
sl@0
   489
                               M3Gfloat clipNear, M3Gfloat clipFar)
sl@0
   490
{
sl@0
   491
    Camera *camera = (Camera *) handle;
sl@0
   492
    M3G_VALIDATE_OBJECT(camera);
sl@0
   493
sl@0
   494
    if (fovy <= 0.0f || fovy >= 180.f
sl@0
   495
        || aspectRatio <= 0.0f
sl@0
   496
        || clipNear <= 0.0f || clipFar <= 0.0f) {
sl@0
   497
        m3gRaiseError(M3G_INTERFACE(camera), M3G_INVALID_VALUE);
sl@0
   498
        return;
sl@0
   499
    }
sl@0
   500
sl@0
   501
    camera->projType   = M3G_PERSPECTIVE;
sl@0
   502
    camera->heightFov  = fovy;
sl@0
   503
    camera->aspect     = aspectRatio;
sl@0
   504
    camera->clipNear   = clipNear;
sl@0
   505
    camera->clipFar    = clipFar;
sl@0
   506
sl@0
   507
    m3gValidateProjectionMatrix(camera);
sl@0
   508
}
sl@0
   509
sl@0
   510
/*!
sl@0
   511
 * \brief Sets a generic projection.
sl@0
   512
 *
sl@0
   513
 * \param handle        Camera object
sl@0
   514
 * \param transform     projection matrix
sl@0
   515
 */
sl@0
   516
M3G_API void m3gSetProjectionMatrix(M3GCamera handle,
sl@0
   517
                                    const M3GMatrix *transform)
sl@0
   518
{
sl@0
   519
    Camera *camera = (Camera *) handle;
sl@0
   520
    M3G_VALIDATE_OBJECT(camera);
sl@0
   521
sl@0
   522
    if (transform == NULL) {
sl@0
   523
        m3gRaiseError(M3G_INTERFACE(camera), M3G_NULL_POINTER);
sl@0
   524
        return;
sl@0
   525
    }
sl@0
   526
    
sl@0
   527
    camera->projType = M3G_GENERIC;    
sl@0
   528
    m3gCopyMatrix(&camera->projMatrix, transform);
sl@0
   529
    
sl@0
   530
    m3gValidateProjectionMatrix(camera);
sl@0
   531
}
sl@0
   532
sl@0
   533
/*!
sl@0
   534
 * \brief Gets camera matrix.
sl@0
   535
 *
sl@0
   536
 * \param handle        Camera object
sl@0
   537
 * \param transform     projection matrix to fill in
sl@0
   538
 * \return              projection type
sl@0
   539
 */
sl@0
   540
M3G_API M3Gint m3gGetProjectionAsMatrix(M3GCamera handle,
sl@0
   541
                                        M3GMatrix *transform)
sl@0
   542
{
sl@0
   543
    Camera *camera = (Camera *) handle;
sl@0
   544
    M3G_VALIDATE_OBJECT(camera);
sl@0
   545
sl@0
   546
    if (transform != NULL) {
sl@0
   547
        /* Check for impossible projection matrix */
sl@0
   548
        if (camera->projType != M3G_GENERIC && 
sl@0
   549
            camera->clipFar == camera->clipNear) {
sl@0
   550
            m3gRaiseError(M3G_INTERFACE(camera), M3G_ARITHMETIC_ERROR);
sl@0
   551
            return 0;
sl@0
   552
        }
sl@0
   553
sl@0
   554
        m3gCopyMatrix(transform, m3gProjectionMatrix(camera));
sl@0
   555
    }
sl@0
   556
sl@0
   557
    return camera->projType;
sl@0
   558
}
sl@0
   559
sl@0
   560
/*!
sl@0
   561
 * \brief Gets camera parameters.
sl@0
   562
 *
sl@0
   563
 * \param handle        Camera object
sl@0
   564
 * \param params        camera parameters to fill in
sl@0
   565
 * \return              projection type
sl@0
   566
 */
sl@0
   567
M3G_API M3Gint m3gGetProjectionAsParams(M3GCamera handle, M3Gfloat *params)
sl@0
   568
{
sl@0
   569
    Camera *camera = (Camera *) handle;
sl@0
   570
    M3G_VALIDATE_OBJECT(camera);
sl@0
   571
sl@0
   572
    if (params != NULL && camera->projType != M3G_GENERIC) {
sl@0
   573
        params[0] = camera->heightFov;
sl@0
   574
        params[1] = camera->aspect;
sl@0
   575
        params[2] = camera->clipNear;
sl@0
   576
        params[3] = camera->clipFar;
sl@0
   577
    }
sl@0
   578
sl@0
   579
    return camera->projType;
sl@0
   580
}
sl@0
   581