From 259a72541e5becbeae18742da2374bfa383428ef Mon Sep 17 00:00:00 2001 From: Sam Lantinga <slouken@libsdl.org> Date: Sat, 10 Oct 2009 02:11:07 +0000 Subject: [PATCH] Fixed bug #798 kty@lavabit.com 2009-09-19 14:19:04 PDT The stable release of SDL 1.2.13 for BeOS/Haiku has a bug in BE_FindClosestFSMode that causes it to sometimes not select the best mode when going fullscreen. There are in fact two bugs in the implementation but I will not go into specifics because there is already a patch for it in the developer SVN 1.3. However I am still reporting it because I believe the following code is a better patch for the issue. The current implementation on SVN only works if it is able to find an exact match for the requested mode. However, by scanning from lowest-to-highest resolution instead of highest-to-lowest, one can find the best mode at all times --HG-- branch : SDL-1.2 extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/branches/SDL-1.2%403997 --- src/video/bwindow/SDL_BWin.h | 2 + src/video/bwindow/SDL_sysevents.cc | 17 +++ src/video/bwindow/SDL_sysvideo.cc | 159 +++++++++++++++-------------- 3 files changed, 103 insertions(+), 75 deletions(-) diff --git a/src/video/bwindow/SDL_BWin.h b/src/video/bwindow/SDL_BWin.h index 778914d6..ba8694fe 100644 --- a/src/video/bwindow/SDL_BWin.h +++ b/src/video/bwindow/SDL_BWin.h @@ -267,6 +267,8 @@ public: } virtual void DispatchMessage(BMessage *msg, BHandler *target); + + virtual void DirectConnected(direct_buffer_info *info); private: #if SDL_VIDEO_OPENGL diff --git a/src/video/bwindow/SDL_sysevents.cc b/src/video/bwindow/SDL_sysevents.cc index f0c452dc..f9409db6 100644 --- a/src/video/bwindow/SDL_sysevents.cc +++ b/src/video/bwindow/SDL_sysevents.cc @@ -379,3 +379,20 @@ void SDL_BWin::DispatchMessage(BMessage *msg, BHandler *target) } BDirectWindow::DispatchMessage(msg, target); } + +void SDL_BWin::DirectConnected(direct_buffer_info *info) { + switch (info->buffer_state & B_DIRECT_MODE_MASK) { + case B_DIRECT_START: + case B_DIRECT_MODIFY: + { + int32 width = info->window_bounds.right - + info->window_bounds.left + 1; + int32 height = info->window_bounds.bottom - + info->window_bounds.top + 1; + SDL_PrivateResize(width, height); + break; + } + default: + break; + } +} diff --git a/src/video/bwindow/SDL_sysvideo.cc b/src/video/bwindow/SDL_sysvideo.cc index d0ffe992..33597621 100644 --- a/src/video/bwindow/SDL_sysvideo.cc +++ b/src/video/bwindow/SDL_sysvideo.cc @@ -57,7 +57,7 @@ static void BE_UnlockHWSurface(_THIS, SDL_Surface *surface); static void BE_FreeHWSurface(_THIS, SDL_Surface *surface); static int BE_ToggleFullScreen(_THIS, int fullscreen); -SDL_Overlay *BE_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display); +static SDL_Overlay *BE_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display); /* OpenGL functions */ #if SDL_VIDEO_OPENGL @@ -358,16 +358,25 @@ static bool BE_FindClosestFSMode(_THIS, int width, int height, int bpp, (current.timing.h_total * current.timing.v_total); modes = SDL_modelist[((bpp+7)/8)-1]; - for ( i=0; modes[i] && (modes[i]->w > width) && - (modes[i]->h > height); ++i ) { - /* still looking */ - } - if ( ! modes[i] || (modes[i]->w < width) || (modes[i]->h < width) ) { - --i; /* We went too far */ + + // find end of list (lowest-resolution mode; modes are ordered + // highest-to-lowest). + i = 0; while(modes[i]) i++; + if (!i) return false; // what? no modes at all? + + // find first mode with resolution >= requested in both dimensions + for (--i; i >= 0; --i) + { + if (modes[i]->w >= width && modes[i]->h >= height) + break; } - + + // unable to find any mode with that high a resolution! + if (i < 0) + return false; + width = modes[i]->w; - height = modes[i]->h; + height = modes[i]->h; bscreen.GetModeList(&dmodes, &nmodes); for ( i = 0; i < nmodes; ++i ) { @@ -396,88 +405,88 @@ static bool BE_FindClosestFSMode(_THIS, int width, int height, int bpp, static int BE_SetFullScreen(_THIS, SDL_Surface *screen, int fullscreen) { - int was_fullscreen; - bool needs_unlock; + // printf("SetFullScreen(%d)\n", fullscreen); BScreen bscreen; - BRect bounds; - display_mode mode; - int width, height, bpp; - - /* Set the fullscreen mode */ - was_fullscreen = SDL_Win->IsFullScreen(); - SDL_Win->SetFullScreen(fullscreen); - fullscreen = SDL_Win->IsFullScreen(); - width = screen->w; - height = screen->h; + // SetFullSscreen() does not work as expected if called in a window + // that was never shown. This is probably a bug in the Haiku Game Kit that needs + // to be investigated. + if (SDL_Win->Lock()) { + // Show our window. + SDL_Win->Show(); + } + + if (SDL_Win->IsLocked()) { + // Unlock the window if it was locked. This is needed as only the + // first call to Show() unlocks the looper. All other calls to it + // will not. + SDL_Win->Unlock(); + } - /* Set the appropriate video mode */ - if ( fullscreen ) { - bpp = screen->format->BitsPerPixel; + int width = screen->w; + int height = screen->h; + + if (fullscreen) { + // Set resolution to the closest available one that matches the + // current SDL resolution. + display_mode mode; bscreen.GetMode(&mode); - if ( (bpp != ColorSpaceToBitsPerPixel(mode.space)) || - (width != mode.virtual_width) || - (height != mode.virtual_height)) { + + int bpp = screen->format->BitsPerPixel; + if (bpp != ColorSpaceToBitsPerPixel(mode.space) || + width != mode.virtual_width || height != mode.virtual_height) { if(BE_FindClosestFSMode(_this, width, height, bpp, &mode)) { bscreen.SetMode(&mode); - /* This simply stops the next resize event from being - * sent to the SDL handler. - */ - SDL_Win->InhibitResize(); } else { - fullscreen = 0; - SDL_Win->SetFullScreen(fullscreen); - } + // printf("Could not set new mode.\n"); + return(0); + } } + } else { + // Reset to the previous known resolution as we are now in window + // mode. + bscreen.SetMode(&saved_mode); } - if ( was_fullscreen && ! fullscreen ) { - bscreen.SetMode(&saved_mode); - } - - if ( SDL_Win->Lock() ) { - int cx, cy; - if ( SDL_Win->Shown() ) { - needs_unlock = 1; - SDL_Win->Hide(); - } else { - needs_unlock = 0; - } - /* This resizes the window and view area, but inhibits resizing - * of the BBitmap due to the InhibitResize call above. Thus the - * bitmap (pixel data) never changes. - */ + + // Effectivelly set/reset full screen mode. If we are already in + // full screen mode, we reset back to windowed mode first so the + // window can resize when going fullscreen. + // if (fullscreen) + // printf("Going fullscreen\n"); + // else + // printf("Going windowed\n"); + SDL_Win->SetFullScreen(fullscreen); + + // Calculate offsets for centering the window (in window mode) and for + // dentering the bitmap (in full screen mode). + BRect bounds = bscreen.Frame(); + bounds.PrintToStream(); + int32 cx = (bounds.IntegerWidth() - width)/2; + int32 cy = (bounds.IntegerHeight() - height)/2; + + // printf ("cx = %d, cy = %d\n", cx, cy); + if (!SDL_Win->IsFullScreen()) { + // printf("Doing not fullscreen stuff.\n"); + // We are not in full screen mode, so we want to change the window + // size to match the resolution in SDL. SDL_Win->ResizeTo(width, height); - bounds = bscreen.Frame(); - /* Calculate offsets - used either to center window - * (windowed mode) or to set drawing offsets (fullscreen mode) - */ - cx = (bounds.IntegerWidth() - width)/2; - cy = (bounds.IntegerHeight() - height)/2; - - if ( fullscreen ) { - /* Set offset for drawing */ - SDL_Win->SetXYOffset(cx, cy); - } else { - SDL_Win->SetXYOffset(0, 0); - } - if ( ! needs_unlock || was_fullscreen ) { - /* Center the window the first time */ - SDL_Win->MoveTo(cx, cy); - } - SDL_Win->Show(); - /* Unlock the window manually after the first Show() */ - if ( needs_unlock ) { - SDL_Win->Unlock(); - } + // And also center the window and reset the drawing offset. + SDL_Win->MoveTo(cx, cy); + SDL_Win->SetXYOffset(0, 0); + } else { + // printf("Doing fullscreen stuff."); + // Center the bitmap whenever we are in full screen mode. + SDL_Win->SetXYOffset(cx, cy); } - - /* Set the fullscreen flag in the screen surface */ - if ( fullscreen ) { + + // Set relevant internal SDL screen flags. + if (SDL_Win->IsFullScreen()) { screen->flags |= SDL_FULLSCREEN; } else { screen->flags &= ~SDL_FULLSCREEN; } + return(1); } -- 2.18.1