Equalizer 1.0
|
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 clock.reset(); 00197 image->readback( eq::Frame::BUFFER_COLOR, pvp, zoom, glObjects ); 00198 event.msec = clock.getTimef(); 00199 00200 const eq::PixelData& pixels = 00201 image->getPixelData( eq::Frame::BUFFER_COLOR ); 00202 event.area.x() = pixels.pvp.w; 00203 event.area.y() = pixels.pvp.h; 00204 event.dataSizeGPU = pixels.pvp.getArea() * _enums[i].pixelSize; 00205 event.dataSizeCPU = 00206 image->getPixelDataSize( eq::Frame::BUFFER_COLOR ); 00207 00208 GLenum error = glGetError(); 00209 if( error != GL_NO_ERROR ) 00210 event.msec = -static_cast<float>( error ); 00211 config->sendEvent( event ); 00212 00213 eq::Compositor::ImageOp op; 00214 op.channel = this; 00215 op.buffers = eq::Frame::BUFFER_COLOR; 00216 op.offset = offset; 00217 op.zoom = zoom; 00218 00219 event.data.type = ConfigEvent::ASSEMBLE; 00220 event.dataSizeCPU = 00221 image->getPixelDataSize( eq::Frame::BUFFER_COLOR ); 00222 00223 clock.reset(); 00224 eq::Compositor::assembleImage( image, op ); 00225 event.msec = clock.getTimef(); 00226 00227 const eq::PixelData& pixelA = 00228 image->getPixelData( eq::Frame::BUFFER_COLOR ); 00229 event.area.x() = pixelA.pvp.w; 00230 event.area.y() = pixelA.pvp.h; 00231 event.dataSizeGPU = 00232 image->getPixelDataSize( eq::Frame::BUFFER_COLOR ); 00233 00234 error = glGetError(); 00235 00236 if( error != GL_NO_ERROR ) 00237 event.msec = -static_cast<float>( error ); 00238 config->sendEvent( event ); 00239 } 00240 } 00241 } 00242 00243 void Channel::_testTiledOperations() 00244 { 00245 //----- setup constant data 00246 const eq::Images& images = _frame.getImages(); 00247 EQASSERT( images[0] ); 00248 00249 eq::Config* config = getConfig(); 00250 const eq::PixelViewport& pvp = getPixelViewport(); 00251 const eq::Vector2i offset( pvp.x, pvp.y ); 00252 00253 ConfigEvent event = _createConfigEvent(); 00254 event.area.x() = pvp.w; 00255 00256 co::base::Clock clock; 00257 eq::Window::ObjectManager* glObjects = getObjectManager(); 00258 const GLEWContext* glewContext = glewGetContext(); 00259 00260 //----- test tiled assembly algorithms 00261 eq::PixelViewport subPVP = pvp; 00262 subPVP.h /= NUM_IMAGES; 00263 00264 for( unsigned i = 0; i < NUM_IMAGES; ++i ) 00265 { 00266 EQASSERT( images[ i ] ); 00267 images[ i ]->setPixelViewport( subPVP ); 00268 } 00269 00270 for( unsigned tiles = 0; tiles < NUM_IMAGES; ++tiles ) 00271 { 00272 _draw( 0 ); 00273 00274 event.area.y() = subPVP.h * (tiles+1); 00275 00276 //---- readback of 'tiles' depth images 00277 event.data.type = ConfigEvent::READBACK; 00278 snprintf( event.formatType, 32, "%d depth tiles", tiles+1 ); 00279 00280 event.msec = 0; 00281 for( unsigned j = 0; j <= tiles; ++j ) 00282 { 00283 subPVP.y = pvp.y + j * subPVP.h; 00284 eq::Image* image = images[ j ]; 00285 EQCHECK( image->allocDownloader( eq::Frame::BUFFER_DEPTH, 00286 EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT, 00287 glewContext )); 00288 image->clearPixelData( eq::Frame::BUFFER_DEPTH ); 00289 00290 clock.reset(); 00291 image->readback( eq::Frame::BUFFER_DEPTH, subPVP, eq::Zoom(), 00292 glObjects ); 00293 event.msec += clock.getTimef(); 00294 00295 } 00296 00297 config->sendEvent( event ); 00298 00299 if( tiles == NUM_IMAGES-1 ) 00300 for( unsigned j = 0; j <= tiles; ++j ) 00301 _saveImage( images[j], 00302 "EQ_COMPRESSOR_DATATYPE_DEPTH_UNSIGNED_INT", 00303 "tiles" ); 00304 00305 //---- readback of 'tiles' color images 00306 event.data.type = ConfigEvent::READBACK; 00307 snprintf( event.formatType, 32, "%d color tiles", tiles+1 ); 00308 00309 event.msec = 0; 00310 for( unsigned j = 0; j <= tiles; ++j ) 00311 { 00312 subPVP.y = pvp.y + j * subPVP.h; 00313 eq::Image* image = images[ j ]; 00314 00315 EQCHECK( image->allocDownloader( eq::Frame::BUFFER_COLOR, 00316 EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA, 00317 glewContext )); 00318 image->clearPixelData( eq::Frame::BUFFER_COLOR ); 00319 00320 clock.reset(); 00321 image->readback( eq::Frame::BUFFER_COLOR, subPVP, eq::Zoom(), 00322 glObjects ); 00323 event.msec += clock.getTimef(); 00324 } 00325 config->sendEvent( event ); 00326 00327 if( tiles == NUM_IMAGES-1 ) 00328 for( unsigned j = 0; j <= tiles; ++j ) 00329 _saveImage( images[j],"EQ_COMPRESSOR_DATATYPE_BGRA","tiles" ); 00330 00331 //---- benchmark assembly operations 00332 subPVP.y = pvp.y + tiles * subPVP.h; 00333 00334 eq::Compositor::ImageOp op; 00335 op.channel = this; 00336 op.buffers = eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH; 00337 op.offset = offset; 00338 00339 // fixed-function 00340 event.data.type = ConfigEvent::ASSEMBLE; 00341 snprintf( event.formatType, 32, "tiles, GL1.1, %d images", tiles+1 ); 00342 00343 clock.reset(); 00344 for( unsigned j = 0; j <= tiles; ++j ) 00345 eq::Compositor::assembleImage( images[j], op ); 00346 00347 event.msec = clock.getTimef(); 00348 config->sendEvent( event ); 00349 00350 // CPU 00351 snprintf( event.formatType, 32, "tiles, CPU, %d images", tiles+1 ); 00352 00353 std::vector< eq::Frame* > frames; 00354 frames.push_back( &_frame ); 00355 00356 clock.reset(); 00357 eq::Compositor::assembleFramesCPU( frames, this ); 00358 event.msec = clock.getTimef(); 00359 config->sendEvent( event ); 00360 } 00361 } 00362 00363 void Channel::_testDepthAssemble() 00364 { 00365 //----- setup constant data 00366 const eq::Images& images = _frame.getImages(); 00367 eq::Image* image = images[ 0 ]; 00368 EQASSERT( image ); 00369 00370 eq::Config* config = getConfig(); 00371 const eq::PixelViewport& pvp = getPixelViewport(); 00372 const eq::Vector2i offset( pvp.x, pvp.y ); 00373 00374 ConfigEvent event = _createConfigEvent(); 00375 event.area.x() = pvp.w; 00376 00377 co::base::Clock clock; 00378 eq::Window::ObjectManager* glObjects = getObjectManager(); 00379 const GLEWContext* glewContext = glewGetContext(); 00380 00381 //----- test depth-based assembly algorithms 00382 for( unsigned i = 0; i < NUM_IMAGES; ++i ) 00383 { 00384 image = images[ i ]; 00385 EQASSERT( image ); 00386 image->setPixelViewport( pvp ); 00387 } 00388 00389 event.area.y() = pvp.h; 00390 00391 for( unsigned i = 0; i < NUM_IMAGES; ++i ) 00392 { 00393 _draw( i ); 00394 00395 // fill depth & color image 00396 image = images[ i ]; 00397 00398 EQCHECK( image->allocDownloader( eq::Frame::BUFFER_COLOR, 00399 EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA, 00400 glewContext )); 00401 00402 EQCHECK( image->allocDownloader( eq::Frame::BUFFER_DEPTH, 00403 EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT, 00404 glewContext )); 00405 00406 image->clearPixelData( eq::Frame::BUFFER_COLOR ); 00407 image->clearPixelData( eq::Frame::BUFFER_DEPTH ); 00408 00409 image->readback( eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH, 00410 pvp, eq::Zoom(), glObjects ); 00411 00412 if( i == NUM_IMAGES-1 ) 00413 _saveImage( image,"EQ_COMPRESSOR_DATATYPE_DEPTH_UNSIGNED_INT", 00414 "depthAssemble" ); 00415 00416 // benchmark 00417 eq::Compositor::ImageOp op; 00418 op.channel = this; 00419 op.buffers = eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH; 00420 op.offset = offset; 00421 00422 // fixed-function 00423 event.data.type = ConfigEvent::ASSEMBLE; 00424 snprintf( event.formatType, 32, "depth, GL1.1, %d images", i+1 ); 00425 00426 clock.reset(); 00427 for( unsigned j = 0; j <= i; ++j ) 00428 eq::Compositor::assembleImageDB_FF( images[j], op ); 00429 00430 event.msec = clock.getTimef(); 00431 config->sendEvent( event ); 00432 00433 // GLSL 00434 if( GLEW_VERSION_2_0 ) 00435 { 00436 snprintf( event.formatType, 32, "depth, GLSL, %d images", i+1 ); 00437 00438 clock.reset(); 00439 for( unsigned j = 0; j <= i; ++j ) 00440 eq::Compositor::assembleImageDB_GLSL( images[j], op ); 00441 event.msec = clock.getTimef(); 00442 config->sendEvent( event ); 00443 } 00444 00445 // CPU 00446 snprintf( event.formatType, 32, "depth, CPU, %d images", i+1 ); 00447 00448 std::vector< eq::Frame* > frames; 00449 frames.push_back( &_frame ); 00450 00451 clock.reset(); 00452 eq::Compositor::assembleFramesCPU( frames, this ); 00453 event.msec = clock.getTimef(); 00454 config->sendEvent( event ); 00455 } 00456 } 00457 00458 void Channel::_saveImage( const eq::Image* image, 00459 const char* externalformat, 00460 const char* info ) 00461 { 00462 return; 00463 00464 static uint32_t counter = 0; 00465 std::ostringstream stringstream; 00466 stringstream << "Image_" << ++counter << "_" << externalformat << "_" 00467 << info; 00468 image->writeImages( stringstream.str( )); 00469 } 00470 00471 void Channel::_draw( const eq::uint128_t& spin ) 00472 { 00473 glPushAttrib( GL_ALL_ATTRIB_BITS ); 00474 00475 eq::Channel::frameDraw( spin ); 00476 00477 glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ); 00478 glEnable( GL_DEPTH_TEST ); 00479 00480 #if 0 00481 setNearFar( 0.5f, 5.0f ); 00482 const GLfloat lightPosition[] = {5.0f, 0.0f, 5.0f, 0.0f}; 00483 const GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f}; 00484 00485 const GLfloat materialDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f}; 00486 00487 glLightfv( GL_LIGHT0, GL_POSITION, lightPosition ); 00488 glLightfv( GL_LIGHT0, GL_DIFFUSE, lightDiffuse ); 00489 00490 glMaterialfv( GL_FRONT, GL_DIFFUSE, materialDiffuse ); 00491 00492 eq::Matrix4f rotation; 00493 eq::Vector3f translation; 00494 00495 translation = eq::Vector3f::ZERO; 00496 translation.z = -2.f; 00497 rotation = eq::Matrix4f::IDENTITY; 00498 rotation.rotate_x( static_cast<float>( -M_PI_2 )); 00499 rotation.rotate_y( static_cast<float>( -M_PI_2 )); 00500 00501 glTranslatef( translation.x, translation.y, translation.z ); 00502 glMultMatrixf( rotation.ml ); 00503 00504 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); 00505 glColor3f( 1.f, 1.f, 0.f ); 00506 glNormal3f( 1.f, -1.f, 0.f ); 00507 glBegin( GL_TRIANGLE_STRIP ); 00508 glVertex3f( 1.f, 10.f, 2.5f ); 00509 glVertex3f( -1.f, 10.f, 2.5f ); 00510 glVertex3f( 1.f,-10.f, -2.5f ); 00511 glVertex3f( -1.f,-10.f, -2.5f ); 00512 glEnd(); 00513 00514 #else 00515 00516 const float lightPos[] = { 0.0f, 0.0f, 1.0f, 0.0f }; 00517 glLightfv( GL_LIGHT0, GL_POSITION, lightPos ); 00518 00519 const float lightAmbient[] = { 0.2f, 0.2f, 0.2f, 1.0f }; 00520 glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient ); 00521 00522 // rotate scene around the origin 00523 glRotatef( static_cast< float >( spin.low() + 3 ) * 10, 1.0f, 0.5f, 0.25f ); 00524 00525 // render six axis-aligned colored quads around the origin 00526 // front 00527 glColor3f( 1.0f, 0.5f, 0.5f ); 00528 glNormal3f( 0.0f, 0.0f, 1.0f ); 00529 glBegin( GL_TRIANGLE_STRIP ); 00530 glVertex3f( .7f, .7f, -1.0f ); 00531 glVertex3f( -.7f, .7f, -1.0f ); 00532 glVertex3f( .7f, -.7f, -1.0f ); 00533 glVertex3f( -.7f, -.7f, -1.0f ); 00534 glEnd(); 00535 00536 // bottom 00537 glColor3f( 0.5f, 1.0f, 0.5f ); 00538 glNormal3f( 0.0f, 1.0f, 0.0f ); 00539 glBegin( GL_TRIANGLE_STRIP ); 00540 glVertex3f( .7f, -1.0f, .7f ); 00541 glVertex3f( -.7f, -1.0f, .7f ); 00542 glVertex3f( .7f, -1.0f, -.7f ); 00543 glVertex3f( -.7f, -1.0f, -.7f ); 00544 glEnd(); 00545 00546 // back 00547 glColor3f( 0.5f, 0.5f, 1.0f ); 00548 glNormal3f( 0.0f, 0.0f, -1.0f ); 00549 glBegin( GL_TRIANGLE_STRIP ); 00550 glVertex3f( .7f, .7f, 1.0f ); 00551 glVertex3f( -.7f, .7f, 1.0f ); 00552 glVertex3f( .7f, -.7f, 1.0f ); 00553 glVertex3f( -.7f, -.7f, 1.0f ); 00554 glEnd(); 00555 00556 // top 00557 glColor3f( 1.0f, 1.0f, 0.5f ); 00558 glNormal3f( 0.f, -1.f, 0.f ); 00559 glBegin( GL_TRIANGLE_STRIP ); 00560 glVertex3f( .7f, 1.0f, .7f ); 00561 glVertex3f( -.7f, 1.0f, .7f ); 00562 glVertex3f( .7f, 1.0f, -.7f ); 00563 glVertex3f( -.7f, 1.0f, -.7f ); 00564 glEnd(); 00565 00566 // right 00567 glColor3f( 1.0f, 0.5f, 1.0f ); 00568 glNormal3f( -1.f, 0.f, 0.f ); 00569 glBegin( GL_TRIANGLE_STRIP ); 00570 glVertex3f( 1.0f, .7f, .7f ); 00571 glVertex3f( 1.0f, -.7f, .7f ); 00572 glVertex3f( 1.0f, .7f, -.7f ); 00573 glVertex3f( 1.0f, -.7f, -.7f ); 00574 glEnd(); 00575 00576 // left 00577 glColor3f( 0.5f, 1.0f, 1.0f ); 00578 glNormal3f( 1.f, 0.f, 0.f ); 00579 glBegin( GL_TRIANGLE_STRIP ); 00580 glVertex3f( -1.0f, .7f, .7f ); 00581 glVertex3f( -1.0f, -.7f, .7f ); 00582 glVertex3f( -1.0f, .7f, -.7f ); 00583 glVertex3f( -1.0f, -.7f, -.7f ); 00584 glEnd(); 00585 00586 #endif 00587 00588 glPopAttrib( ); 00589 } 00590 00591 00592 }