Skip to content

Commit

Permalink
Fixed bug #798
Browse files Browse the repository at this point in the history
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
  • Loading branch information
slouken committed Oct 10, 2009
1 parent 1de2e6a commit ab59e90
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 75 deletions.
2 changes: 2 additions & 0 deletions src/video/bwindow/SDL_BWin.h
Expand Up @@ -267,6 +267,8 @@ class SDL_BWin : public BDirectWindow
}

virtual void DispatchMessage(BMessage *msg, BHandler *target);

virtual void DirectConnected(direct_buffer_info *info);

private:
#if SDL_VIDEO_OPENGL
Expand Down
17 changes: 17 additions & 0 deletions src/video/bwindow/SDL_sysevents.cc
Expand Up @@ -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;
}
}
159 changes: 84 additions & 75 deletions src/video/bwindow/SDL_sysvideo.cc
Expand Up @@ -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
Expand Down Expand Up @@ -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 ) {
Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit ab59e90

Please sign in to comment.