# HG changeset patch # User Sam Lantinga # Date 1255140667 0 # Node ID 0620847bf1a8f1d90d8dad2266e212c020f66a98 # Parent 9ea4413f0a9ea555e1f0676db0dfdba4c944f61c 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 diff -r 9ea4413f0a9e -r 0620847bf1a8 src/video/bwindow/SDL_BWin.h --- a/src/video/bwindow/SDL_BWin.h Sat Oct 10 02:03:53 2009 +0000 +++ b/src/video/bwindow/SDL_BWin.h Sat Oct 10 02:11:07 2009 +0000 @@ -267,6 +267,8 @@ } virtual void DispatchMessage(BMessage *msg, BHandler *target); + + virtual void DirectConnected(direct_buffer_info *info); private: #if SDL_VIDEO_OPENGL diff -r 9ea4413f0a9e -r 0620847bf1a8 src/video/bwindow/SDL_sysevents.cc --- a/src/video/bwindow/SDL_sysevents.cc Sat Oct 10 02:03:53 2009 +0000 +++ b/src/video/bwindow/SDL_sysevents.cc Sat Oct 10 02:11:07 2009 +0000 @@ -379,3 +379,20 @@ } 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 -r 9ea4413f0a9e -r 0620847bf1a8 src/video/bwindow/SDL_sysvideo.cc --- a/src/video/bwindow/SDL_sysvideo.cc Sat Oct 10 02:03:53 2009 +0000 +++ b/src/video/bwindow/SDL_sysvideo.cc Sat Oct 10 02:11:07 2009 +0000 @@ -57,7 +57,7 @@ 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 @@ (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 */ + + // 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; } - if ( ! modes[i] || (modes[i]->w < width) || (modes[i]->h < width) ) { - --i; /* We went too far */ - } - + + // 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 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; - /* Set the appropriate video mode */ - if ( fullscreen ) { - bpp = screen->format->BitsPerPixel; - bscreen.GetMode(&mode); - 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); - } - } - } - if ( was_fullscreen && ! fullscreen ) { - bscreen.SetMode(&saved_mode); + // 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(); } - 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. - */ - 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; + 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 ( 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); + 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); + } else { + // printf("Could not set new mode.\n"); + return(0); + } } - SDL_Win->Show(); + } else { + // Reset to the previous known resolution as we are now in window + // mode. + bscreen.SetMode(&saved_mode); + } + + // 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); - /* 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); }