[SDL] Changing the Screen Size at Runtime

Samuel E. Bray taxtropel_news at yahoo.com
Wed Jan 12 14:25:30 PST 2005


On Wednesday 12 January 2005 08:31 am, Michael Wyrzykowski wrote:
> On Tue, 2005-01-11 at 19:11 +0000, Michael Wyrzykowski wrote:
> > > > The SDL_VIDEORESIZE event doesn't do anything by itself. SDL does not
> > > > take any action when it sees that event or when it generates that
> > > > event. The event is there to tell you that the window has changed
> > > > size. Your code is responsible for actually changing the displayable
> > > > size of the window. What does your code do to handle the event? It
> > > > should be calling SDL_SetVideoMode() to make the SDL surface match
> > > > the new window size, and then (on Windows) reloading all your
> > > > textures and probably recreating your OpenGL context.
> > > >
> > > > If your code is not handling the SDL_VIDEORESIZE event then your     
> > > >   > > program is not doing the right things when the window changes
> > > > size.
> > > >
> > > >   Bob Pendleton
> > >
> > > I am handling the SDL_VIDEORESIZE event like:
> > > ------
> > > if(event.type == SDL_VIDEORESIZE)
> > > {
> > >     int width = event.resize.w;
> > >     int height = event.resize.h;
> > >     float scale_width = float(width)/800; //game logic set for
> > >     float scale_height = float(height)/600;// 800x600 resolution
> > >
> > >     glViewport( 0, 0, width, height);
> > >     glMatrixMode(GL_PROJECTION);
> > >     glLoadIdentity();
> > >     glOrtho( 0, width, height, 0, -1, 1);
> > >     glMatrixMode(GL_MODELVIEW);
> > >     glLoadIdentity();
> > >     glScalef( scale_width, scale_height, 1.0f );
> > > }
> >
> > Yeah, you really are supposed to call SDL_SetVideoMode to make the SDL
> > view of the window match the windowing systems view of the window.    >
> > What happens when you make the window larger than the original window?
> >
> >   Bob Pendleton
>
> When I make the window larger my using the mouse, the call to glScalef()
> simply scales everything that it draws so that whatever size the window is,
> then images will be scaled appropriately to fit. Nothing is cut off. For
> example, the size of my background image is 800x600 (also the default size
> to the window). If the user changes the window size with the mouse to
> 400x600, then glScalef() will be called to scale all images by 0.5 on the
> x-axis, 1.0 on the y-axis, and 1.0 on the z-axis.
>
> When resizing the window with the mouse, I do not need to reload in any
> textures, and everything displays properly. However, I wanted to be able to
> specify the sizes the user could choose, so the graphics do not looked
> distorted from changing a 800x600 window to something like 600x800 (making
> all graphics look taller and less wide).
>
> I'm thinking that the proper thing to do would be to actually call
> SetVideoMode again to request the correct resolution. It may be that I am
> developing a laptop that I did not notice any difference (an LCD display 
> scales images because it only has one true resolution).
>
>
>
> ___________________________________________________________________
> Speed up your surfing with Juno SpeedBand.
> Now includes pop-up blocker!
> Only $14.95/month -visit http://www.juno.com/surf to sign up today!
>
>
> _______________________________________________
> SDL mailing list
> SDL at libsdl.org
> http://www.libsdl.org/mailman/listinfo/sdl

Here's how I usually do it.

First setup SetGLWindow()

void SetGLWindow(int width, int height)
{
  GLfloat ratio;

  if(height == 0)
    height = 1;

  ratio = (GLfloat)width/(GLfloat)height;

  glViewport(0, 0, (GLint)width, (GLint)height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f, ratio, 0.1f, 100.0f);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

}

Then I wait for a resize event in my main loop


