OSGFishEyeProjector.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038
00039 #include <stdlib.h>
00040 #include <stdio.h>
00041
00042 #include <sstream>
00043 #include <fstream>
00044
00045 #include "OSGConfig.h"
00046
00047 #include "OSGAction.h"
00048 #include "OSGCamera.h"
00049 #include "OSGRenderAction.h"
00050 #include "OSGSceneFileHandler.h"
00051 #include "OSGVolumeDraw.h"
00052
00053 #include "OSGFishEyeProjector.h"
00054 #include "OSGFishEyeProjectorData.h"
00055
00056 #include "OSGFrameBufferObject.h"
00057 #include "OSGFrameBufferAttachment.h"
00058 #include "OSGRenderBuffer.h"
00059 #include "OSGTextureBuffer.h"
00060
00061 #include "OSGChunkMaterial.h"
00062 #include "OSGMaterialChunk.h"
00063 #include "OSGTextureObjChunk.h"
00064 #include "OSGDrawEnv.h"
00065 #include "OSGImageFunctions.h"
00066 #include "OSGStateOverride.h"
00067 #include "OSGTextureEnvChunk.h"
00068 #include "OSGSimpleSHLFunctions.h"
00069 #include "OSGPerspectiveCamera.h"
00070
00071 #include "OSGTypedGeoVectorProperty.h"
00072 #include "OSGTypedGeoIntegralProperty.h"
00073
00074
00075 #include "OSGMatrixUtility.h"
00076
00077 #include "OSGGLU.h"
00078
00079
00080 OSG_USING_NAMESPACE
00081
00089 UInt32 FishEyeProjector::_uiFramebuffer_object_extension =
00090     Window::invalidExtensionID;
00091
00092 UInt32 FishEyeProjector::_uiFuncDrawBuffers              =
00093     Window::invalidFunctionID;
00094
00095 typedef void   (OSG_APIENTRY *GLDrawBuffersEXTProcT)(
00096     GLsizei  n,
00097     const GLenum  *buffers);
00098
00099
00100
00101
00102 void osgMedian(Vec3d &vRes, const Vec3d &v1, const Vec3d &v2)
00103 {
00104     vRes[0] = (v1[0] + v2[0]) * 0.5;
00105     vRes[1] = (v1[1] + v2[1]) * 0.5;
00106     vRes[2] = (v1[2] + v2[2]) * 0.5;
00107 }
00108
00109 void osgMedian(Vec2d &vRes, const Vec2d &v1, const Vec2d &v2)
00110 {
00111     vRes[0] = (v1[0] + v2[0]) * 0.5;
00112     vRes[1] = (v1[1] + v2[1]) * 0.5;
00113 }
00114
00115
00116 Vec3d osgRotateX(Vec3d p,double theta)
00117 {
00118     Vec3d q;
00119
00120     q[0] =  p[0];
00121     q[1] =  p[1] * cos(theta) + p[2] * sin(theta);
00122     q[2] = -p[1] * sin(theta) + p[2] * cos(theta);
00123
00124     return q;
00125 }
00126
00127 int FishEyeProjector::MirrorPosition(Vec3d   c,
00128                                      Real64  r,
00129                                      Vec3d   p1,
00130                                      Vec3d   p2,
00131                                      Vec3d  &p0)
00132 {
00133     int i;
00134     int nres = 1000;
00135
00136     double theta,thetamax,thetamin,phi;
00137     double ctheta,stheta;
00138     double l1,l2,val,valmin;
00139     Vec3d  p;
00140
00141     p0.setValues(0.0, 0.0, 0.0);
00142
00143     if(p1[2] < 0)
00144         return 1;
00145
00146     // Translate to origin
00147     p1[0] -= c[0];
00148     p2[0] -= c[0];
00149
00150     // Rotate about z axis so p1 lies in x-z plane
00151     phi = atan2(p1[1], p1[2]);
00152
00153     p1 = osgRotateX(p1, -phi);
00154
00155     if(fabs(p1[1]) > 0.00001)
00156         return 2;
00157
00158     // Calculate the maximum possible value of theta
00159     // Mirror is at origin
00160     if(fabs(p2[0]) <= r)
00161         return 3;
00162
00163     thetamax = acos(r / fabs(p2[0]));
00164
00165     // Iterate to find the minimum light path length
00166     thetamin = thetamax;
00167     valmin   = 1e32;
00168
00169     for(i = 0; i <= nres; i++)
00170     {
00171         theta = i * PiHalf / double(nres);
00172
00173         if(theta >= thetamax)
00174             break;
00175
00176         ctheta = cos(theta);
00177         stheta = sin(theta);
00178
00179         l1 = ((p2[0] + r * ctheta) *(p2[0] + r * ctheta) +
00180               (r * stheta)*(r * stheta));
00181
00182         l2 = ((p1[0] + r * ctheta) *(p1[0] + r * ctheta) +
00183               (p1[2] - r * stheta) *(p1[2] - r * stheta));
00184
00185         val = sqrt(l1) + sqrt(l2);
00186
00187         if (val < valmin)
00188         {
00189             valmin   = val;
00190             thetamin = theta;
00191         }
00192     }
00193
00194     if(thetamin < 0)
00195         return 4;
00196
00197     // Calculate p0
00198     p[0] = -r * cos(thetamin);
00199     p[1] =  0;
00200     p[2] =  r * sin(thetamin);
00201
00202     // Rotate back
00203     p = osgRotateX(p, phi);
00204
00205     // Translate back
00206     p[0] += c[0];
00207
00208     p0 = p;
00209
00210     return 0;
00211 }
00212
00213 void FishEyeProjector::EstimateWarp(Real64  u, Real64 v,
00214                                     Real64 &x, Real64 &z,
00215                                     Real64 &br)
00216 {
00217 #if 0
00218     Int32  ix,iy;
00219     Real64 tu,tv;
00220 #endif
00221     Int32  n;
00222     Real64 mu,longitude,latitude;
00223     Vec3d  p1,p,p0;
00224
00225     Real64 domeradius   = this->getDomeRadius  (); // 2.5;
00226     Real64 mirrorradius = this->getMirrorRadius(); //0.3;
00227     Vec3d  mirrorpos    = this->getMirrorPos   (); //(2.4,0,0);
00228     Vec3d  projectorpos = this->getProjectorPos(); //(1.85,0,0);
00229     Real64 aspectratio  = this->getAspectRatio (); // 4/3.0;
00230     Real64 throwdist    = this->getThrowDist   (); //1.5;
00231
00232     Vec3d  frustum[4];
00233
00234     if(this->getMode() == FishEyeProjector::MirrorDome)
00235     {
00236         // Location of projection plane, 1 unit in front of projector
00237         for(Int32 i = 0; i < 4; i++)
00238             frustum[i][0] = projectorpos[0] + 1;
00239
00240         frustum[0][1] = -0.5 / throwdist;
00241         frustum[1][1] = -0.5 / throwdist;
00242         frustum[2][1] =  0.5 / throwdist;
00243         frustum[3][1] =  0.5 / throwdist;
00244         frustum[0][2] =  0;
00245         frustum[1][2] =  1.0 / (throwdist * aspectratio);
00246         frustum[2][2] =  1.0 / (throwdist * aspectratio);
00247         frustum[3][2] =  0;
00248
00249         // longitude and latitude, latitude clampd at pi/2
00250         // latitude = 0 at north pole of dome, pi/2 at horizon of dome
00251         longitude = atan2(v, u); // -pi to pi
00252         latitude  = PiHalf * sqrt(u * u + v * v);
00253
00254         if (latitude > PiHalf)
00255             latitude = PiHalf;
00256
00257         // p1 is the point on the dome, dome centered at the origin
00258         p1[0] = domeradius * sin(latitude) * sin(longitude);
00259         p1[1] = domeradius * sin(latitude) * cos(longitude);
00260         p1[2] = domeradius * cos(latitude);
00261
00262         // Calculate the reflection position on the dome
00263         if ((n = MirrorPosition(mirrorpos,
00264                                 mirrorradius,
00265                                 p1,
00266                                 projectorpos,
00267                                 p0          )) != 0)
00268         {
00269             fprintf(stderr,"Error %d, at (%g,%g) = (%g,%g)\n",
00270                     n,u,v,latitude,longitude);
00271         }
00272
00273         // Calculate the point "p" on the projection plane
00274         mu = (frustum[0][0] - projectorpos[0]) / (p0[0] - projectorpos[0]);
00275
00276         p[0] = frustum[0][0];
00277         p[1] = projectorpos[1] + mu * (p0[1] - projectorpos[1]);
00278         p[2] = projectorpos[2] + mu * (p0[2] - projectorpos[2]);
00279
00280         // Set brigthness
00281         br = 1;
00282
00283         if (p1[0] > 0)
00284             br = 1 - p1[0] / domeradius;
00285
00286         if (br < 0)
00287             br = 0;
00288
00289         if (p1[0] >= mirrorpos[0])
00290             br = -1;
00291
00292         p[1] *= throwdist;
00293         p[1] *= 2;
00294         p[1] *= aspectratio;
00295
00296         p[2] *= throwdist;
00297         p[2] *= aspectratio;
00298         p[2] *= 2;
00299         p[2] -= 1;
00300
00301         x = p[1];
00302         z = p[2];
00303
00304     }
00305     else
00306     {
00307         // warp mesh ToDo
00308     }
00309 }
00310
00311 /*-------------------------------------------------------------------------*/
00312 /*                               Sync                                      */
00313
00314 void FishEyeProjector::changed(ConstFieldMaskArg whichField,
00315                                UInt32            origin,
00316                                BitVector         details)
00317 {
00318     if(0x0000 != (whichField & (ModeFieldMask | MeshRefinementLevelFieldMask)))
00319     {
00320         if(_sfMode.getValue() < 0x0001)
00321             _sfMode.setValue(0x0001);
00322
00323         if(_sfMode.getValue() > 0x0006)
00324             _sfMode.setValue(0x0006);
00325
00326         fprintf(stderr, "Rebuild for %d %d\n",
00327                 _sfMode.getValue(),
00328                 _sfMeshRefinementLevel.getValue());
00329
00330         rebuildGeometries();
00331     }
00332
00333     if(0x0000 != (whichField & ShowDomeIntensityFieldMask))
00334     {
00335         for(UInt32 i = 0; i < 4; ++i)
00336         {
00337             Geometry *pGeo = _mfGeometries[i];
00338
00339             if(pGeo == NULL)
00340                 continue;
00341
00342             GeoVectorProperty *pColProp =
00343                 pGeo->getProperty(Geometry::ColorsIndex);
00344
00345             if(pColProp != NULL)
00346             {
00347                 pColProp->setIgnore(!this->getShowDomeIntensity());
00348             }
00349         }
00350     }
00351
00352     Inherited::changed(whichField, origin, details);
00353 }
00354
00355 /*-------------------------------------------------------------------------*/
00356 /*                               Dump                                      */
00357
00358 void FishEyeProjector::dump(      UInt32    OSG_CHECK_ARG(uiIndent),
00359                                   const BitVector OSG_CHECK_ARG(bvFlags )) const
00360 {
00361     SLOG << "Dump VisitSubTree NI" << std::endl;
00362 }
00363
00364 /*-------------------------------------------------------------------------*/
00365 /*                            Constructors                                 */
00366
00367 FishEyeProjector::FishEyeProjector(void) :
00368     Inherited  (  )
00369 {
00370 }
00371
00372 FishEyeProjector::FishEyeProjector(const FishEyeProjector &source) :
00373
00374     Inherited  (source)
00375 {
00376 }
00377
00378 /*-------------------------------------------------------------------------*/
00379 /*                             Destructor                                  */
00380
00381 FishEyeProjector::~FishEyeProjector(void)
00382 {
00383 }
00384
00385 /*-------------------------------------------------------------------------*/
00386 /*                                Draw                                     */
00387
00394 ActionBase::ResultE FishEyeProjector::renderEnter(Action *action)
00395 {
00396     static Matrix transforms[] =
00397         {
00398             // left
00399             Matrix( 1,  0,  0,  0,
00400                     0,  1,  0,  0,
00401                     0,  0,  1,  0,
00402                     0,  0,  0,  1),
00403
00404             // right
00405             Matrix( 0,  0, -1,  0,
00406                     0,  1,  0,  0,
00407                     1,  0,  0,  0,
00408                     0,  0,  0,  1),
00409
00410             // bottom
00411             Matrix( 1,  0,  0,  0,
00412                     0,  0,  1,  0,
00413                     0, -1,  0,  0,
00414                     0,  0,  0,  1),
00415
00416             // top
00417             Matrix( 1,  0,  0,  0,
00418                     0,  0, -1,  0,
00419                     0,  1,  0,  0,
00420                     0,  0,  0,  1),
00421         };
00422
00423     static Matrix deltaTr[] =
00424         {
00425             Matrix ( 0.70710678f,  0,  0.70710678f,  0,
00426                      0,            1,  0,            0,
00427                      -0.70710678f, 0,  0.70710678f,  0,
00428                      0,            0,  0,            1),
00429
00430             Matrix ( 0.70710678f,  0,  0.70710678f,  0,
00431                      0,            1,  0,            0,
00432                      -0.70710678f, 0,  0.70710678f,  0,
00433                      0,            0,  0,            1),
00434
00435             Matrix (-0.70710678f, 0, -0.70710678f,  0,
00436                     0,            1,  0,            0,
00437                     0.70710678f,  0, -0.70710678f,  0,
00438                     0,            0,  0,            1),
00439
00440             Matrix ( 0.70710678f, 0, -0.70710678f, 0,
00441                      0,           1,  0,           0,
00442                      0.70710678f, 0,  0.70710678f, 0,
00443                      0,           0,  0,           1)
00444         };
00445
00446     RenderAction *a = dynamic_cast<RenderAction *>(action);
00447
00448     a->disableDefaultPartition();
00449
00450
00451     Background      *pBack      = a->getBackground();
00452
00453     Viewport        *pPort      = a->getViewport();
00454
00455
00456     FishEyeProjectorData *pData =
00457         a->getData<FishEyeProjectorData *>(_iDataSlotId);
00458
00459
00460     if(pData == NULL)
00461     {
00462         pData = this->initData(a);
00463     }
00464
00465     a->beginPartitionGroup();
00466     {
00467
00468         FrameBufferObject *pTarget  = pData->getRenderTarget();
00469
00470         Matrix mGlobalCam;
00471
00472         if(pPort != NULL)
00473         {
00474             Camera *pGlobalCam = pPort->getCamera();
00475
00476
00477             pGlobalCam->getViewing(mGlobalCam,
00478                                    pPort->getPixelWidth (),
00479                                    pPort->getPixelHeight());
00480         }
00481
00482
00483         Camera *pCam = pData->getCamera();
00484
00485         for(UInt32 i = 0; i < 4; ++i)
00486         {
00487             a->pushPartition();
00488             {
00489                 RenderPartition   *pPart    = a->getActivePartition();
00490
00491                 pPart->setVolumeDrawing(false);
00492
00493                 pPart->setRenderTarget(pTarget       );
00494                 pPart->setWindow      (a->getWindow());
00495
00496                 pPart->calcViewportDimension(0,
00497                                              0,
00498                                              1,
00499                                              1,
00500                                              this->getResolution(),
00501                                              this->getResolution());
00502
00503                 Matrix m, t;
00504
00505                 // set the projection
00506                 pCam->getProjection          (m,
00507                                               pPart->getViewportWidth (),
00508                                               pPart->getViewportHeight());
00509
00510                 pCam->getProjectionTranslation(t,
00511                                                pPart->getViewportWidth (),
00512                                                pPart->getViewportHeight());
00513
00514                 pPart->setupProjection(m, t);
00515
00516                 m = transforms[i];
00517
00518                 m.multLeft(deltaTr[i]);
00519
00520                 m.invert();
00521
00522                 m.mult(mGlobalCam);
00523
00524                 pPart->setupViewing(m);
00525
00526                 pPart->setNear     (pCam->getNear());
00527                 pPart->setFar      (pCam->getFar ());
00528
00529                 pPart->calcFrustum();
00530
00531                 pPart->setBackground(pBack);
00532
00533
00534                 a->useNodeList(false);
00535
00536                 this->recurseFromThis(a);
00537
00538                 pPart->setDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + i);
00539
00540 #ifdef OSG_DEBUGX
00541                 std::string szMessage("fishX\n");
00542                 pPart->setDebugString(szMessage          );
00543 #endif
00544             }
00545             a->popPartition();
00546         }
00547
00548
00549
00550         a->pushPartition((RenderPartition::CopyWindow      |
00551                           RenderPartition::CopyViewportSize),
00552                          RenderPartition::SimpleCallback);
00553         {
00554             RenderPartition *pPart  = a->getActivePartition();
00555
00556 #ifdef OSG_DEBUGX
00557             std::string szMessage("PostProcessPartition\n");
00558             pPart->setDebugString(szMessage          );
00559 #endif
00560 
00561             Matrix m, t;
00562
00563             m.setIdentity();
00564             t.setIdentity();
00565
00566             MatrixOrthogonal( m,
00567                               0.f, 1.f,
00568                               0.f, 1.f,
00569                               -1.f, 1.f);
00570
00571             pPart->setupProjection(m, t);
00572
00573             RenderPartition::SimpleDrawCallback f;
00574
00575             f = boost::bind(&FishEyeProjector::postProcess, this, _1);
00576
00577             pPart->dropFunctor(f);
00578         }
00579         a->popPartition();
00580     }
00581     a->endPartitionGroup();
00582
00583     return Action::Skip;
00584 }
00585
00586 ActionBase::ResultE FishEyeProjector::renderLeave(Action *action)
00587 {
00588     return Action::Skip;
00589 }
00590
00591 /*-------------------------------------------------------------------------*/
00592 /*                               Init                                      */
00593
00594 void FishEyeProjector::initMethod(InitPhase ePhase)
00595 {
00596     Inherited::initMethod(ePhase);
00597
00598     if(ePhase == TypeObject::SystemPost)
00599     {
00600         RenderAction::registerEnterDefault(
00601             FishEyeProjector::getClassType(),
00602             reinterpret_cast<Action::Callback>(&FishEyeProjector::renderEnter));
00603
00604         RenderAction::registerLeaveDefault(
00605             FishEyeProjector::getClassType(),
00606             reinterpret_cast<Action::Callback>(&FishEyeProjector::renderLeave));
00607
00608         _uiFramebuffer_object_extension =
00609             Window::registerExtension("GL_EXT_framebuffer_object");
00610
00611         _uiFuncDrawBuffers  =
00612             Window::registerFunction (
00613                 OSG_DLSYM_UNDERSCORE"glDrawBuffersARB",
00614                 _uiFramebuffer_object_extension);
00615     }
00616 }
00617
00618 void FishEyeProjector::warpData(Geometry *pGeo)
00619 {
00620     GeoVec3dPropertyUnrecPtr pPosProp =
00621         dynamic_cast<GeoVec3dProperty *>(
00622             pGeo->getProperty(Geometry::PositionsIndex));
00623
00624     GeoVec2dPropertyUnrecPtr pUVProp  =
00625         dynamic_cast<GeoVec2dProperty *>(
00626             pGeo->getProperty(Geometry::TexCoordsIndex));
00627
00628     GeoColor3fPropertyUnrecPtr pColProp =
00629         dynamic_cast<GeoColor3fProperty *>(
00630             pGeo->getProperty(Geometry::ColorsIndex));
00631
00632     if(pColProp == NULL)
00633     {
00634         pColProp = GeoColor3fProperty::create();
00635
00636         GeoUInt32Property *pIdx =
00637             dynamic_cast<GeoUInt32Property *>(
00638                 pGeo->getIndex(Geometry::TexCoordsIndex));
00639
00640
00641         pGeo->setProperty(pColProp, Geometry::ColorsIndex);
00642         pGeo->setIndex   (pIdx,     Geometry::ColorsIndex);
00643     }
00644
00645     if(this->getShowDomeIntensity() == false)
00646         pColProp->setIgnore(true);
00647
00648     MFVec3d   &oPos = *(pPosProp->editFieldPtr());
00649     MFVec2d   &oUV  = *(pUVProp ->editFieldPtr());
00650     MFColor3f &oCol = *(pColProp->editFieldPtr());
00651
00652     oCol.resize(oPos.size());
00653
00654     Real64 x[3], z[3], b[3];
00655
00656     UInt32 uiNumTris = oPos.size() / 3;
00657
00658     UInt32 uiCurrIdx = 0;
00659
00660     for(UInt32 i = 0; i < uiNumTris; ++i)
00661     {
00662
00663         EstimateWarp(oPos[i * 3 + 0][0],
00664                      oPos[i * 3 + 0][2], (x[0]), (z[0]), (b[0]));
00665
00666         EstimateWarp(oPos[i * 3 + 1][0],
00667                      oPos[i * 3 + 1][2], (x[1]), (z[1]), (b[1]));
00668
00669         EstimateWarp(oPos[i * 3 + 2][0],
00670                      oPos[i * 3 + 2][2], (x[2]), (z[2]), (b[2]));
00671
00672         if(b[0] < 0 || b[1] < 0 || b[2] < 0)
00673         {
00674             continue;
00675         }
00676
00677         for(UInt32 j = 0; j < 3; ++j)
00678         {
00679             oPos[uiCurrIdx][0] = x[j];
00680             oPos[uiCurrIdx][1] = 0;
00681             oPos[uiCurrIdx][2] = z[j];
00682
00683             oUV[uiCurrIdx] = oUV[i * 3 + j];
00684
00685             oCol[uiCurrIdx].setValuesRGB(b[j], b[j], b[j]);
00686
00687             ++uiCurrIdx;
00688         }
00689     }
00690
00691     oPos.resize(uiCurrIdx);
00692     oUV .resize(uiCurrIdx);
00693     oCol.resize(uiCurrIdx);
00694 }
00695
00696
00697 void FishEyeProjector::flattenVertex(Vec3d  &oVertex,
00698                                      Real64  aperture)
00699 {
00700     double phi,r;
00701
00702     r   = atan2(osgSqrt(oVertex[0] * oVertex[0] + oVertex[2] * oVertex[2]),
00703                 oVertex[1]) / (osgDegree2Rad(aperture) / 2);
00704
00705     phi = atan2(oVertex[2], oVertex[0]);
00706
00707     oVertex[0] = r * osgCos(phi);
00708     oVertex[1] = 0;
00709     oVertex[2] = r * osgSin(phi);
00710 }
00711
00712 void FishEyeProjector::splitFaces(MFVec2d &vUV,
00713                                   MFVec3d &vP,
00714                                   UInt32  &uiSize)
00715 {
00716     UInt32 oldSize = uiSize;
00717     UInt32 n2      = uiSize;
00718
00719     for(UInt32 i = 0; i < oldSize; i++)
00720     {
00721         osgMedian(vP[n2 * 3 + 0], vP[i * 3 + 0], vP[i * 3 + 1]);
00722
00723         vP[n2 * 3 + 1] = vP[i * 3 + 1];
00724
00725         osgMedian(vP[n2 * 3 + 2], vP[i * 3 + 1], vP[i * 3 + 2]);
00726
00727
00728         osgMedian(vUV[n2 * 3 + 0], vUV[i * 3 + 0], vUV[i * 3 + 1]);
00729
00730         vUV[n2 * 3 + 1] = vUV[i * 3 + 1];
00731
00732         osgMedian(vUV[n2 * 3 + 2], vUV[i * 3 + 1], vUV[i * 3 + 2]);
00733
00734
00735
00736         osgMedian(vP[(n2+1) * 3 + 0], vP[i * 3 + 1],vP[i * 3 + 2]);
00737
00738         vP[(n2+1) * 3 + 1] = vP[i * 3 + 2];
00739
00740         osgMedian(vP[(n2+1) * 3 + 2], vP[i * 3 + 2],vP[i * 3 + 0]);
00741
00742
00743         osgMedian(vUV[(n2+1) * 3 + 0], vUV[i * 3 + 1], vUV[i * 3 + 2]);
00744
00745         vUV[(n2+1) * 3 + 1] = vUV[i * 3 + 2];
00746
00747         osgMedian(vUV[(n2+1) * 3 + 2], vUV[i * 3 + 2], vUV[i * 3 + 0]);
00748
00749
00750
00751         osgMedian(vP[(n2+2) * 3 + 0], vP[i * 3 + 0], vP[i * 3 + 1]);
00752         osgMedian(vP[(n2+2) * 3 + 1], vP[i * 3 + 1], vP[i * 3 + 2]);
00753         osgMedian(vP[(n2+2) * 3 + 2], vP[i * 3 + 2], vP[i * 3 + 0]);
00754
00755         osgMedian(vUV[(n2+2) * 3 + 0], vUV[i * 3 + 0], vUV[i * 3 + 1]);
00756         osgMedian(vUV[(n2+2) * 3 + 1], vUV[i * 3 + 1], vUV[i * 3 + 2]);
00757         osgMedian(vUV[(n2+2) * 3 + 2], vUV[i * 3 + 2], vUV[i * 3 + 0]);
00758
00759
00760
00761         osgMedian(vP[i * 3 + 1], vP[i * 3 + 0], vP[i * 3 + 1]);
00762         osgMedian(vP[i * 3 + 2], vP[i * 3 + 0], vP[i * 3 + 2]);
00763
00764         osgMedian(vUV[i * 3 + 1], vUV[i * 3 + 0], vUV[i * 3 + 1]);
00765         osgMedian(vUV[i * 3 + 2], vUV[i * 3 + 0], vUV[i * 3 + 2]);
00766
00767         n2 += 3;
00768     }
00769
00770     uiSize = n2;
00771 }
00772
00773
00774 void FishEyeProjector::initTopMesh(Geometry *pGeo)
00775 {
00776     GeoVec2dPropertyUnrecPtr pUVProp  =
00777         dynamic_cast<GeoVec2dProperty *>(
00778             pGeo->getProperty(Geometry::TexCoordsIndex));
00779
00780     GeoVec3dPropertyUnrecPtr pPosProp =
00781         dynamic_cast<GeoVec3dProperty *>(
00782             pGeo->getProperty(Geometry::PositionsIndex));
00783
00784     OSG_ASSERT(pUVProp  != NULL);
00785     OSG_ASSERT(pPosProp != NULL);
00786
00787     MFVec2d  &oUV  = *(pUVProp ->editFieldPtr());
00788     MFVec3d  &oPos = *(pPosProp->editFieldPtr());
00789
00790     Real32 rSq2H = osgSqrt(2.0) / 2.0;
00791
00792     oUV .resize(3);
00793     oPos.resize(3);
00794
00795     oPos[0].setValues(-rSq2H,   0.0, 0.5);
00796     oPos[1].setValues(   0.0, rSq2H, 0.5);
00797     oPos[2].setValues( rSq2H,   0.0, 0.5);
00798
00799
00800     oUV[0].setValues(0.0, 1.0);
00801     oUV[1].setValues(0.0, 0.0);
00802     oUV[2].setValues(1.0, 0.0);
00803 }
00804
00805 void FishEyeProjector::initBottomMesh(Geometry *pGeo)
00806 {
00807     GeoVec2dPropertyUnrecPtr pUVProp  =
00808         dynamic_cast<GeoVec2dProperty *>(
00809             pGeo->getProperty(Geometry::TexCoordsIndex));
00810
00811     GeoVec3dPropertyUnrecPtr pPosProp =
00812         dynamic_cast<GeoVec3dProperty *>(
00813             pGeo->getProperty(Geometry::PositionsIndex));
00814
00815     OSG_ASSERT(pUVProp  != NULL);
00816     OSG_ASSERT(pPosProp != NULL);
00817
00818     MFVec2d  &oUV  = *(pUVProp ->editFieldPtr());
00819     MFVec3d  &oPos = *(pPosProp->editFieldPtr());
00820
00821     Real32 rSq2H = osgSqrt(2.0) / 2.0;
00822
00823     oUV .resize(3);
00824     oPos.resize(3);
00825
00826     oPos[0].setValues(-rSq2H,   0.0, -0.5);
00827     oPos[1].setValues( rSq2H,   0.0, -0.5);
00828     oPos[2].setValues(   0.0, rSq2H, -0.5);
00829
00830     oUV[0].setValues(1.0, 0.0);
00831     oUV[1].setValues(0.0, 1.0);
00832     oUV[2].setValues(0.0, 0.0);
00833 }
00834
00835 void FishEyeProjector::initLeftMesh(Geometry *pGeo)
00836 {
00837     GeoVec2dPropertyUnrecPtr pUVProp  =
00838         dynamic_cast<GeoVec2dProperty *>(
00839             pGeo->getProperty(Geometry::TexCoordsIndex));
00840
00841     GeoVec3dPropertyUnrecPtr pPosProp =
00842         dynamic_cast<GeoVec3dProperty *>(
00843             pGeo->getProperty(Geometry::PositionsIndex));
00844
00845     OSG_ASSERT(pUVProp  != NULL);
00846     OSG_ASSERT(pPosProp != NULL);
00847
00848     MFVec2d  &oUV  = *(pUVProp ->editFieldPtr());
00849     MFVec3d  &oPos = *(pPosProp->editFieldPtr());
00850
00851     Real32 rSq2H = osgSqrt(2.0) / 2.0;
00852
00853     oUV .resize(6);
00854     oPos.resize(6);
00855
00856     oPos[0].setValues(-rSq2H,   0.0, -0.5);
00857     oPos[1].setValues(   0.0, rSq2H, -0.5);
00858     oPos[2].setValues(-rSq2H,   0.0,  0.5);
00859
00860     oUV[0].setValues(0.0, 0.0);
00861     oUV[1].setValues(1.0, 0.0);
00862     oUV[2].setValues(0.0, 1.0);
00863
00864
00865     oPos[3].setValues(-rSq2H,   0.0,  0.5);
00866     oPos[4].setValues(   0.0, rSq2H, -0.5);
00867     oPos[5].setValues(   0.0, rSq2H,  0.5);
00868
00869     oUV[3].setValues(0.0, 1.0);
00870     oUV[4].setValues(1.0, 0.0);
00871     oUV[5].setValues(1.0, 1.0);
00872 }
00873
00874 void FishEyeProjector::initRightMesh(Geometry *pGeo)
00875 {
00876     GeoVec2dPropertyUnrecPtr pUVProp  =
00877         dynamic_cast<GeoVec2dProperty *>(
00878             pGeo->getProperty(Geometry::TexCoordsIndex));
00879
00880     GeoVec3dPropertyUnrecPtr pPosProp =
00881         dynamic_cast<GeoVec3dProperty *>(
00882             pGeo->getProperty(Geometry::PositionsIndex));
00883
00884     OSG_ASSERT(pUVProp  != NULL);
00885     OSG_ASSERT(pPosProp != NULL);
00886
00887     MFVec2d  &oUV  = *(pUVProp ->editFieldPtr());
00888     MFVec3d  &oPos = *(pPosProp->editFieldPtr());
00889
00890     Real32 rSq2H = osgSqrt(2.0) / 2.0;
00891
00892     oUV .resize(6);
00893     oPos.resize(6);
00894
00895     oPos[0].setValues(0.0, rSq2H, -0.5);
00896     oPos[1].setValues(rSq2H, 0.0, -0.5);
00897     oPos[2].setValues(rSq2H, 0.0, 0.5);
00898
00899     oUV[0].setValues(0.0, 0.0);
00900     oUV[1].setValues(1.0, 0.0);
00901     oUV[2].setValues(1.0, 1.0);
00902
00903
00904     oPos[3].setValues(  0.0, rSq2H, -0.5);
00905     oPos[4].setValues(rSq2H,   0.0,  0.5);
00906     oPos[5].setValues(  0.0, rSq2H,  0.5);
00907
00908     oUV[3].setValues(0.0, 0.0);
00909     oUV[4].setValues(1.0, 1.0);
00910     oUV[5].setValues(0.0, 1.0);
00911 }
00912
00913 void FishEyeProjector::updateMesh(Geometry *pGeo)
00914 {
00915     GeoVec2dPropertyUnrecPtr pUVProp  =
00916         dynamic_cast<GeoVec2dProperty *>(
00917             pGeo->getProperty(Geometry::TexCoordsIndex));
00918
00919     GeoVec3dPropertyUnrecPtr pPosProp =
00920         dynamic_cast<GeoVec3dProperty *>(
00921             pGeo->getProperty(Geometry::PositionsIndex));
00922
00923     OSG_ASSERT(pUVProp  != NULL);
00924     OSG_ASSERT(pPosProp != NULL);
00925
00926     MFVec2d  &oUV  = *(pUVProp ->editFieldPtr());
00927     MFVec3d  &oPos = *(pPosProp->editFieldPtr());
00928
00929     UInt32 uiNumTris = oPos.size() / 3;
00930
00931     for(UInt32 i = 0; i < this->getMeshRefinementLevel(); i++)
00932     {
00933         oUV .resize(4 * uiNumTris * 3);
00934         oPos.resize(4 * uiNumTris * 3);
00935
00936         splitFaces(oUV, oPos, uiNumTris);
00937     }
00938
00939     for(UInt32 i = 0; i < oPos.size(); i++)
00940         oPos[i].normalize();
00941
00942     for(UInt32 i = 0; i < oPos.size(); i++)
00943     {
00944         flattenVertex(oPos[i], 180.0);
00945     }
00946
00947
00948     GeoUInt32Property *pIdx =
00949         dynamic_cast<GeoUInt32Property *>(
00950             pGeo->getIndex(Geometry::TexCoordsIndex));
00951
00952     GeoUInt32Property *pLen =
00953         dynamic_cast<GeoUInt32Property *>(pGeo->getLengths());
00954
00955     GeoUInt8Property  *pTyp =
00956         dynamic_cast<GeoUInt8Property   *>(pGeo->getTypes());
00957
00958     OSG_ASSERT(pIdx != NULL);
00959     OSG_ASSERT(pLen != NULL);
00960     OSG_ASSERT(pTyp != NULL);
00961
00962
00963 //    if(this->getMode() == FishEyeProjector::WarpMap || ToDo
00964     if(this->getMode() == FishEyeProjector::MirrorDome )
00965     {
00966         warpData(pGeo);
00967     }
00968     else
00969     {
00970         GeoVectorProperty *pColProp = pGeo->getProperty(Geometry::ColorsIndex);
00971
00972         if(pColProp != NULL)
00973         {
00974             pColProp->setIgnore(true);
00975         }
00976     }
00977
00978     pTyp->clear();
00979     pLen->clear();
00980
00981     pTyp->push_back(GL_TRIANGLES);
00982     pLen->push_back(oPos.size() );
00983
00984     pIdx->clear();
00985
00986     for(UInt32 i = 0; i < oPos.size(); ++i)
00987     {
00988         pIdx->push_back(i);
00989     }
00990 }
00991
00992 void FishEyeProjector::rebuildGeometries(void)
00993 {
00994     if(this->_mfGeometries.size() == 0)
00995     {
00996         for(UInt32 i = 0; i < 4; ++i)
00997         {
00998             GeometryUnrecPtr pGeo = Geometry::create();
00999
01000             GeoVec2dPropertyUnrecPtr pUV  = GeoVec2dProperty::create();
01001             GeoVec3dPropertyUnrecPtr pPos = GeoVec3dProperty::create();
01002
01003             GeoUInt32PropertyUnrecPtr pIdx = GeoUInt32Property::create();
01004             GeoUInt32PropertyUnrecPtr pLen = GeoUInt32Property::create();
01005             GeoUInt8PropertyUnrecPtr  pTyp = GeoUInt8Property ::create();
01006
01007             pGeo->setProperty(pUV,  Geometry::TexCoordsIndex);
01008             pGeo->setProperty(pPos, Geometry::PositionsIndex);
01009
01010             pGeo->setTypes  (pTyp);
01011             pGeo->setLengths(pLen);
01012
01013             pGeo->setIndex(pIdx, Geometry::PositionsIndex);
01014             pGeo->setIndex(pIdx, Geometry::TexCoordsIndex);
01015
01016             this->pushToGeometries(pGeo);
01017         }
01018     }
01019
01020
01021     initTopMesh   (this->getGeometries(0));
01022     updateMesh    (this->getGeometries(0));
01023
01024     initBottomMesh(this->getGeometries(1));
01025     updateMesh    (this->getGeometries(1));
01026
01027     initLeftMesh  (this->getGeometries(2));
01028     updateMesh    (this->getGeometries(2));
01029
01030     initRightMesh (this->getGeometries(3));
01031     updateMesh    (this->getGeometries(3));
01032 }
01033
01034 FishEyeProjectorData *FishEyeProjector::initData(RenderActionBase *pAction)
01035 {
01036     FishEyeProjectorDataUnrecPtr pData =
01037         pAction->getData<FishEyeProjectorData *>(_iDataSlotId);
01038
01039     if(pData == NULL)
01040     {
01041         pData = setupStageData(pAction);
01042
01043         this->setData(pData, _iDataSlotId, pAction);
01044     }
01045
01046     return pData;
01047 }
01048
01049 FishEyeProjectorDataTransitPtr FishEyeProjector::setupStageData(
01050     RenderActionBase *pAction)
01051 {
01052     FishEyeProjectorDataTransitPtr returnValue =
01053         FishEyeProjectorData::createLocal();
01054
01055     if(returnValue == NULL)
01056         return returnValue;
01057
01058     FrameBufferObjectUnrecPtr pTarget      = NULL;
01059     RenderBufferUnrecPtr      pDepthBuffer = NULL;
01060
01061     pTarget      = FrameBufferObject::createLocal();
01062     pDepthBuffer = RenderBuffer     ::createLocal();
01063
01064     pDepthBuffer->setInternalFormat (GL_DEPTH_COMPONENT24);
01065
01066     pTarget     ->setDepthAttachment(pDepthBuffer        );
01067
01068     returnValue ->setRenderTarget   (pTarget             );
01069
01070
01071     for(UInt32 i = 0; i < 4; ++i)
01072     {
01073         TextureObjChunkUnrecPtr pTex = TextureObjChunk::createLocal();
01074
01075         ImageUnrecPtr pImg = Image::createLocal();
01076
01077         pImg->set(Image::OSG_RGB_PF,
01078                   this->getResolution(),
01079                   this->getResolution(),
01080                   1,
01081                   1,
01082                   1,
01083                   0.0,
01084                   0,
01085                   Image::OSG_UINT8_IMAGEDATA,
01086                   false,
01087                   1);
01088
01089         pTex   ->setImage         (pImg                   );
01090         pTex   ->setMinFilter     (GL_LINEAR              );
01091         pTex   ->setMagFilter     (GL_LINEAR              );
01092         pTex   ->setWrapS         (GL_CLAMP_TO_EDGE       );
01093         pTex   ->setWrapT         (GL_CLAMP_TO_EDGE       );
01094         pTex   ->setInternalFormat(this->getBufferFormat());
01095
01096
01097         TextureBufferUnrecPtr pTexBuffer = TextureBuffer::createLocal();
01098
01099         pTexBuffer->setTexture  (pTex         );
01100         pTexBuffer->setTexTarget(GL_TEXTURE_2D);
01101
01102         pTarget->setColorAttachment(pTexBuffer, i);
01103
01104         returnValue->editMFTextures()->push_back(pTex);
01105     }
01106
01107
01108
01109     pTarget->setSize(this->getResolution(),
01110                      this->getResolution());
01111
01112
01113
01114     PerspectiveCameraUnrecPtr pCam = PerspectiveCamera::createLocal();
01115
01116     pCam->setNear(pAction->getCamera()->getNear());
01117     pCam->setFar (pAction->getCamera()->getFar ());
01118
01119     pCam->setFov (osgDegree2Rad(90.f));
01120
01121     returnValue->setCamera(pCam);
01122
01123
01124     returnValue->setTextureRes   (this->getResolution  ());
01125     returnValue->setTextureFormat(this->getBufferFormat());
01126
01127
01128     commitChanges();
01129
01130
01131     return returnValue;
01132 }
01133
01134
01135 void FishEyeProjector::resizeStageData(FishEyeProjectorData *pData,
01136                                        Int32                 iPixelWidth,
01137                                        Int32                 iPixelHeight)
01138 {
01139     FWARNING(("FishEyeProjector resize not implemented ==> wrong results\n"));
01140 }
01141
01142
01143 void FishEyeProjector::postProcess(DrawEnv *pEnv)
01144 {
01145     Window *win = pEnv->getWindow();
01146
01147     if(win->hasExtension(_uiFramebuffer_object_extension) == false)
01148     {
01149         FNOTICE(("Framebuffer objects not supported on Window %p!\n", win));
01150         return;
01151     }
01152
01153     FishEyeProjectorData *pData =
01154         pEnv->getData<FishEyeProjectorData *>(_iDataSlotId);
01155
01156
01157     if(pData == NULL)
01158         return;
01159
01160
01161
01162
01163     if(this->getMode() == WarpMap)
01164     {
01165         glClearColor(0.0,0.0,0.0,0.0);
01166     }
01167     else
01168     {
01169         glClearColor(0.05f,0.05f,0.05f,0.0f);
01170     }
01171
01172
01173     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01174
01175
01176     // Create camera projection for dome
01177     glMatrixMode(GL_MODELVIEW);
01178     glPushMatrix();
01179     glLoadIdentity();
01180
01181     switch(this->getMode())
01182     {
01183         case TruncateBottom:
01184             gluLookAt(0.0,-1.0,0.25,0.0,0.0,0.25,0.0,0.0,1.0);
01185             break;
01186
01187         case TruncateTop:
01188             gluLookAt(0.0,-1.0,-0.25,0.0,0.0,-0.25,0.0,0.0,1.0);
01189             break;
01190
01191         case DomeVertical:
01192         case DomeHorizontal:
01193         case WarpMap:
01194         case MirrorDome:
01195         default:
01196             gluLookAt(0.0,-1.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0);
01197             break;
01198     }
01199
01200
01201     glMatrixMode(GL_PROJECTION);
01202     glPushMatrix();
01203     glLoadIdentity();
01204
01205
01206     glViewport(0,0,
01207                pEnv->getPixelWidth (),
01208                pEnv->getPixelHeight());
01209
01210     double r = pEnv->getPixelWidth () / double(pEnv->getPixelHeight());
01211
01212     switch(this->getMode())
01213     {
01214         case TruncateBottom:
01215         case TruncateTop:
01216             glOrtho(-r*0.75,r*0.75,-0.75,0.75,0.1,10.0);
01217             break;
01218
01219         case DomeHorizontal:
01220             glOrtho(-r*0.75,r*0.75,-0.75,0.75,0.1,10.0);
01221             break;
01222
01223         case DomeVertical:
01224         case WarpMap:
01225         case MirrorDome:
01226         default:
01227             glOrtho(-r,r,-1.0,1.0,0.1,10.0);
01228             break;
01229     }
01230
01231
01232     // Finally draw the dome geometry
01233
01234     if(this->getShowMesh() == true)
01235         glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
01236
01237     glColor3f(1.0,1.0,1.0);
01238
01239
01240     TextureObjChunk *pTexT = pData->getTextures (3);
01241     Geometry        *pGeoT = this->getGeometries(0);
01242
01243     pTexT->activate(pEnv);
01244
01245     pGeoT->drawPrimitives(pEnv);
01246
01247
01248     TextureObjChunk *pTexB = pData->getTextures (2);
01249     Geometry        *pGeoB = this->getGeometries(1);
01250
01251     pTexB->changeFrom(pEnv, pTexT);
01252
01253     pGeoB->drawPrimitives(pEnv);
01254
01255
01256     TextureObjChunk *pTexL = pData->getTextures (0);
01257     Geometry        *pGeoL = this->getGeometries(2);
01258
01259     pTexL->changeFrom(pEnv, pTexB);
01260
01261     pGeoL->drawPrimitives(pEnv);
01262
01263
01264     TextureObjChunk *pTexR = pData->getTextures (1);
01265     Geometry        *pGeoR = this->getGeometries(3);
01266
01267     pTexR->changeFrom(pEnv, pTexL);
01268
01269     pGeoR->drawPrimitives(pEnv);
01270
01271     pTexR->deactivate(pEnv);
01272
01273     if(this->getShowMesh() == true)
01274         glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
01275
01276
01277 #ifdef OSG_DRAW_FACES
01278     glMatrixMode(GL_MODELVIEW);
01279     glLoadIdentity();
01280
01281     glMatrixMode(GL_PROJECTION);
01282     glLoadIdentity();
01283
01284     glOrtho(-1.0,1.0,-1.0,1.0,0.1,10.0);
01285
01286     glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
01287
01288     glDisable(GL_DEPTH_TEST);
01289
01290     TextureObjChunk *pTex1 = pData->getTextures(0);
01291
01292     pTex1->activate(pEnv);
01293
01294     glBegin(GL_QUADS);
01295     {
01296         glTexCoord2f(0.0, 0.0);
01297         glVertex3f(-0.9, -0.9, -1.0);
01298
01299         glTexCoord2f(1.0, 0.0);
01300         glVertex3f(-0.6, -0.9, -1.0);
01301
01302         glTexCoord2f(1.0, 1.0);
01303         glVertex3f(-0.6, -0.6, -1.0);
01304
01305         glTexCoord2f(0.0, 1.0);
01306         glVertex3f(-0.9, -0.6, -1.0);
01307     }
01308     glEnd();
01309
01310     TextureObjChunk *pTex2 = pData->getTextures(1);
01311
01312     pTex2->changeFrom(pEnv, pTex1);
01313
01314     glBegin(GL_QUADS);
01315     {
01316         glTexCoord2f(0.0, 0.0);
01317         glVertex3f(-0.5, -0.9, -1.0);
01318
01319         glTexCoord2f(1.0, 0.0);
01320         glVertex3f(-0.2, -0.9, -1.0);
01321
01322         glTexCoord2f(1.0, 1.0);
01323         glVertex3f(-0.2, -0.6, -1.0);
01324
01325         glTexCoord2f(0.0, 1.0);
01326         glVertex3f(-0.5, -0.6, -1.0);
01327     }
01328     glEnd();
01329
01330     pTex1 = pData->getTextures(2);
01331
01332     pTex1->changeFrom(pEnv, pTex2);
01333
01334     glBegin(GL_QUADS);
01335     {
01336         glTexCoord2f(0.0, 0.0);
01337         glVertex3f(-0.1, -0.9, -1.0);
01338
01339         glTexCoord2f(1.0, 0.0);
01340         glVertex3f( 0.2, -0.9, -1.0);
01341
01342         glTexCoord2f(1.0, 1.0);
01343         glVertex3f( 0.2, -0.6, -1.0);
01344
01345         glTexCoord2f(0.0, 1.0);
01346         glVertex3f(-0.1, -0.6, -1.0);
01347     }
01348     glEnd();
01349
01350     pTex2 = pData->getTextures(3);
01351
01352     pTex2->changeFrom(pEnv, pTex1);
01353
01354     glBegin(GL_QUADS);
01355     {
01356         glTexCoord2f(0.0, 0.0);
01357         glVertex3f(0.3, -0.9, -1.0);
01358
01359         glTexCoord2f(1.0, 0.0);
01360         glVertex3f(0.6, -0.9, -1.0);
01361
01362         glTexCoord2f(1.0, 1.0);
01363         glVertex3f(0.6, -0.6, -1.0);
01364
01365         glTexCoord2f(0.0, 1.0);
01366         glVertex3f(0.3, -0.6, -1.0);
01367     }
01368     glEnd();
01369
01370     pTex2->deactivate(pEnv);
01371
01372     glEnable(GL_DEPTH_TEST);
01373 #endif
01374 
01375
01376     glMatrixMode(GL_PROJECTION);
01377     glPopMatrix();
01378
01379     glMatrixMode(GL_MODELVIEW);
01380     glPopMatrix();
01381
01382 }
01383