src/render/rSysdep.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023 
00024 ***************************************************************************
00025 
00026 */
00027 
00028 
00029 #include "defs.h"
00030 
00031 #include "rGL.h"
00032 
00033 #ifndef DEDICATED
00034 #include "rSDL.h"
00035 #endif
00036 
00037 #include "rSysdep.h"
00038 #include "tInitExit.h"
00039 #include "tDirectories.h"
00040 #include "tSysTime.h"
00041 #include "rConsole.h"
00042 #include "aa_config.h"
00043 #include <iostream>
00044 #include "rScreen.h"
00045 #include "rTexture.h"
00046 #include "tCommandLine.h"
00047 #include "tConfiguration.h"
00048 #include "tRecorder.h"
00049 #include "rTextureRenderTarget.h"
00050 #include <memory>
00051 
00052 #ifndef DEDICATED
00053 #include "SDL_thread.h"
00054 #include "SDL_mutex.h"
00055 
00056 #include <png.h>
00057 #include <unistd.h>
00058 #define SCREENSHOT_PNG_BITDEPTH 8
00059 #define SCREENSHOT_BYTES_PER_PIXEL 3
00060 #ifndef SDL_OPENGL
00061 #ifndef DIRTY
00062 #define DIRTY
00063 #endif
00064 #endif
00065 
00066 //#ifndef SDL_OPENGL
00067 //#error "need SDL 1.1"
00068 //#endif
00069 
00070 #ifndef DIRTY
00071 
00072 // nothing to be done.
00073 
00074 /*
00075 //#elif defined(HAVE_FXMESA)
00076  #include <GL/gl>
00077  #include <GL/fxmesa>
00078 
00079  static fxMesaContext ctx=NULL;
00080 */
00081 
00082 #elif defined(WIN32)
00083 
00084 #include <windows.h>
00085 #include <windef.h>
00086 #include "rGL.h"
00087 static HDC hDC=NULL;
00088 static HGLRC hRC=NULL;
00089 
00090 #elif defined(unix) || defined(__unix__)
00091 
00092 #include <GL/glx.h>
00093 static GLXContext cx;
00094 Display *dpy=NULL;
00095 Window  win;
00096 
00097 #endif
00098 
00099 #ifdef DIRTY
00100 #include <SDL_syswm.h>
00101 
00102 // graphics initialisation and cleanup:
00103 bool  rSysDep::InitGL(){
00104     SDL_SysWMinfo system;
00105     SDL_VERSION(&system.version);
00106     if (!SDL_GetWMInfo(&system)){
00107         std::cerr << "Video information not available!\n";
00108         return(false);
00109     }
00110 
00111     /*
00112     con << "SDL version: " << (int)system.version.major
00113          << "." <<  (int)system.version.minor << "." <<  (int)system.version.patch << '\n';
00114     */
00115 
00116     /*
00117     //#ifdef HAVE_FXMESA
00118     if(!ctx){
00119       int x=fxQueryHardware();
00120       if(x){
00121         std::cerr << "No 3Dfx hardware available.\n" << x << '\n';
00122         return(false);
00123       }
00124 
00125       GLint attribs[]={FXMESA_DOUBLEBUFFER,FXMESA_DEPTH_SIZE,16,FXMESA_NONE};
00126       ctx=fxMesaCreateBestContext(0,sr_screenWidth,sr_screenHeight,attribs);
00127 
00128       if (!ctx){
00129         std::cerr << "Could not create FX rendering context!\n";
00130         return(false);
00131       }
00132 
00133       fxMesaMakeCurrent(ctx);
00134     }
00135     */
00136 #ifdef WIN32
00137     // windows GL initialisation stolen from
00138     // http://www.geocities.com/SiliconValley/Code/1219/opengl32.html
00139 
00140     if (!hRC){
00141         HWND hWnd=system.window;
00142 
00143         PIXELFORMATDESCRIPTOR pfd;
00144         int iFormat;
00145 
00146         // get the device context (DC)
00147         hDC = GetDC( hWnd );
00148         if (!hDC) return false;
00149 
00150         // set the pixel format for the DC
00151         ZeroMemory( &pfd, sizeof( pfd ) );
00152         pfd.nSize = sizeof( pfd );
00153         pfd.nVersion = 1;
00154         pfd.dwFlags = PFD_DRAW_TO_WINDOW |
00155                       PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
00156         pfd.iPixelType = PFD_TYPE_RGBA;
00157         pfd.cColorBits = currentScreensetting.colorDepth ? 24 : 16;
00158         pfd.cDepthBits = 16;
00159         pfd.iLayerType = PFD_MAIN_PLANE;
00160         iFormat = ChoosePixelFormat( hDC, &pfd );
00161         SetPixelFormat( hDC, iFormat, &pfd );
00162 
00163         // create and enable the render context (RC)
00164         hRC = wglCreateContext( hDC );
00165         if (!hRC || !wglMakeCurrent( hDC, hRC ))
00166             return false;
00167     }
00168 
00169 #elif defined(unix) || defined(__unix__)
00170     if (system.subsystem!=SDL_SYSWM_X11){
00171         std::cerr << "System is not X11!\n";
00172         std::cerr << (int)system.subsystem << "!=" << (int)SDL_SYSWM_X11 <<'\n';
00173         return false;
00174     }
00175 
00176     if (!dpy){
00177 
00178         dpy=system.info.x11.display;
00179         win=system.info.x11.window;
00180 
00181         int errorbase,tEventbase;
00182         if (glXQueryExtension(dpy,&errorbase,&tEventbase) == False){
00183             std::cerr << "OpenGL through GLX not supported.\n";
00184             return false;
00185         }
00186 
00187         int configuration[]={GLX_DOUBLEBUFFER,GLX_RGBA,GLX_DEPTH_SIZE ,12, GLX_RED_SIZE,1,
00188                              GLX_BLUE_SIZE,1,GLX_GREEN_SIZE,1,None
00189                             };
00190 
00191         XVisualInfo *vi=glXChooseVisual(dpy,DefaultScreen(dpy),configuration);
00192 
00193         if (vi== NULL){
00194             std::cerr << "Could not initialize Visual.\n";
00195             return false;
00196         }
00197 
00198         cx=glXCreateContext(dpy,vi,
00199                             NULL,True);
00200 
00201         if (cx== NULL){
00202             std::cerr << "Could not initialize GL context.\n";
00203             return false;
00204         }
00205 
00206         if (!glXMakeCurrent(dpy,win,cx)){
00207             dpy=0;
00208             return false;
00209         }
00210     }
00211 
00212 #endif
00213 
00214     return true;
00215 }
00216 
00217 void  rSysDep::ExitGL(){
00218     SDL_SysWMinfo system;
00219     SDL_GetWMInfo(&system);
00220 
00221     /*
00222     #ifdef HAVE_FXMESA
00223 
00224     if(ctx){
00225       fxMesaDestroyContext(ctx);
00226       ctx=NULL;
00227       fxCloseHardware();
00228     }
00229     */
00230 
00231 #if defined(WIN32)
00232     HWND hWnd=system.window;
00233 
00234     // windows GL cleanup stolen from
00235     // http://www.geocities.com/SiliconValley/Code/1219/opengl32.html
00236     if (hRC){
00237 
00238         wglMakeCurrent( NULL, NULL );
00239         wglDeleteContext( hRC );
00240         ReleaseDC( hWnd, hDC );
00241 
00242         hRC=NULL;
00243         hDC=NULL;
00244     }
00245 #elif defined(unix) || defined(__unix__)
00246     if (dpy){
00247 
00248         //    glXReleaseBuffersMESA( dpy, win );
00249         glXMakeCurrent(dpy,None,NULL);
00250         glXDestroyContext(dpy, cx );
00251         dpy=NULL;
00252     }
00253 #endif
00254 }
00255 #endif // DIRTY
00256 
00257 bool sr_screenshotIsPlanned=false;
00258 static bool   s_videoout    =false;
00259 static int    s_videooutDest=fileno(stdout);
00260 
00261 static bool png_screenshot=true;
00262 static tConfItem<bool> pns("PNG_SCREENSHOT",png_screenshot);
00263 #ifndef DEDICATED
00264 
00265 static void SDL_SavePNG(SDL_Surface *image, tString filename){
00266     png_structp png_ptr;
00267     png_infop info_ptr;
00268     png_byte **row_ptrs;
00269     int i;
00270     static FILE *fp;
00271 
00272     if (!(fp = fopen(filename, "wb"))) {
00273         fprintf(stderr, "can't open file for writing\n");
00274         return;
00275     }
00276 
00277     if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) {
00278         return;
00279     }
00280 
00281     if (!(info_ptr = png_create_info_struct(png_ptr))) {
00282         png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00283         return;
00284     }
00285 
00286     png_init_io(png_ptr, fp);
00287 
00288     png_set_IHDR(png_ptr, info_ptr, sr_screenWidth, sr_screenHeight,
00289                  SCREENSHOT_PNG_BITDEPTH, PNG_COLOR_TYPE_RGB,
00290                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
00291                  PNG_FILTER_TYPE_DEFAULT);
00292     png_write_info(png_ptr, info_ptr);
00293 
00294     // get pointers
00295     if (!(row_ptrs = (png_byte**) malloc(sr_screenHeight * sizeof(png_byte*)))) {
00296         png_destroy_write_struct(&png_ptr, &info_ptr);
00297         return;
00298     }
00299 
00300     for (i = 0; i < sr_screenHeight; i++) {
00301         row_ptrs[i] = (png_byte *)image->pixels + (sr_screenHeight - i - 1)
00302                       * SCREENSHOT_BYTES_PER_PIXEL * sr_screenWidth;
00303     }
00304 
00305     png_write_image(png_ptr, row_ptrs);
00306     png_write_end(png_ptr, info_ptr);
00307     png_destroy_write_struct(&png_ptr, &info_ptr);
00308 
00309     free(row_ptrs);
00310     fclose(fp);
00311 }
00312 #endif
00313 
00314 static void make_screenshot(){
00315 #ifndef DEDICATED
00316     // screenshot count
00317     static int number=0;
00318     number++;
00319 
00320     SDL_Surface *image;
00321     SDL_Surface *temp;
00322     int idx;
00323     image = SDL_CreateRGBSurface(SDL_SWSURFACE, sr_screenWidth, sr_screenHeight,
00324                                  24, 0x0000FF, 0x00FF00, 0xFF0000 ,0);
00325     temp = SDL_CreateRGBSurface(SDL_SWSURFACE, sr_screenWidth, sr_screenHeight,
00326                                 24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
00327 
00328     // make upside down screenshot (make sure it comes from the screen)
00329 
00330     glReadPixels(0,0,sr_screenWidth, sr_screenHeight, GL_RGB,
00331                  GL_UNSIGNED_BYTE, image->pixels);
00332 
00333     // turn image around
00334     for (idx = 0; idx < sr_screenHeight; idx++)
00335     {
00336         memcpy(reinterpret_cast<char *>(temp->pixels) + 3 * sr_screenWidth * idx,
00337                reinterpret_cast<char *>(image->pixels)+ 3
00338                * sr_screenWidth*(sr_screenHeight - idx-1),
00339                3*sr_screenWidth);
00340     }
00341 
00342     if (s_videoout)
00343         write(s_videooutDest, temp->pixels, sr_screenWidth * sr_screenHeight * 3);
00344 
00345     if (sr_screenshotIsPlanned) {
00346         // save screenshot in unused slot
00347         bool done = false;
00348         while ( !done )
00349         {
00350             // generate filename
00351             tString fileName("screenshot_");
00352             fileName << number;
00353             if (png_screenshot)
00354                 fileName << ".png";
00355             else
00356                 fileName << ".bmp";
00357 
00358             // test if file exists
00359             std::ifstream s;
00360             if ( tDirectories::Screenshot().Open( s, fileName ) )
00361             {
00362                 // yes! try next number
00363                 number++;
00364                 continue;
00365             }
00366 
00367             // save image
00368             if (png_screenshot)
00369                 SDL_SavePNG(image, tDirectories::Screenshot().GetWritePath( fileName ));
00370             else
00371                 SDL_SaveBMP(temp, tDirectories::Screenshot().GetWritePath( fileName ) );
00372             done = true;
00373         }
00374     }
00375 
00376     // cleanup
00377     SDL_FreeSurface(image);
00378     SDL_FreeSurface(temp);
00379 #endif
00380 }
00381 
00382 class PerformanceCounter
00383 {
00384 public:
00385     PerformanceCounter(): count_(0){
00386         tRealSysTimeFloat();
00387     }
00388     unsigned int Count(){
00389         return count_++;
00390     }
00391     ~PerformanceCounter()
00392     {
00393         double time = tRealSysTimeFloat();
00394         std::stringstream s;
00395         s << count_ << " frames in " << time << " seconds: " << count_ / time << " fps.\n";
00396 #ifdef WIN32
00397         MessageBox (NULL, s.str().c_str() , "Performance", MB_OK);
00398 #else
00399         std::cout << s.str();
00400 #endif
00401     }
00402 private:
00403     unsigned int count_;
00404 };
00405 
00406 static double s_nextFastForwardFrameRecorded=0; // the next frame to render in recorded time
00407 static double s_nextFastForwardFrameReal=0;     // the next frame to render in real time
00408 #endif // DEDICATED
00409 
00410 // settings for fast forward mode
00411 static REAL sr_FF_Maxstep=1; // maximum step between rendered frames
00412 static tSettingItem<REAL> c_ff( "FAST_FORWARD_MAXSTEP",
00413                                 sr_FF_Maxstep );
00414 
00415 static REAL sr_FF_MaxstepReal=.05; // maximum step in real time between rendered frames
00416 static tSettingItem<REAL> c_ffre( "FAST_FORWARD_MAXSTEP_REAL",
00417                                   sr_FF_MaxstepReal );
00418 
00419 static REAL sr_FF_MaxstepRel=1; // maximum step between rendered frames relative to end of FF mode
00420 static tSettingItem<REAL> c_ffr( "FAST_FORWARD_MAXSTEP_REL",
00421                                  sr_FF_MaxstepRel );
00422 
00423 
00424 static double s_fastForwardTo=0;
00425 static bool   s_fastForward =false;
00426 static bool   s_benchmark   =false;
00427 
00428 class rFastForwardCommandLineAnalyzer: public tCommandLineAnalyzer
00429 {
00430 private:
00431     virtual bool DoAnalyze( tCommandLineParser & parser )
00432     {
00433         // get option
00434         tString forward;
00435         if ( parser.GetOption( forward, "--fastforward" ) )
00436         {
00437             // set fast forward mode
00438             s_fastForward = true;
00439 
00440             // read time
00441             std::stringstream str(static_cast< char const * >( forward ) );
00442             str >> s_fastForwardTo;
00443 
00444             return true;
00445         }
00446 
00447         if ( parser.GetSwitch( "--benchmark" ) )
00448         {
00449             // set benchmark mode
00450             s_benchmark = true;
00451             return true;
00452         }
00453 
00454 #ifndef DEDICATED
00455         if ( parser.GetSwitch( "--videoout" ) )
00456         {
00457             // redirect all regular output to stderr
00458             if ((s_videooutDest = dup(fileno(stdout))) == -1)
00459                 std::cout << "Warning: Failed to duplicate stdout descriptor for video\n";
00460             else {
00461                 if (-1 == dup2(fileno(stderr), fileno(stdout)))
00462                     std::cout << "Warning: Failed to redirect default output to stderr\n";
00463                 else
00464                     std::cout << "Video Output: normal output redirected to stderr\n";
00465             }
00466             // set video out mode
00467             s_videoout = true;
00468             return true;
00469         }
00470 #endif
00471 
00472         return false;
00473     }
00474 
00475     virtual void DoHelp( std::ostream & s )
00476     {                                      //
00477         s << "--fastforward <time>         : lets time run very fast until the given time is reached\n";
00478         s << "--benchmark                  : renders frames as they were recorded\n";
00479 #ifndef DEDICATED
00480         s << "--videoout                   : writes a raw video stream of frames to stdout\n";
00481 #endif
00482     }
00483 };
00484 
00485 static rFastForwardCommandLineAnalyzer analyzer;
00486 
00487 // #define MILLION 1000000
00488 
00489 /*
00490 static double lastFrame = -1;
00491 static void sr_DelayFrame( int targetFPS )
00492 {
00493     // calculate microseconds per frame
00494     int uSecsPerFrame = MILLION/(targetFPS + 10);
00495 
00496     // calculate microseconds spent rendering
00497     double thisFrame = tRealSysTimeFloat();
00498 
00499     int uSecsPassed = static_cast<int>( MILLION * ( thisFrame - lastFrame ) );
00500 
00501 //    con << uSecsPassed << "\n";
00502 
00503     // wait
00504     int uSecsToWait = uSecsPerFrame - uSecsPassed;
00505     if ( uSecsToWait > 0 )
00506         tDelay( uSecsToWait );
00507 
00508     // call glFinish to wait for GPU
00509     glFinish();
00510 }
00511 */
00512 
00513 rSysDep::rSwapMode rSysDep::swapMode_ = rSysDep::rSwap_glFlush;
00514 //rSysDep::rSwapMode rSysDep::swapMode_ = rSysDep::rSwap_60Hz;
00515 
00516 // buffer swap:
00517 #ifndef DEDICATED
00518 // for setting breakpoints in optimized mode, too
00519 static void breakpoint(){}
00520 
00521 static bool sr_netSyncThreadGoOn = true;
00522 static rSysDep::rNetIdler * sr_netIdler = NULL;
00523 int sr_NetSyncThread(void *lockVoid)
00524 {
00525     SDL_mutex *lock = (SDL_mutex *)lockVoid;
00526 
00527     SDL_mutexP(lock);
00528 
00529     while ( sr_netSyncThreadGoOn )
00530     {
00531         SDL_mutexV(lock);
00532         // wait for network data
00533         bool toDo = sr_netIdler->Wait();
00534         SDL_mutexP(lock);
00535 
00536         if ( toDo )
00537         {
00538             // disable rendering (during auto-scrolling of console, for example)
00539             bool glout = sr_glOut;
00540             sr_glOut = false;
00541 
00542             // new network data arrived, handle it
00543             sr_netIdler->Do();
00544 
00545             // enable rendering again
00546             sr_glOut = glout;
00547         }
00548     }
00549 
00550     SDL_mutexV(lock);
00551 
00552     return 0;
00553 }
00554 
00555 static SDL_Thread * sr_netSyncThread = NULL;
00556 static SDL_mutex * sr_netLock = NULL;
00557 void rSysDep::StartNetSyncThread( rNetIdler * idler )
00558 {
00559     sr_netIdler = idler;
00560 
00561     return; // BUG This thread is crashing ruby
00562 
00563     // can't use thrading trouble while recording
00564     if ( tRecorder::IsRunning() )
00565         return;
00566 
00567     if ( sr_netSyncThread )
00568         return;
00569 
00570     // create lock
00571     if ( !sr_netLock )
00572         sr_netLock = SDL_CreateMutex();
00573 
00574     // start thread
00575     sr_netSyncThread = SDL_CreateThread( sr_NetSyncThread, sr_netLock );
00576     if ( !sr_netSyncThread )
00577         return;
00578 
00579     // lock mutex, the thread should only do work while the main thread is waiting for the refresh
00580     SDL_mutexP( sr_netLock );
00581 }
00582 
00583 void rSysDep::StopNetSyncThread()
00584 {
00585     // stop and delete thread
00586     if ( sr_netSyncThread )
00587     {
00588         SDL_mutexV(  sr_netLock );
00589         sr_netSyncThreadGoOn = false;
00590         SDL_WaitThread( sr_netSyncThread, NULL );
00591         sr_netSyncThread = NULL;
00592         sr_netIdler = NULL;
00593     }
00594 
00595     // delete lock
00596     if ( sr_netLock )
00597     {
00598         SDL_DestroyMutex( sr_netLock );
00599         sr_netLock = NULL;
00600     }
00601 }
00602 
00603 int NextPowerOfTwo( int in )
00604 {
00605     int x = 1;
00606     while ( x * 32 <= in )
00607         x <<= 5;
00608     while ( x < in )
00609         x <<= 1;
00610 
00611     return x;
00612 }
00613 
00614 bool sr_MotionBlurCore( REAL alpha, rTextureRenderTarget & blurTarget )
00615 {
00616     sr_CheckGLError();
00617 
00618     if ( alpha < 0 )
00619         alpha = 0;
00620 
00621     {
00622         if ( blurTarget.IsTarget() )
00623         {
00624             blurTarget.Pop();
00625 
00626             blurTarget.Select();
00627 
00628             glDrawBuffer( GL_FRONT );
00629 
00630             sr_CheckGLError();
00631 
00632             // determine the texture coordinates of the lower right corner
00633             REAL maxu = REAL(sr_screenWidth)/blurTarget.GetWidth();
00634             REAL maxv = REAL(sr_screenHeight)/blurTarget.GetHeight();
00635 
00636             glEnable(GL_TEXTURE_2D);
00637 
00638             // blend the last frame and the current frame with the specified alpha value
00639             glDisable( GL_DEPTH_TEST );
00640             glDepthMask(0);
00641 
00642             glMatrixMode( GL_PROJECTION );
00643             glLoadIdentity();
00644             glMatrixMode( GL_MODELVIEW );
00645             glLoadIdentity();
00646             glViewport(0,0,sr_screenWidth, sr_screenHeight);
00647 
00648             glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,
00649                             GL_NEAREST);
00650             glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
00651                             GL_NEAREST);
00652 
00653             glDisable(GL_ALPHA_TEST);
00654             // glDisable(GL_BLEND);
00655             glEnable(GL_BLEND);
00656             glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
00657 
00658             glDisable(GL_LIGHTING);
00659 
00660             glBegin( GL_QUADS );
00661             glColor4f( 1,1,1,alpha );
00662 
00663             glTexCoord2f( 0, 0 );
00664             glVertex2f( -1, -1 );
00665 
00666             glTexCoord2f( maxu, 0 );
00667             glVertex2f( 1, -1 );
00668 
00669             glTexCoord2f( maxu, maxv );
00670             glVertex2f( 1, 1 );
00671 
00672             glTexCoord2f( 0, maxv );
00673             glVertex2f( -1, 1 );
00674             glEnd();
00675 
00676             sr_CheckGLError();
00677 
00678             // clean up
00679             glDepthMask(1);
00680 
00681             glDrawBuffer( GL_BACK );
00682         }
00683 
00684         blurTarget.Push();
00685 
00686         sr_CheckGLError();
00687 
00688         return false;
00689     }
00690 
00691     return true;
00692 
00693 #if 0
00694     GLenum error = glGetError();
00695     if ( error != GL_NO_ERROR )
00696         con << "GL error " << error << "\n";
00697 #endif
00698 }
00699 
00700 // frames from about this far apart get blended together
00701 static REAL sr_motionBlurTime = .0075;
00702 static tSettingItem<REAL> c_mb( "MOTION_BLUR_TIME",
00703                                 sr_motionBlurTime );
00704 
00705 // blurs the motion, time is the current time
00706 bool sr_MotionBlur( double time, std::auto_ptr< rTextureRenderTarget > & blurTarget )
00707 {
00708     static bool lastActive = false;
00709     bool active = false;
00710 
00711     // measure frame rendering time
00712     static double lastTime = time;
00713     REAL frameTime = time - lastTime;
00714 
00715     if ( currentScreensetting.vSync == ArmageTron_VSync_MotionBlur )
00716     {
00717         // use hysteresis to autodisable motion blurring if rendering gets
00718         // far too slow and reenable it if rendering gets fast enough again
00719         static int hyster = 0;
00720         static int thresh = 100;
00721         active = lastActive;
00722 
00723         if ( frameTime * 2 < sr_motionBlurTime )
00724         {
00725             if ( ++hyster > thresh )
00726             {
00727                 active = true;
00728                 hyster = thresh;
00729             }
00730         }
00731         else if ( frameTime > sr_motionBlurTime * 2 )
00732         {
00733             if ( --hyster < -thresh )
00734             {
00735                 active = false;
00736                 hyster = -thresh;
00737             }
00738         }
00739         else
00740         {
00741             if ( hyster < 0 )
00742                 ++hyster;
00743             else
00744                 --hyster;
00745         }
00746 
00747         lastTime = time;
00748     }
00749 
00750     // really blur.
00751     if ( lastActive )
00752     {
00753         // determine blur texture size
00754         int blurWidth = NextPowerOfTwo( sr_screenWidth );
00755         int blurHeight = NextPowerOfTwo( sr_screenHeight );
00756 
00757         // destroy existing blur texture if it is too small
00758         if ( blurTarget.get() && ( blurTarget->GetWidth() < blurWidth || blurTarget->GetHeight() < blurHeight ) )
00759         {
00760             blurTarget = std::auto_ptr< rTextureRenderTarget >();
00761         }
00762 
00763         // create blur texture
00764         if ( !blurTarget.get() )
00765         {
00766             try
00767             {
00768                 blurTarget = std::auto_ptr< rTextureRenderTarget >( new rTextureRenderTarget( blurWidth, blurHeight  ) );
00769             }
00770             catch( rExceptionGLEW const & e )
00771             {
00772                 // unsupported. Disable motion blur.
00773                 currentScreensetting.vSync = ArmageTron_VSync_Off;
00774                 lastActive = false;
00775 
00776                 con << tOutput("$screen_vsync_motionblur_unsupported");
00777 
00778                 return true;
00779             }
00780         }
00781 
00782         // really blur
00783         bool ret = sr_MotionBlurCore( 1 - frameTime / sr_motionBlurTime, *blurTarget );
00784 
00785         // store active value for the next frame
00786         lastActive = active;
00787 
00788         // if the next frame won't be blurred, deactivate rendering to the texture
00789         if ( !active )
00790         {
00791             blurTarget->Pop();
00792         }
00793 
00794         return ret;
00795     }
00796 
00797     lastActive = active;
00798 
00799     // no motion blur happened when we got here
00800     if ( blurTarget.get() && blurTarget->IsTarget() )
00801     {
00802         blurTarget->Pop();
00803     }
00804 
00805     return true;
00806 }
00807 
00808 void rSysDep::SwapGL(){
00809     static std::auto_ptr< rTextureRenderTarget > blurTarget(0);
00810 
00811     if ( s_benchmark )
00812     {
00813         static PerformanceCounter counter;
00814         counter.Count();
00815     }
00816 
00817     double time = tSysTimeFloat();
00818     double realTime = tRealSysTimeFloat();
00819 
00820     bool next_glOut = sr_glOut;
00821 
00822     /* static double mytime = time; //ljr
00823     if (false && time < mytime + 1. / 29.97) {
00824         printf("skipping! %f %f\n", time, mytime);
00825         next_glOut = false;
00826     } else {
00827         printf("rendering %f %f\n", time, mytime);
00828         mytime = time;
00829         next_glOut = true;
00830     } */
00831 
00832     // adapt playback speed to recorded speed
00833     if ( !s_benchmark && !s_fastForward && tRecorder::IsPlayingBack() )
00834     {
00835         static double timeOffset=0;
00836         static double lastRendered=0;
00837 
00838         // calculate how much we're behind the rendering schedule
00839         double behind = - time + realTime + timeOffset;
00840         // std::cout << behind << " " << sr_glOut << "\n";
00841 
00842         // large delays can only be caused by breakpoints or map downloads; ignore them
00843         if ( behind > .5 || realTime > lastRendered + .2 )
00844         {
00845             timeOffset -= behind;
00846             next_glOut = true;
00847         }
00848         else
00849         {
00850             // we're a bit behind, skip the next frame
00851             if ( behind > .1 )
00852             {
00853                 next_glOut = false;
00854             }
00855             else if ( sr_glOut )
00856             {
00857                 lastRendered=realTime;
00858                 // we're ahead, pause a bit
00859                 if  ( behind < -.5 )
00860                     timeOffset -= behind;
00861                 else if ( behind < -.1 )
00862                 {
00863                     int delay = int( -( behind + .1 ) * 1000000 );
00864                     // std::cout << behind << ":" << delay << "\n";
00865                     tDelayForce( delay );
00866                 }
00867             }
00868             else
00869             {
00870                 // we're not behind any more. Reactivate rendering.
00871                 next_glOut = true;
00872             }
00873         }
00874 
00875         if ( next_glOut )
00876             lastRendered=realTime;
00877     }
00878 
00879     if (!sr_glOut)
00880     {
00881         // display next frame in fast foward mode
00882         if ( s_fastForward && ( time > s_nextFastForwardFrameRecorded || realTime > s_nextFastForwardFrameReal ) || next_glOut )
00883         {
00884             sr_glOut = true;
00885             rSysDep::ClearGL();
00886         }
00887 
00888         // in playback or recording mode, always execute frame tasks, they may be improtant for consistency
00889         if ( tRecorder::IsRunning() ) {
00890             rPerFrameTask::DoPerFrameTasks();
00891 #ifdef HAVE_LIBRUBY
00892             rPerFrameTaskRuby::DoPerFrameTasks();
00893 #endif
00894         }
00895 
00896 
00897         return;
00898     }
00899 
00900 
00901     rPerFrameTask::DoPerFrameTasks();
00902 #ifdef HAVE_LIBRUBY
00903     rPerFrameTaskRuby::DoPerFrameTasks();
00904 #endif
00905 
00906     // unlock the mutex while waiting for the swap operation to finish
00907     SDL_mutexV(  sr_netLock );
00908     sr_LockSDL();
00909 
00910     // actiate motion blur (does not use the game state, so it's OK to call here )
00911     bool shouldSwap = sr_MotionBlur( time, blurTarget );
00912 
00913     switch ( swapMode_ )
00914     {
00915     case rSwap_Fastest:
00916         break;
00917     case rSwap_glFlush:
00918         glFlush();
00919         break;
00920     case rSwap_glFinish:
00921         glFinish();
00922         break;
00923     }
00924 
00925     if ( shouldSwap )
00926     {
00927 #if defined(SDL_OPENGL)
00928         if (lastSuccess.useSDL)
00929             SDL_GL_SwapBuffers();
00930         //#elif defined(HAVE_FXMESA)
00931         //fxMesaSwapBuffers();
00932 #endif
00933 
00934 #ifdef DIRTY
00935         if (!lastSuccess.useSDL){
00936 #if defined(WIN32)
00937             SwapBuffers( hDC );
00938 #elif defined(unix) || defined(__unix__)
00939             glXSwapBuffers(dpy,win);
00940 #endif
00941         }
00942 #endif
00943     }
00944 
00945     if (sr_screenshotIsPlanned){
00946         make_screenshot();
00947         sr_screenshotIsPlanned=false;
00948     }
00949     else if (s_videoout)
00950         make_screenshot();
00951 
00952     sr_UnlockSDL();
00953     // lock mutex again
00954     SDL_mutexP(  sr_netLock );
00955 
00956 
00957     // disable output in fast forward mode
00958     if ( s_fastForward && tRecorder::IsPlayingBack() )
00959     {
00960         if ( time < s_fastForwardTo )
00961         {
00962             // next displayed frame should be ten percent closer to the target, but at most 10 seconds
00963             s_nextFastForwardFrameRecorded = ( s_fastForwardTo - time ) * sr_FF_MaxstepRel;
00964             if ( s_nextFastForwardFrameRecorded > sr_FF_Maxstep )
00965                 s_nextFastForwardFrameRecorded = sr_FF_Maxstep ;
00966             s_nextFastForwardFrameRecorded += time;
00967             s_nextFastForwardFrameReal = realTime + sr_FF_MaxstepReal ;
00968 
00969             next_glOut = false;
00970         }
00971         else
00972         {
00973             std::cout << "End of fast forward mode.\n";
00974             st_Breakpoint();
00975             s_fastForward = false;
00976         }
00977     }
00978 
00979     //#ifdef DEBUG
00980     if ( !s_fastForward )
00981     {
00982         breakpoint();
00983     }
00984     //#endif
00985 
00986     // store frame time for next frame
00987     // lastFrame = tRealSysTimeFloat();
00988 
00989     sr_glOut = next_glOut;
00990 }
00991 #endif // dedicated
00992 
00993 #ifndef DEDICATED
00994 static SDL_mutex *mut;
00995 
00996 static void stuff_init(){
00997     mut=SDL_CreateMutex();
00998 }
00999 
01000 static tInitExit stuff_ie(&stuff_init);
01001 #endif
01002 
01003 void sr_LockSDL(){
01004     //std::cerr << "locking...";
01005 #ifndef DEDICATED
01006 #ifndef WIN32
01007     //SDL_mutexP(mut);
01008 #endif
01009 #endif
01010     //std::cerr << " locked!\n";
01011 }
01012 
01013 void sr_UnlockSDL(){
01014     //std::cerr << "unlocking...";
01015 #ifndef DEDICATED
01016 #ifndef WIN32
01017     //SDL_mutexV(mut);
01018 #endif
01019 #endif
01020     //std::cerr << " unlocked!\n";
01021 }
01022 
01023 #ifndef DEDICATED
01024 void  rSysDep::ClearGL(){
01025     if (sr_glOut){
01026 
01027         /*
01028         if (sr_screenshotIsPlanned){
01029           make_screenshot();
01030           sr_screenshotIsPlanned=false;
01031         }
01032         */
01033 
01034         glClearColor(0.0,0.0,0.0,1.0);
01035         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01036     }
01037 }
01038 #endif
01039 
01040 

Generated on Sat Mar 15 22:55:53 2008 for Armagetron Advanced by  doxygen 1.5.4