00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "channel.h"
00019
00020 #include "config.h"
00021 #include "configEvent.h"
00022
00023 using namespace std;
00024 using namespace eq::base;
00025
00026 #ifdef WIN32_API
00027 # define snprintf _snprintf
00028 #endif
00029
00030 namespace eqPixelBench
00031 {
00032 namespace
00033 {
00034 #pragma warning(disable: 411) // class defines no constructor to initialize ...
00035 struct EnumMap
00036 {
00037 const char* formatString;
00038 const char* typeString;
00039 const uint32_t format;
00040 const uint32_t type;
00041 };
00042 #pragma warning(default: 411)
00043
00044 #define ENUM_MAP_ITEM( format, type ) \
00045 { #format, #type, format, type }
00046
00047 static EnumMap _enums[] = {
00048 ENUM_MAP_ITEM( GL_RGBA, GL_UNSIGNED_BYTE ),
00049 ENUM_MAP_ITEM( GL_RGBA, GL_UNSIGNED_BYTE ),
00050 ENUM_MAP_ITEM( GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV ),
00051 ENUM_MAP_ITEM( GL_RGBA, GL_HALF_FLOAT ),
00052 ENUM_MAP_ITEM( GL_RGBA, GL_FLOAT ),
00053 ENUM_MAP_ITEM( GL_BGRA, GL_UNSIGNED_BYTE ),
00054 ENUM_MAP_ITEM( GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV ),
00055 ENUM_MAP_ITEM( GL_BGRA, GL_HALF_FLOAT ),
00056 ENUM_MAP_ITEM( GL_BGRA, GL_FLOAT ),
00057 ENUM_MAP_ITEM( GL_RGB, GL_UNSIGNED_BYTE ),
00058 ENUM_MAP_ITEM( GL_RGB, GL_UNSIGNED_INT_8_8_8_8_REV),
00059 ENUM_MAP_ITEM( GL_RGB, GL_HALF_FLOAT ),
00060 ENUM_MAP_ITEM( GL_RGB, GL_FLOAT ),
00061 ENUM_MAP_ITEM( GL_BGR, GL_UNSIGNED_BYTE ),
00062 ENUM_MAP_ITEM( GL_BGR, GL_UNSIGNED_INT_8_8_8_8_REV ),
00063 ENUM_MAP_ITEM( GL_BGR, GL_HALF_FLOAT ),
00064 ENUM_MAP_ITEM( GL_BGR, GL_FLOAT ),
00065 ENUM_MAP_ITEM( GL_DEPTH_COMPONENT, GL_FLOAT ),
00066 ENUM_MAP_ITEM( GL_DEPTH_COMPONENT, GL_UNSIGNED_INT ),
00067 ENUM_MAP_ITEM( GL_DEPTH_STENCIL_NV, GL_UNSIGNED_INT_24_8_NV ),
00068 { 0, 0, false, false }};
00069
00070 #define NUM_IMAGES 8
00071 }
00072
00073 Channel::Channel( eq::Window* parent )
00074 : eq::Channel( parent )
00075 {
00076 eq::FrameData* frameData = new eq::FrameData;
00077 _frame.setData( frameData );
00078
00079 for( unsigned i = 0; i < NUM_IMAGES; ++i )
00080 frameData->newImage();
00081 }
00082
00083 void Channel::frameStart( const uint32_t frameID, const uint32_t frameNumber )
00084 {
00085 Config* config = static_cast< Config* >( getConfig( ));
00086 const Clock* clock = config->getClock();
00087
00088 if( clock )
00089 {
00090 ConfigEvent event;
00091 event.msec = clock->getTimef();
00092
00093 const string& name = getName();
00094 if( name.empty( ))
00095 snprintf( event.data.user.data, 32, "%p", this);
00096 else
00097 snprintf( event.data.user.data, 32, "%s", name.c_str( ));
00098 event.data.user.data[31] = '\0';
00099 event.area.x() = 0;
00100 event.area.y() = 0;
00101
00102 snprintf( event.formatType, 64, "Latency between app and render start");
00103 event.data.type = ConfigEvent::START_LATENCY;
00104
00105 config->sendEvent( event );
00106 }
00107
00108 eq::Channel::frameStart( frameID, frameNumber );
00109 }
00110
00111 void Channel::frameDraw( const uint32_t frameID )
00112 {
00113
00114 applyBuffer();
00115 applyViewport();
00116
00117 glMatrixMode( GL_PROJECTION );
00118 glLoadIdentity();
00119
00120 applyFrustum();
00121
00122 glMatrixMode( GL_MODELVIEW );
00123 glLoadIdentity();
00124 applyHeadTransform();
00125
00126 setupAssemblyState();
00127
00128 _testFormats();
00129 _testTiledOperations();
00130 _testDepthAssemble();
00131
00132 resetAssemblyState();
00133 }
00134
00135 ConfigEvent Channel::_createConfigEvent()
00136 {
00137 ConfigEvent event;
00138 const string& name = getName();
00139
00140 if( name.empty( ))
00141 snprintf( event.data.user.data, 32, "%p", this );
00142 else
00143 snprintf( event.data.user.data, 32, "%s", name.c_str( ));
00144
00145 event.data.user.data[31] = '\0';
00146 return event;
00147 }
00148
00149 void Channel::_testFormats()
00150 {
00151
00152 const eq::ImageVector& images = _frame.getImages();
00153 eq::Image* image = images[ 0 ];
00154 EQASSERT( image );
00155
00156 eq::Config* config = getConfig();
00157 const eq::PixelViewport& pvp = getPixelViewport();
00158 const eq::Vector2i offset( pvp.x, pvp.y );
00159
00160 ConfigEvent event = _createConfigEvent();
00161 event.area.x() = pvp.w;
00162
00163 Clock clock;
00164 eq::Window::ObjectManager* glObjects = getObjectManager();
00165
00166
00167 glGetError();
00168 for( uint32_t i=0; _enums[i].formatString; ++i )
00169 {
00170 _draw( 0 );
00171
00172
00173 snprintf( event.formatType, 64, "%s/%s",
00174 _enums[i].formatString, _enums[i].typeString );
00175 event.formatType[63] = '\0';
00176 event.data.type = ConfigEvent::READBACK;
00177 event.area.y() = pvp.h;
00178
00179 image->setFormat( eq::Frame::BUFFER_COLOR, _enums[i].format );
00180 image->setType( eq::Frame::BUFFER_COLOR, _enums[i].type );
00181 image->clearPixelData( eq::Frame::BUFFER_COLOR );
00182 image->disablePBO();
00183
00184
00185 clock.reset();
00186 image->startReadback( eq::Frame::BUFFER_COLOR, pvp, eq::Zoom(),
00187 glObjects );
00188 image->syncReadback();
00189 event.msec = clock.getTimef();
00190
00191 GLenum error = glGetError();
00192 if( error != GL_NO_ERROR )
00193 event.msec = - static_cast<float>( error );
00194 config->sendEvent( event );
00195
00196 _saveImage( image, _enums[i].typeString, _enums[i].formatString,
00197 "formats" );
00198
00199 if( error != GL_NO_ERROR )
00200 continue;
00201
00202
00203 event.data.type = ConfigEvent::READBACK_PBO;
00204 image->clearPixelData( eq::Frame::BUFFER_COLOR );
00205 image->enablePBO();
00206
00207 clock.reset();
00208 image->startReadback( eq::Frame::BUFFER_COLOR, pvp, eq::Zoom(),
00209 glObjects );
00210 image->syncReadback();
00211 event.msec = clock.getTimef();
00212
00213 error = glGetError();
00214 if( error != GL_NO_ERROR )
00215 event.msec = - static_cast<float>( error );
00216 config->sendEvent( event );
00217
00218 _saveImage( image, _enums[i].typeString, _enums[i].formatString,
00219 "formats_PBO" );
00220
00221
00222 event.data.type = ConfigEvent::ASSEMBLE;
00223 eq::Compositor::ImageOp op;
00224 op.channel = this;
00225 op.buffers = eq::Frame::BUFFER_COLOR;
00226 op.offset = offset;
00227
00228 clock.reset();
00229 eq::Compositor::assembleImage( image, op );
00230 event.msec = clock.getTimef();
00231
00232 error = glGetError();
00233 if( error != GL_NO_ERROR )
00234 event.msec = - static_cast<float>( error );
00235
00236 config->sendEvent( event );
00237 }
00238 }
00239
00240 void Channel::_testTiledOperations()
00241 {
00242
00243 const eq::ImageVector& images = _frame.getImages();
00244 EQASSERT( images[0] );
00245
00246 eq::Config* config = getConfig();
00247 const eq::PixelViewport& pvp = getPixelViewport();
00248 const eq::Vector2i offset( pvp.x, pvp.y );
00249
00250 ConfigEvent event = _createConfigEvent();
00251 event.area.x() = pvp.w;
00252
00253 Clock clock;
00254 eq::Window::ObjectManager* glObjects = getObjectManager();
00255
00256
00257 eq::PixelViewport subPVP = pvp;
00258 subPVP.h /= NUM_IMAGES;
00259
00260 for( unsigned i = 0; i < NUM_IMAGES; ++i )
00261 {
00262 EQASSERT( images[ i ] );
00263 images[ i ]->setPixelViewport( subPVP );
00264 }
00265
00266 for( unsigned tiles = 0; tiles < NUM_IMAGES; ++tiles )
00267 {
00268 _draw( 0 );
00269
00270 event.area.y() = subPVP.h * (tiles+1);
00271
00272
00273 event.data.type = ConfigEvent::READBACK;
00274 snprintf( event.formatType, 64, "%d depth tiles", tiles+1 );
00275
00276 event.msec = 0;
00277 for( unsigned j = 0; j <= tiles; ++j )
00278 {
00279 subPVP.y = pvp.y + j * subPVP.h;
00280 eq::Image* image = images[ j ];
00281 image->disablePBO();
00282 image->setFormat( eq::Frame::BUFFER_COLOR, GL_DEPTH_COMPONENT );
00283 image->setType( eq::Frame::BUFFER_COLOR, GL_UNSIGNED_INT );
00284 image->clearPixelData( eq::Frame::BUFFER_COLOR );
00285
00286 clock.reset();
00287 image->startReadback( eq::Frame::BUFFER_COLOR, subPVP, eq::Zoom(),
00288 glObjects );
00289 image->syncReadback();
00290 event.msec += clock.getTimef();
00291 }
00292
00293 config->sendEvent( event );
00294
00295 if( tiles == NUM_IMAGES-1 )
00296 for( unsigned j = 0; j <= tiles; ++j )
00297 _saveImage( images[j],
00298 "GL_DEPTH_COMPONENT","GL_UNSIGNED_INT","tiles" );
00299
00300
00301 event.data.type = ConfigEvent::READBACK_PBO;
00302
00303 for( unsigned j = 0; j <= tiles; ++j )
00304 {
00305 eq::Image* image = images[ j ];
00306 image->enablePBO();
00307 image->setFormat( eq::Frame::BUFFER_COLOR, GL_DEPTH_COMPONENT );
00308 image->setType( eq::Frame::BUFFER_COLOR, GL_UNSIGNED_INT );
00309 image->clearPixelData( eq::Frame::BUFFER_COLOR );
00310 }
00311 clock.reset();
00312 for( unsigned j = 0; j <= tiles; ++j )
00313 {
00314 subPVP.y = pvp.y + j * subPVP.h;
00315 images[ j ]->startReadback( eq::Frame::BUFFER_COLOR, subPVP,
00316 eq::Zoom(), glObjects );
00317 }
00318
00319 for( unsigned j = 0; j <= tiles; ++j )
00320 images[ j ]->syncReadback();
00321
00322 event.msec = clock.getTimef();
00323 config->sendEvent( event );
00324
00325 if( tiles == NUM_IMAGES-1 )
00326 for( unsigned j = 0; j <= tiles; ++j )
00327 _saveImage(images[j],
00328 "GL_DEPTH_COMPONENT","GL_UNSIGNED_INT","tiles_PBO");
00329
00330
00331
00332 event.data.type = ConfigEvent::READBACK;
00333 snprintf( event.formatType, 64, "%d color tiles", tiles+1 );
00334
00335 event.msec = 0;
00336 for( unsigned j = 0; j <= tiles; ++j )
00337 {
00338 subPVP.y = pvp.y + j * subPVP.h;
00339 eq::Image* image = images[ j ];
00340 image->disablePBO();
00341 image->setFormat( eq::Frame::BUFFER_COLOR, GL_BGRA );
00342 image->setType( eq::Frame::BUFFER_COLOR, GL_UNSIGNED_BYTE );
00343 image->clearPixelData( eq::Frame::BUFFER_COLOR );
00344
00345 clock.reset();
00346 image->startReadback( eq::Frame::BUFFER_COLOR, subPVP, eq::Zoom(),
00347 glObjects );
00348 image->syncReadback();
00349 event.msec += clock.getTimef();
00350 }
00351
00352 config->sendEvent( event );
00353
00354 if( tiles == NUM_IMAGES-1 )
00355 for( unsigned j = 0; j <= tiles; ++j )
00356 _saveImage( images[j],"GL_BGRA","GL_UNSIGNED_BYTE","tiles" );
00357
00358
00359 event.data.type = ConfigEvent::READBACK_PBO;
00360
00361 for( unsigned j = 0; j <= tiles; ++j )
00362 {
00363 eq::Image* image = images[ j ];
00364 image->enablePBO();
00365 image->setFormat( eq::Frame::BUFFER_COLOR, GL_BGRA );
00366 image->setType( eq::Frame::BUFFER_COLOR, GL_UNSIGNED_BYTE );
00367 image->clearPixelData( eq::Frame::BUFFER_COLOR );
00368 }
00369 clock.reset();
00370 for( unsigned j = 0; j <= tiles; ++j )
00371 {
00372 subPVP.y = pvp.y + j * subPVP.h;
00373 images[ j ]->startReadback( eq::Frame::BUFFER_COLOR, subPVP,
00374 eq::Zoom(), glObjects );
00375 }
00376
00377 for( unsigned j = 0; j <= tiles; ++j )
00378 images[ j ]->syncReadback();
00379
00380 event.msec = clock.getTimef();
00381 config->sendEvent( event );
00382
00383 if( tiles == NUM_IMAGES-1 )
00384 for( unsigned j = 0; j <= tiles; ++j )
00385 _saveImage(images[j],"GL_BGRA","GL_UNSIGNED_BYTE","tiles_PBO" );
00386
00387
00388
00389 subPVP.y = pvp.y + tiles * subPVP.h;
00390
00391 eq::Compositor::ImageOp op;
00392 op.channel = this;
00393 op.buffers = eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH;
00394 op.offset = offset;
00395
00396
00397 event.data.type = ConfigEvent::ASSEMBLE;
00398 snprintf( event.formatType, 64,
00399 "Tiled assembly (GL1.1) of %d images", tiles+1 );
00400
00401 clock.reset();
00402 for( unsigned j = 0; j <= tiles; ++j )
00403 eq::Compositor::assembleImage( images[j], op );
00404
00405 event.msec = clock.getTimef();
00406 config->sendEvent( event );
00407
00408
00409 snprintf( event.formatType, 64,
00410 "Tiled assembly (CPU) of %d images", tiles+1 );
00411
00412 std::vector< eq::Frame* > frames;
00413 frames.push_back( &_frame );
00414
00415 clock.reset();
00416 eq::Compositor::assembleFramesCPU( frames, this );
00417 event.msec = clock.getTimef();
00418 config->sendEvent( event );
00419 }
00420 }
00421
00422 void Channel::_testDepthAssemble()
00423 {
00424
00425 const eq::ImageVector& images = _frame.getImages();
00426 eq::Image* image = images[ 0 ];
00427 EQASSERT( image );
00428
00429 eq::Config* config = getConfig();
00430 const eq::PixelViewport& pvp = getPixelViewport();
00431 const eq::Vector2i offset( pvp.x, pvp.y );
00432
00433 ConfigEvent event = _createConfigEvent();
00434 event.area.x() = pvp.w;
00435
00436 Clock clock;
00437 eq::Window::ObjectManager* glObjects = getObjectManager();
00438
00439
00440
00441 for( unsigned i = 0; i < NUM_IMAGES; ++i )
00442 {
00443 image = images[ i ];
00444 EQASSERT( image );
00445 image->setPixelViewport( pvp );
00446 }
00447
00448 event.area.y() = pvp.h;
00449
00450 for( unsigned i = 0; i < NUM_IMAGES; ++i )
00451 {
00452 _draw( i );
00453
00454
00455 image = images[ i ];
00456 image->setFormat( eq::Frame::BUFFER_COLOR, GL_BGRA );
00457 image->setType( eq::Frame::BUFFER_COLOR, GL_UNSIGNED_BYTE );
00458 image->setFormat( eq::Frame::BUFFER_DEPTH, GL_DEPTH_COMPONENT );
00459 image->setType( eq::Frame::BUFFER_DEPTH, GL_UNSIGNED_INT );
00460 image->clearPixelData( eq::Frame::BUFFER_COLOR );
00461 image->clearPixelData( eq::Frame::BUFFER_DEPTH );
00462
00463 image->startReadback( eq::Frame::BUFFER_COLOR |
00464 eq::Frame::BUFFER_DEPTH, pvp, eq::Zoom(),
00465 glObjects );
00466 image->syncReadback();
00467
00468 if( i == NUM_IMAGES-1 )
00469 _saveImage( image,"GL_BGRA","GL_UNSIGNED_BYTE","depthAssemble" );
00470
00471
00472 eq::Compositor::ImageOp op;
00473 op.channel = this;
00474 op.buffers = eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH;
00475 op.offset = offset;
00476
00477
00478 event.data.type = ConfigEvent::ASSEMBLE;
00479 snprintf( event.formatType, 64,
00480 "Depth-based assembly (GL1.1) of %d images", i+1 );
00481
00482 clock.reset();
00483 for( unsigned j = 0; j <= i; ++j )
00484 eq::Compositor::assembleImageDB_FF( images[j], op );
00485
00486 event.msec = clock.getTimef();
00487 config->sendEvent( event );
00488
00489
00490 if( GLEW_VERSION_2_0 )
00491 {
00492 snprintf( event.formatType, 64,
00493 "Depth-based assembly (GLSL) of %d images", i+1 );
00494
00495 clock.reset();
00496 for( unsigned j = 0; j <= i; ++j )
00497 eq::Compositor::assembleImageDB_GLSL( images[j], op );
00498 event.msec = clock.getTimef();
00499 config->sendEvent( event );
00500 }
00501
00502
00503 snprintf( event.formatType, 64,
00504 "Depth-based assembly (CPU) of %d images", i+1 );
00505
00506 std::vector< eq::Frame* > frames;
00507 frames.push_back( &_frame );
00508
00509 clock.reset();
00510 eq::Compositor::assembleFramesCPU( frames, this );
00511 event.msec = clock.getTimef();
00512 config->sendEvent( event );
00513 }
00514 }
00515
00516 void Channel::_saveImage( const eq::Image* image,
00517 const char* type,
00518 const char* format,
00519 const char* info )
00520 {
00521 return;
00522
00523 static uint32_t counter = 0;
00524 ostringstream stringstream;
00525 stringstream << "Image_" << ++counter << "_"
00526 << type << "_" << format << "_" << info;
00527 image->writeImages( stringstream.str( ));
00528 }
00529
00530
00531 void Channel::_draw( const uint32_t spin )
00532 {
00533 glPushAttrib( GL_ALL_ATTRIB_BITS );
00534
00535 eq::Channel::frameDraw( spin );
00536
00537 glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
00538 glEnable( GL_DEPTH_TEST );
00539
00540 #ifdef _0
00541 setNearFar( 0.5f, 5.0f );
00542 const GLfloat lightPosition[] = {5.0f, 0.0f, 5.0f, 0.0f};
00543 const GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
00544
00545 const GLfloat materialDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
00546
00547 glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
00548 glLightfv( GL_LIGHT0, GL_DIFFUSE, lightDiffuse );
00549
00550 glMaterialfv( GL_FRONT, GL_DIFFUSE, materialDiffuse );
00551
00552 eq::Matrix4f rotation;
00553 eq::Vector3f translation;
00554
00555 translation = eq::Vector3f::ZERO;
00556 translation.z = -2.f;
00557 rotation = eq::Matrix4f::IDENTITY;
00558 rotation.rotate_x( static_cast<float>( -M_PI_2 ));
00559 rotation.rotate_y( static_cast<float>( -M_PI_2 ));
00560
00561 glTranslatef( translation.x, translation.y, translation.z );
00562 glMultMatrixf( rotation.ml );
00563
00564 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
00565 glColor3f( 1.f, 1.f, 0.f );
00566 glNormal3f( 1.f, -1.f, 0.f );
00567 glBegin( GL_TRIANGLE_STRIP );
00568 glVertex3f( 1.f, 10.f, 2.5f );
00569 glVertex3f( -1.f, 10.f, 2.5f );
00570 glVertex3f( 1.f,-10.f, -2.5f );
00571 glVertex3f( -1.f,-10.f, -2.5f );
00572 glEnd();
00573
00574 #else
00575
00576 const float lightPos[] = { 0.0f, 0.0f, 1.0f, 0.0f };
00577 glLightfv( GL_LIGHT0, GL_POSITION, lightPos );
00578
00579 const float lightAmbient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
00580 glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient );
00581
00582
00583 glRotatef( static_cast< float >( spin + 3 ) * 10, 1.0f, 0.5f, 0.25f );
00584
00585
00586
00587 glColor3f( 1.0f, 0.5f, 0.5f );
00588 glNormal3f( 0.0f, 0.0f, 1.0f );
00589 glBegin( GL_TRIANGLE_STRIP );
00590 glVertex3f( .7f, .7f, -1.0f );
00591 glVertex3f( -.7f, .7f, -1.0f );
00592 glVertex3f( .7f, -.7f, -1.0f );
00593 glVertex3f( -.7f, -.7f, -1.0f );
00594 glEnd();
00595
00596
00597 glColor3f( 0.5f, 1.0f, 0.5f );
00598 glNormal3f( 0.0f, 1.0f, 0.0f );
00599 glBegin( GL_TRIANGLE_STRIP );
00600 glVertex3f( .7f, -1.0f, .7f );
00601 glVertex3f( -.7f, -1.0f, .7f );
00602 glVertex3f( .7f, -1.0f, -.7f );
00603 glVertex3f( -.7f, -1.0f, -.7f );
00604 glEnd();
00605
00606
00607 glColor3f( 0.5f, 0.5f, 1.0f );
00608 glNormal3f( 0.0f, 0.0f, -1.0f );
00609 glBegin( GL_TRIANGLE_STRIP );
00610 glVertex3f( .7f, .7f, 1.0f );
00611 glVertex3f( -.7f, .7f, 1.0f );
00612 glVertex3f( .7f, -.7f, 1.0f );
00613 glVertex3f( -.7f, -.7f, 1.0f );
00614 glEnd();
00615
00616
00617 glColor3f( 1.0f, 1.0f, 0.5f );
00618 glNormal3f( 0.f, -1.f, 0.f );
00619 glBegin( GL_TRIANGLE_STRIP );
00620 glVertex3f( .7f, 1.0f, .7f );
00621 glVertex3f( -.7f, 1.0f, .7f );
00622 glVertex3f( .7f, 1.0f, -.7f );
00623 glVertex3f( -.7f, 1.0f, -.7f );
00624 glEnd();
00625
00626
00627 glColor3f( 1.0f, 0.5f, 1.0f );
00628 glNormal3f( -1.f, 0.f, 0.f );
00629 glBegin( GL_TRIANGLE_STRIP );
00630 glVertex3f( 1.0f, .7f, .7f );
00631 glVertex3f( 1.0f, -.7f, .7f );
00632 glVertex3f( 1.0f, .7f, -.7f );
00633 glVertex3f( 1.0f, -.7f, -.7f );
00634 glEnd();
00635
00636
00637 glColor3f( 0.5f, 1.0f, 1.0f );
00638 glNormal3f( 1.f, 0.f, 0.f );
00639 glBegin( GL_TRIANGLE_STRIP );
00640 glVertex3f( -1.0f, .7f, .7f );
00641 glVertex3f( -1.0f, -.7f, .7f );
00642 glVertex3f( -1.0f, .7f, -.7f );
00643 glVertex3f( -1.0f, -.7f, -.7f );
00644 glEnd();
00645
00646 #endif
00647
00648 glPopAttrib( );
00649 }
00650
00651
00652 }