while(!done)
    {
      while(SDL_PollEvent(&event))
    {
     switch(event.type)
      {
      case SDL_ACTIVEEVENT:
       if(event.active.gain == 0)
        isActive = FALSE;
       else
        isActive = TRUE;
       break;
      case SDL_VIDEORESIZE:
       if((surface = SDL_SetVideoMode(event.resize.w,
                       event.resize.h,
                       SCREEN_BPP,
                       videoFlags)) == NULL)
        {
         fprintf(stderr,"Unable to grab surface after resize event: 
%s\n",SDL_GetError());
         Quit(1);
        }
       SetGLWindow(event.resize.w, event.resize.h);
       break;
      case SDL_KEYDOWN:
       HandleKeyDown(&event.key.keysym);
       break;
      case SDL_QUIT:
       done = TRUE;
       break;
      default:
       break;
      }
    }
      if(isActive)
    DrawScreen();
    }


**** -- Below is the full example program. More examples can be found on 
http://nehe.gamedev.net

/***** Begin Code Paste *****/

/* build with:
 * gcc -ggdb -Wall -L/usr/X11R6/lib -lGL -lGLU `sdl-config --cflags --libs` 
sdl-gl-18.c -o sdl-gl-18
 */

#include <stdio.h>
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>

#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define SCREEN_BPP 32

#define TRUE 1
#define FALSE 0

SDL_Surface *surface;

int light = FALSE;

GLdouble part1, part2;
GLdouble p1 = 0;
GLdouble p2 = 1;

GLfloat xRot, yRot, ySpeed, xSpeed;
GLfloat z = -5.0f;

GLfloat ambientLight[] = {0.5f, 0.5f, 0.5f, 1.0f };
GLfloat diffusedLight[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat lightPosition[] = {0.0f, 0.0f, 2.0f, 1.0f};

GLUquadricObj *quadric;
GLuint object = 0;

GLuint filter;
GLuint texture[3];


void Quit(int returnCode)
{
  gluDeleteQuadric(quadric);
  glDeleteTextures(3, texture);

  SDL_Quit();

  if(returnCode != 42)
    exit(returnCode);
}

int LoadTextures()
{
  int status = FALSE;

  SDL_Surface *textureImage;

  if((textureImage=SDL_LoadBMP("q_tex.bmp")))
    {
      status = TRUE;

      glGenTextures(3, texture);

      glBindTexture(GL_TEXTURE_2D, texture[0]);
      glTexImage2D(GL_TEXTURE_2D,
          0,
          3,
          textureImage->w,
          textureImage->h,
          0,
          GL_BGR,
          GL_UNSIGNED_BYTE,
          textureImage->pixels);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

      glBindTexture(GL_TEXTURE_2D, texture[1]);
      glTexImage2D(GL_TEXTURE_2D,
          0,
          3,
          textureImage->w,
          textureImage->h,
          0,
          GL_BGR,
          GL_UNSIGNED_BYTE,
          textureImage->pixels);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

      glBindTexture(GL_TEXTURE_2D, texture[2]);
      gluBuild2DMipmaps(GL_TEXTURE_2D,
            3,
            textureImage->w,
            textureImage->h,
            GL_BGR,
            GL_UNSIGNED_BYTE,
            textureImage->pixels);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
GL_LINEAR_MIPMAP_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

      SDL_FreeSurface(textureImage);
    }
  return status;
}

int InitGL(void)
{
  if(!LoadTextures())
  return FALSE;

 glEnable(GL_TEXTURE_2D);
 glShadeModel(GL_SMOOTH);
 glClearColor(0.0, 0.0, 0.0, 0.0);
 glClearDepth(1.0);
 glEnable(GL_DEPTH_TEST);
 glDepthFunc(GL_LEQUAL);
 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
     
 glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffusedLight);
 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
 glEnable(GL_LIGHT0);

 quadric = gluNewQuadric();
 gluQuadricNormals(quadric, GLU_SMOOTH);
 gluQuadricTexture(quadric, GL_TRUE);

 return TRUE;
}

void SetGLWindow(int width, int height)
{
  GLfloat ratio;

  if(height == 0)
    height = 1;

  ratio = (GLfloat)width/(GLfloat)height;

  glViewport(0, 0, (GLint)width, (GLint)height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f, ratio, 0.1f, 100.0f);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

}

void HandleKeyDown(SDL_keysym *keysym)
{
  switch(keysym->sym)
    {
    case SDLK_ESCAPE:
    case SDLK_q:
      Quit(0);
      break;
    case SDLK_F1:
      SDL_WM_ToggleFullScreen(surface);
      break;
    case SDLK_f:
      filter = (++filter)%3;
      break;
    case SDLK_l:
      light = !light;
      if(!light)
    glDisable(GL_LIGHTING);
      else
    glEnable(GL_LIGHTING);
      break;
    case SDLK_SPACE:
      object = (++object)%6;
      break;
    case SDLK_PAGEUP:
      if(keysym->mod & KMOD_SHIFT)
    z -= 0.08;
      else
    z -= 0.02;
      break;
    case SDLK_PAGEDOWN:
      if(keysym->mod & KMOD_SHIFT)
    z += 0.08;
      else
    z += 0.02;
      break;
    case SDLK_UP:
      if(keysym->mod & KMOD_SHIFT)
    xSpeed -= 0.04;
      else
    xSpeed -= 0.01;
      break;
    case SDLK_DOWN:
      if(keysym->mod & KMOD_SHIFT)
    xSpeed += 0.04;
      else
    xSpeed += 0.01;
      break;
    case SDLK_RIGHT:
      if(keysym->mod & KMOD_SHIFT)
    ySpeed += 0.04;
      else
    ySpeed += 0.01;
      break;
    case SDLK_LEFT:
      if(keysym->mod & KMOD_SHIFT)
    ySpeed -= 0.04;
      else
    ySpeed -= 0.01;
      break;
    default:
      break;
    }
}

void DrawCube(void)
{
  glBegin (GL_QUADS);
  {
    /* draw cube */

    /* each face drawn counter clockwise 
     * beginining from the bottom left corner */

    /* front face  */
    glNormal3f( 0.0, 0.0, 1.0);

    glTexCoord2f(1.0, 0.0);
    glVertex3f(-1.0, -1.0, 1.0);
    
    glTexCoord2f(0.0, 0.0);
    glVertex3f(1.0, -1.0, 1.0);
    
    glTexCoord2f(0.0, 1.0);
    glVertex3f(1.0, 1.0, 1.0);

    glTexCoord2f(1.0, 1.0);
    glVertex3f(-1.0, 1.0, 1.0);

    /* right face */
    glNormal3f(1.0, 0.0, 0.0);
    
    glTexCoord2f(1.0, 0.0);
    glVertex3f(1.0, -1.0, 1.0);
    
    glTexCoord2f(0.0, 0.0);
    glVertex3f(1.0, -1.0, -1.0);

    glTexCoord2f(0.0, 1.0);
    glVertex3f(1.0, 1.0, -1.0);
    
    glTexCoord2f(1.0, 1.0);
    glVertex3f(1.0, 1.0, 1.0);

    /* back face */
    glNormal3f(0.0, 0.0, -1.0);

    glTexCoord2f(1.0, 0.0);
    glVertex3f(1.0, -1.0, -1.0);

    glTexCoord2f(0.0, 0.0);
    glVertex3f(-1.0, -1.0, -1.0);
    
    glTexCoord2f(0.0, 1.0);
    glVertex3f(-1.0, 1.0, -1.0);
    
    glTexCoord2f(1.0, 1.0);
    glVertex3f(1.0, 1.0, -1.0);

    /* left face */
    glNormal3f(1.0, 0.0, 0.0);

    glTexCoord2f(1.0, 0.0);
    glVertex3f(-1.0, -1.0, -1.0);

    glTexCoord2f(0.0, 0.0);
    glVertex3f(-1.0, -1.0, 1.0);

    glTexCoord2f(0.0, 1.0);
    glVertex3f(-1.0, 1.0, 1.0);

    glTexCoord2f(1.0, 1.0);
    glVertex3f(-1.0, 1.0, -1.0);

    /* top face */
    glNormal3f(0.0, 1.0, 0.0);
    
    glTexCoord2f(1.0, 0.0);
    glVertex3f(-1.0, 1.0, 1.0);

    glTexCoord2f(0.0, 0.0);
    glVertex3f(1.0, 1.0, 1.0);

    glTexCoord2f(0.0, 1.0);
    glVertex3f(1.0, 1.0, -1.0);

    glTexCoord2f(1.0, 1.0);
    glVertex3f(-1.0, 1.0, -1.0);

    /* bottom face */
    glNormal3f(0.0, -1.0, 0.0);

    glTexCoord2f(1.0, 0.0);
    glVertex3f(-1.0, -1.0, -1.0);

    glTexCoord2f(0.0, 0.0);
    glVertex3f(1.0, -1.0, -1.0);

    glTexCoord2f(0.0, 1.0);
    glVertex3f(1.0, -1.0, 1.0);

    glTexCoord2f(1.0, 1.0);
    glVertex3f(-1.0, -1.0, 1.0);
  }
  glEnd();
}

void DrawScreen(void)
{
  static GLint timeA, timeB, frames = 0;
  static GLfloat fps, seconds = 0.0;

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glLoadIdentity();

  glTranslatef(0.0, 0.0, z);

  glRotatef(xRot, 1.0, 0.0, 0.0);
  glRotatef(yRot, 0.0, 1.0, 0.0);

  glBindTexture(GL_TEXTURE_2D, texture[filter]);

  switch(object)
    {
    case 0:
      glTranslatef(0.0, 0.0, 1.0);
      gluDisk(quadric, 0.5, 1.0, 32, 32);
      glTranslatef(0.0, 0.0, -1.5f);
      gluCylinder(quadric, 1.0, 1.0, 3.0, 32, 32);
      break;
    case 1:
      gluDisk(quadric, 0.5, 1.5, 32, 32);
      break;
    case 2:
      DrawCube();
      break;
    case 3:
      gluSphere(quadric, 1.3f, 32, 32);
      break;
    case 4:
      /* draw a cone */
      glTranslatef(0.0, 0.0, -1.5);
      gluCylinder(quadric, 1.0, 0.0, 3.0, 32, 32);
      break;
    case 5:
      part1 += p1;
      part2 += p2;
      if(part1 > 359)
    {
     part1 = 0;
     p1 = 0;
     p2 = 1;
     part2 = 0;
    }
      if(part2 > 359)
    {
     p1 = 1;
     p2 = 0;
    }
      gluPartialDisk(quadric, 0.5, 1.5, 32, 32, part1, part2-part1);
      break;
    }

  SDL_GL_SwapBuffers();

  frames++;
  timeB = SDL_GetTicks();
  if(timeB - timeA >= 5000)
    {
      seconds = (timeB - timeA) / 1000.0;
      fps = frames / seconds;
      fprintf(stdout, "%d frames in %g seconds = %g fps.\n", frames, seconds, 
fps);
      timeA = timeB;
      frames = 0;
    }

  xRot += xSpeed;
  yRot += ySpeed;
 
}

int main(int argc, char **argv)
{

  int videoFlags;
  int done = FALSE;

  SDL_Event event;

  int isActive = TRUE;

  if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
      fprintf(stderr,"Unable to init video: %s\n", SDL_GetError());
      Quit(1);
    }

  videoFlags = 
    SDL_OPENGL | 
    SDL_GL_DOUBLEBUFFER | 
    SDL_HWPALETTE | 
    SDL_RESIZABLE | 
    SDL_HWSURFACE | 
    SDL_HWACCEL;

  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

  if((surface = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 
videoFlags)) == NULL)
    {
      fprintf(stderr,"Unable to grab surface: %s\n",SDL_GetError());
      Quit(1);
    }

  if((SDL_EnableKeyRepeat(100, SDL_DEFAULT_REPEAT_INTERVAL)) > 0)
    {
      fprintf(stderr,"Unable to setup keyboad repeat: %s\n",SDL_GetError());
      Quit(1);
    }

  if(!InitGL())
    {
      fprintf(stderr,"Unable to init OpenGL: %s\n", SDL_GetError());
    }

  SetGLWindow(SCREEN_WIDTH, SCREEN_HEIGHT);

  while(!done)
    {
      while(SDL_PollEvent(&event))
    {
     switch(event.type)
      {
      case SDL_ACTIVEEVENT:
       if(event.active.gain == 0)
        isActive = FALSE;
       else
        isActive = TRUE;
       break;
      case SDL_VIDEORESIZE:
       if((surface = SDL_SetVideoMode(event.resize.w,
                       event.resize.h,
                       SCREEN_BPP,
                       videoFlags)) == NULL)
        {
         fprintf(stderr,"Unable to grab surface after resize event: 
%s\n",SDL_GetError());
         Quit(1);
        }
       SetGLWindow(event.resize.w, event.resize.h);
       break;
      case SDL_KEYDOWN:
       HandleKeyDown(&event.key.keysym);
       break;
      case SDL_QUIT:
       done = TRUE;
       break;
      default:
       break;
      }
    }
      if(isActive)
    DrawScreen();
    }

  Quit(42);
  return 0;
}


-- 
They that can give up essential liberty to obtain a little temporary safety 
deserve neither liberty nor safety.  --Benjamin Franklin




More information about the SDL mailing list