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