Equalizer  1.2.1
eqPixelBench/channel.cpp
00001 
00002 /* Copyright (c) 2007-2010, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions are met:
00006  *
00007  * - Redistributions of source code must retain the above copyright notice, this
00008  *   list of conditions and the following disclaimer.
00009  * - Redistributions in binary form must reproduce the above copyright notice,
00010  *   this list of conditions and the following disclaimer in the documentation
00011  *   and/or other materials provided with the distribution.
00012  * - Neither the name of Eyescale Software GmbH nor the names of its
00013  *   contributors may be used to endorse or promote products derived from this
00014  *   software without specific prior written permission.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00017  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00019  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00020  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00021  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00022  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00023  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00024  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00025  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00026  * POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00029 #include "channel.h"
00030 
00031 #include "config.h"
00032 #include "configEvent.h"
00033 
00034 #include <co/plugins/compressor.h>
00035 
00036 #ifdef WIN32_API
00037 #  define snprintf _snprintf
00038 #endif
00039 
00040 namespace eqPixelBench
00041 {
00042 namespace
00043 {
00044 #pragma warning(disable: 411) // class defines no constructor to initialize ...
00045 struct EnumMap
00046 {
00047     const char*    internalFormatString;
00048     const uint32_t internalFormat;
00049     const size_t   pixelSize;
00050 };
00051 
00052 #pragma warning(default: 411)
00053 
00054 #define ENUM_MAP_ITEM( internalFormat, pixelSize )  \
00055     { #internalFormat, EQ_COMPRESSOR_DATATYPE_ ## internalFormat, pixelSize }
00056 
00057 static EnumMap _enums[] = {
00058     ENUM_MAP_ITEM( RGBA32F, 16 ), // initial buffer resize
00059     ENUM_MAP_ITEM( RGBA, 4 ),
00060     ENUM_MAP_ITEM( RGB10_A2, 4 ),
00061     ENUM_MAP_ITEM( RGBA16F, 8 ),
00062     ENUM_MAP_ITEM( RGBA32F, 16 ),
00063     ENUM_MAP_ITEM( DEPTH, 4 ),
00064     { 0, 0, 0 }};
00065 #define NUM_IMAGES 8
00066 }
00067 
00068 Channel::Channel( eq::Window* parent )
00069         : eq::Channel( parent )
00070 {
00071     eq::FrameData* frameData = new eq::FrameData;
00072     _frame.setData( frameData );
00073 
00074     for( unsigned i = 0; i < NUM_IMAGES; ++i )
00075         frameData->newImage( eq::Frame::TYPE_MEMORY, getDrawableConfig( ));
00076 }
00077 
00078 void Channel::frameStart( const eq::uint128_t& frameID, const uint32_t frameNumber ) 
00079 {
00080     Config* config = static_cast< Config* >( getConfig( ));
00081     const co::base::Clock* clock  = config->getClock();
00082 
00083     if( clock )
00084     {
00085         ConfigEvent   event;
00086         event.msec = clock->getTimef();
00087 
00088         const std::string& name  = getName();
00089         if( name.empty( ))    
00090             snprintf( event.data.user.data, 32, "%p", this);
00091         else
00092             snprintf( event.data.user.data, 32, "%s", name.c_str( ));
00093 
00094         event.data.user.data[31] = 0;
00095         event.area.x() = 0;
00096         event.area.y() = 0;
00097 
00098         snprintf( event.formatType, 32, "app->pipe thread latency");
00099         event.data.type = ConfigEvent::START_LATENCY;
00100 
00101         config->sendEvent( event );
00102     }
00103 
00104     eq::Channel::frameStart( frameID, frameNumber );
00105 }
00106 
00107 void Channel::frameDraw( const eq::uint128_t& frameID )
00108 {
00109     //----- setup GL state
00110     applyBuffer();
00111     applyViewport();
00112 
00113     glMatrixMode( GL_PROJECTION );
00114     glLoadIdentity();
00115 
00116     applyFrustum();
00117 
00118     glMatrixMode( GL_MODELVIEW );
00119     glLoadIdentity();
00120     applyHeadTransform();
00121 
00122     setupAssemblyState();
00123 
00124     _testFormats( 1.0f );
00125     _testFormats( 0.5f );
00126     _testFormats( 2.0f );
00127     _testTiledOperations();
00128     _testDepthAssemble();
00129 
00130     resetAssemblyState();
00131 }
00132 
00133 ConfigEvent Channel::_createConfigEvent()
00134 {
00135     ConfigEvent   event;
00136     const std::string& name = getName();
00137 
00138     if( name.empty( ))    
00139         snprintf( event.data.user.data, 32, "%p", this );
00140     else
00141         snprintf( event.data.user.data, 32, "%s", name.c_str( ));
00142 
00143     event.data.user.data[31] = 0;
00144     return event;
00145 }
00146 
00147 void Channel::_testFormats( float applyZoom )
00148 {
00149     //----- setup constant data
00150     const eq::Images& images = _frame.getImages();
00151     eq::Image*        image  = images[ 0 ];
00152     EQASSERT( image );
00153 
00154     Config* config = static_cast< Config* >( getConfig( ));
00155     const eq::PixelViewport& pvp = getPixelViewport();
00156     const eq::Vector2i offset( pvp.x, pvp.y );
00157     const eq::Zoom zoom( applyZoom, applyZoom );
00158 
00159     co::base::Clock clock;
00160     eq::Window::ObjectManager* glObjects = getObjectManager();
00161 
00162     //----- test all default format/type combinations
00163     ConfigEvent event = _createConfigEvent();
00164     glGetError();
00165     for( uint32_t i=0; _enums[i].internalFormatString; ++i )
00166     {
00167         const uint32_t internalFormat = _enums[i].internalFormat;
00168         image->flush();
00169         image->setInternalFormat( eq::Frame::BUFFER_COLOR, internalFormat );
00170         image->setQuality( eq::Frame::BUFFER_COLOR, 0.f );
00171         image->setAlphaUsage( false );
00172 
00173         const GLEWContext* glewContext = glewGetContext();
00174         std::vector< uint32_t > names;
00175         image->findTransferers( eq::Frame::BUFFER_COLOR, glewContext, names );
00176 
00177         for( std::vector< uint32_t >::const_iterator j = names.begin();
00178              j != names.end(); ++j )
00179         {
00180             _draw( 0 );
00181 
00182             // setup
00183             event.formatType[31] = '\0';
00184             event.data.type = ConfigEvent::READBACK;
00185 
00186             image->allocDownloader( eq::Frame::BUFFER_COLOR, *j, glewContext );
00187             image->setPixelViewport( pvp );
00188 
00189             const uint32_t outputToken = 
00190                 image->getExternalFormat( eq::Frame::BUFFER_COLOR );
00191             snprintf( event.formatType, 32, "%s/%x/%x", 
00192                 _enums[i].internalFormatString, outputToken, *j );
00193 
00194 
00195             // read
00196         glFinish();
00197         size_t nLoops = 0;
00198             clock.reset();
00199         while( clock.getTime64() < 100 /*ms*/ )
00200         {
00201         image->readback( eq::Frame::BUFFER_COLOR, pvp, zoom, glObjects);
00202         ++nLoops;
00203         }
00204         glFinish();
00205             event.msec = clock.getTimef() / float( nLoops );
00206 
00207             const eq::PixelData& pixels =
00208                 image->getPixelData( eq::Frame::BUFFER_COLOR );
00209             event.area.x() = pixels.pvp.w;             
00210             event.area.y() = pixels.pvp.h;
00211             event.dataSizeGPU = pixels.pvp.getArea() * _enums[i].pixelSize;
00212             event.dataSizeCPU = 
00213             image->getPixelDataSize( eq::Frame::BUFFER_COLOR );
00214 
00215             GLenum error = glGetError();
00216             if( error != GL_NO_ERROR )
00217                 event.msec = -static_cast<float>( error );
00218             config->sendEvent( event );
00219 
00220             eq::Compositor::ImageOp op;
00221             op.channel = this;
00222             op.buffers = eq::Frame::BUFFER_COLOR;
00223             op.offset = offset;
00224             op.zoom = zoom;
00225 
00226             event.data.type = ConfigEvent::ASSEMBLE;
00227             event.dataSizeCPU = 
00228                 image->getPixelDataSize( eq::Frame::BUFFER_COLOR );
00229 
00230             clock.reset();
00231             eq::Compositor::assembleImage( image, op );
00232             event.msec = clock.getTimef();
00233 
00234             const eq::PixelData& pixelA =
00235                 image->getPixelData( eq::Frame::BUFFER_COLOR );
00236             event.area.x() = pixelA.pvp.w; 
00237             event.area.y() = pixelA.pvp.h;
00238             event.dataSizeGPU =
00239                 image->getPixelDataSize( eq::Frame::BUFFER_COLOR );
00240 
00241             error = glGetError();
00242             
00243             if( error != GL_NO_ERROR )
00244                 event.msec = -static_cast<float>( error );
00245             config->sendEvent( event );
00246         }
00247     }
00248 }
00249 
00250 void Channel::_testTiledOperations()
00251 {
00252     //----- setup constant data
00253     const eq::Images& images = _frame.getImages();
00254     EQASSERT( images[0] );
00255 
00256     eq::Config* config = getConfig();
00257     const eq::PixelViewport& pvp    = getPixelViewport();
00258     const eq::Vector2i     offset( pvp.x, pvp.y );
00259 
00260     ConfigEvent event = _createConfigEvent();
00261     event.area.x() = pvp.w;
00262 
00263     co::base::Clock clock;
00264     eq::Window::ObjectManager* glObjects = getObjectManager();
00265     const GLEWContext* glewContext = glewGetContext();
00266 
00267     //----- test tiled assembly algorithms
00268     eq::PixelViewport subPVP = pvp;
00269     subPVP.h /= NUM_IMAGES;
00270 
00271     for( unsigned i = 0; i < NUM_IMAGES; ++i )
00272     {
00273         EQASSERT( images[ i ] );
00274         images[ i ]->setPixelViewport( subPVP );
00275     }
00276 
00277     for( unsigned tiles = 0; tiles < NUM_IMAGES; ++tiles )
00278     {
00279         _draw( 0 );
00280 
00281         event.area.y() = subPVP.h * (tiles+1);
00282 
00283         //---- readback of 'tiles' depth images
00284         event.data.type = ConfigEvent::READBACK;
00285         snprintf( event.formatType, 32, "%d depth tiles", tiles+1 ); 
00286 
00287         event.msec = 0;
00288         for( unsigned j = 0; j <= tiles; ++j )
00289         {
00290             subPVP.y = pvp.y + j * subPVP.h;
00291             eq::Image* image = images[ j ];
00292             EQCHECK( image->allocDownloader( eq::Frame::BUFFER_DEPTH, 
00293                              EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT,
00294                                              glewContext ));
00295             image->clearPixelData( eq::Frame::BUFFER_DEPTH );
00296 
00297             clock.reset();
00298             image->readback( eq::Frame::BUFFER_DEPTH, subPVP, eq::Zoom(),
00299                              glObjects );
00300             event.msec += clock.getTimef();
00301             
00302         }
00303 
00304         config->sendEvent( event );
00305 
00306         if( tiles == NUM_IMAGES-1 )
00307             for( unsigned j = 0; j <= tiles; ++j )
00308                 _saveImage( images[j],
00309                             "EQ_COMPRESSOR_DATATYPE_DEPTH_UNSIGNED_INT",
00310                             "tiles" );
00311 
00312         //---- readback of 'tiles' color images
00313         event.data.type = ConfigEvent::READBACK;
00314         snprintf( event.formatType, 32, "%d color tiles", tiles+1 );
00315 
00316         event.msec = 0;
00317         for( unsigned j = 0; j <= tiles; ++j )
00318         {
00319             subPVP.y = pvp.y + j * subPVP.h;
00320             eq::Image* image = images[ j ];
00321 
00322             EQCHECK( image->allocDownloader( eq::Frame::BUFFER_COLOR, 
00323                                             EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA,
00324                                               glewContext ));
00325             image->clearPixelData( eq::Frame::BUFFER_COLOR );
00326 
00327             clock.reset();
00328             image->readback( eq::Frame::BUFFER_COLOR, subPVP, eq::Zoom(),
00329                              glObjects );
00330             event.msec += clock.getTimef();
00331         }
00332         config->sendEvent( event );
00333 
00334         if( tiles == NUM_IMAGES-1 )
00335             for( unsigned j = 0; j <= tiles; ++j )
00336                 _saveImage( images[j],"EQ_COMPRESSOR_DATATYPE_BGRA","tiles" );
00337 
00338         //---- benchmark assembly operations
00339         subPVP.y = pvp.y + tiles * subPVP.h;
00340 
00341         eq::Compositor::ImageOp op;
00342         op.channel = this;
00343         op.buffers = eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH;
00344         op.offset  = offset;
00345 
00346         // fixed-function
00347         event.data.type = ConfigEvent::ASSEMBLE;
00348         snprintf( event.formatType, 32, "tiles, GL1.1, %d images", tiles+1 ); 
00349 
00350         clock.reset();
00351         for( unsigned j = 0; j <= tiles; ++j )
00352             eq::Compositor::assembleImage( images[j], op );
00353 
00354         event.msec = clock.getTimef();
00355         config->sendEvent( event );
00356 
00357         // CPU
00358         snprintf( event.formatType, 32, "tiles, CPU,   %d images", tiles+1 ); 
00359 
00360         std::vector< eq::Frame* > frames;
00361         frames.push_back( &_frame );
00362 
00363         clock.reset();
00364         eq::Compositor::assembleFramesCPU( frames, this );
00365         event.msec = clock.getTimef();
00366         config->sendEvent( event );
00367     }
00368 }
00369 
00370 void Channel::_testDepthAssemble()
00371 {
00372     //----- setup constant data
00373     const eq::Images& images = _frame.getImages();
00374     eq::Image* image  = images[ 0 ];
00375     EQASSERT( image );
00376 
00377     eq::Config* config = getConfig();
00378     const eq::PixelViewport& pvp    = getPixelViewport();
00379     const eq::Vector2i offset( pvp.x, pvp.y );
00380 
00381     ConfigEvent event = _createConfigEvent();
00382     event.area.x() = pvp.w;
00383 
00384     co::base::Clock clock;
00385     eq::Window::ObjectManager* glObjects = getObjectManager();
00386     const GLEWContext* glewContext = glewGetContext();
00387 
00388     //----- test depth-based assembly algorithms
00389     for( unsigned i = 0; i < NUM_IMAGES; ++i )
00390     {
00391         image = images[ i ];
00392         EQASSERT( image );
00393         image->setPixelViewport( pvp );
00394     }
00395 
00396     event.area.y() = pvp.h;
00397 
00398     for( unsigned i = 0; i < NUM_IMAGES; ++i )
00399     {
00400         _draw( i );
00401 
00402         // fill depth & color image
00403         image = images[ i ];
00404 
00405         EQCHECK( image->allocDownloader( eq::Frame::BUFFER_COLOR, 
00406                                          EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA, 
00407                                          glewContext ));
00408 
00409         EQCHECK( image->allocDownloader( eq::Frame::BUFFER_DEPTH, 
00410                              EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT,
00411                                          glewContext ));
00412 
00413         image->clearPixelData( eq::Frame::BUFFER_COLOR );
00414         image->clearPixelData( eq::Frame::BUFFER_DEPTH );
00415 
00416         image->readback( eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH,
00417                          pvp, eq::Zoom(), glObjects );
00418 
00419         if( i == NUM_IMAGES-1 )
00420             _saveImage( image,"EQ_COMPRESSOR_DATATYPE_DEPTH_UNSIGNED_INT",
00421                               "depthAssemble" );
00422 
00423         // benchmark
00424         eq::Compositor::ImageOp op;
00425         op.channel = this;
00426         op.buffers = eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH;
00427         op.offset  = offset;
00428 
00429         // fixed-function
00430         event.data.type = ConfigEvent::ASSEMBLE;
00431         snprintf( event.formatType, 32, "depth, GL1.1, %d images", i+1 ); 
00432 
00433         clock.reset();
00434         for( unsigned j = 0; j <= i; ++j )
00435             eq::Compositor::assembleImageDB_FF( images[j], op );
00436 
00437         event.msec = clock.getTimef();
00438         config->sendEvent( event );
00439 
00440         // GLSL
00441         if( GLEW_VERSION_2_0 )
00442         {
00443             snprintf( event.formatType, 32, "depth, GLSL,  %d images", i+1 ); 
00444 
00445             clock.reset();
00446             for( unsigned j = 0; j <= i; ++j )
00447                 eq::Compositor::assembleImageDB_GLSL( images[j], op );
00448             event.msec = clock.getTimef();
00449             config->sendEvent( event );
00450         }
00451 
00452         // CPU
00453         snprintf( event.formatType, 32, "depth, CPU,   %d images", i+1 ); 
00454 
00455         std::vector< eq::Frame* > frames;
00456         frames.push_back( &_frame );
00457 
00458         clock.reset();
00459         eq::Compositor::assembleFramesCPU( frames, this );
00460         event.msec = clock.getTimef();
00461         config->sendEvent( event );
00462     }
00463 }
00464 
00465 void Channel::_saveImage( const eq::Image* image,
00466                           const char*      externalformat,
00467                           const char*      info    )
00468 {
00469     return;
00470 
00471     static uint32_t counter = 0;
00472     std::ostringstream stringstream;
00473     stringstream << "Image_" << ++counter << "_" << externalformat << "_"
00474                  << info;
00475     image->writeImages( stringstream.str( ));
00476 }
00477 
00478 void Channel::_draw( const eq::uint128_t& spin )
00479 {
00480     glPushAttrib( GL_ALL_ATTRIB_BITS );
00481 
00482     eq::Channel::frameDraw( spin );
00483 
00484     glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
00485     glEnable( GL_DEPTH_TEST );
00486 
00487 #if 0
00488     setNearFar( 0.5f, 5.0f );
00489     const GLfloat lightPosition[]    = {5.0f, 0.0f, 5.0f, 0.0f};
00490     const GLfloat lightDiffuse[]     = {0.8f, 0.8f, 0.8f, 1.0f};
00491 
00492     const GLfloat materialDiffuse[]  = {0.8f, 0.8f, 0.8f, 1.0f};
00493 
00494     glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
00495     glLightfv( GL_LIGHT0, GL_DIFFUSE,  lightDiffuse  );
00496 
00497     glMaterialfv( GL_FRONT, GL_DIFFUSE,   materialDiffuse );
00498 
00499     eq::Matrix4f rotation;
00500     eq::Vector3f translation;
00501 
00502     translation   = eq::Vector3f::ZERO;
00503     translation.z = -2.f;
00504     rotation = eq::Matrix4f::IDENTITY;
00505     rotation.rotate_x( static_cast<float>( -M_PI_2 ));
00506     rotation.rotate_y( static_cast<float>( -M_PI_2 ));
00507 
00508     glTranslatef( translation.x, translation.y, translation.z );
00509     glMultMatrixf( rotation.ml );
00510 
00511     glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
00512     glColor3f( 1.f, 1.f, 0.f );
00513     glNormal3f( 1.f, -1.f, 0.f );
00514     glBegin( GL_TRIANGLE_STRIP );
00515         glVertex3f(  1.f, 10.f,  2.5f );
00516         glVertex3f( -1.f, 10.f,  2.5f );
00517         glVertex3f(  1.f,-10.f, -2.5f );
00518         glVertex3f( -1.f,-10.f, -2.5f );
00519     glEnd();
00520 
00521 #else
00522 
00523     const float lightPos[] = { 0.0f, 0.0f, 1.0f, 0.0f };
00524     glLightfv( GL_LIGHT0, GL_POSITION, lightPos );
00525 
00526     const float lightAmbient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
00527     glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient );
00528 
00529     // rotate scene around the origin
00530     glRotatef( static_cast< float >( spin.low() + 3 ) * 10, 1.0f, 0.5f, 0.25f );
00531 
00532     // render six axis-aligned colored quads around the origin
00533     //  front
00534     glColor3f( 1.0f, 0.5f, 0.5f );
00535     glNormal3f( 0.0f, 0.0f, 1.0f );
00536     glBegin( GL_TRIANGLE_STRIP );
00537     glVertex3f(  .7f,  .7f, -1.0f );
00538     glVertex3f( -.7f,  .7f, -1.0f );
00539     glVertex3f(  .7f, -.7f, -1.0f );
00540     glVertex3f( -.7f, -.7f, -1.0f );
00541     glEnd();
00542 
00543     //  bottom
00544     glColor3f( 0.5f, 1.0f, 0.5f );
00545     glNormal3f( 0.0f, 1.0f, 0.0f );
00546     glBegin( GL_TRIANGLE_STRIP );
00547     glVertex3f(  .7f, -1.0f,  .7f );
00548     glVertex3f( -.7f, -1.0f,  .7f );
00549     glVertex3f(  .7f, -1.0f, -.7f );
00550     glVertex3f( -.7f, -1.0f, -.7f );
00551     glEnd();
00552 
00553     //  back
00554     glColor3f( 0.5f, 0.5f, 1.0f );
00555     glNormal3f( 0.0f, 0.0f, -1.0f );
00556     glBegin( GL_TRIANGLE_STRIP );
00557     glVertex3f(  .7f,  .7f, 1.0f );
00558     glVertex3f( -.7f,  .7f, 1.0f );
00559     glVertex3f(  .7f, -.7f, 1.0f );
00560     glVertex3f( -.7f, -.7f, 1.0f );
00561     glEnd();
00562 
00563     //  top
00564     glColor3f( 1.0f, 1.0f, 0.5f );
00565     glNormal3f( 0.f, -1.f, 0.f );
00566     glBegin( GL_TRIANGLE_STRIP );
00567     glVertex3f(  .7f, 1.0f,  .7f );
00568     glVertex3f( -.7f, 1.0f,  .7f );
00569     glVertex3f(  .7f, 1.0f, -.7f );
00570     glVertex3f( -.7f, 1.0f, -.7f );
00571     glEnd();
00572 
00573     //  right
00574     glColor3f( 1.0f, 0.5f, 1.0f );
00575     glNormal3f( -1.f, 0.f, 0.f );
00576     glBegin( GL_TRIANGLE_STRIP );
00577     glVertex3f( 1.0f,  .7f,  .7f );
00578     glVertex3f( 1.0f, -.7f,  .7f );
00579     glVertex3f( 1.0f,  .7f, -.7f );
00580     glVertex3f( 1.0f, -.7f, -.7f );
00581     glEnd();
00582 
00583     //  left
00584     glColor3f( 0.5f, 1.0f, 1.0f );
00585     glNormal3f( 1.f, 0.f, 0.f );
00586     glBegin( GL_TRIANGLE_STRIP );
00587     glVertex3f( -1.0f,  .7f,  .7f );
00588     glVertex3f( -1.0f, -.7f,  .7f );
00589     glVertex3f( -1.0f,  .7f, -.7f );
00590     glVertex3f( -1.0f, -.7f, -.7f );
00591     glEnd();
00592 
00593 #endif
00594 
00595     glPopAttrib( );
00596 }
00597 
00598 
00599 }
Generated on Fri Jun 8 2012 15:44:29 for Equalizer 1.2.1 by  doxygen 1.8.0