Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) SDL example 5: moving an image over a background image in a 2D OpenGL environment

 

This SDL example shows an image moving over a background image, like this screenshot (png).

 

Operating system: Ubuntu

IDE: Qt Creator 2.0.0

Project type: Qt4 Console Application

Selected required modules: QtCore

Compiler: G++ 4.4.1

Additional libraries: SDL, OpenGL, Boost

 

 

 

 

 

Qt project file

 

#-------------------------------------------------
#
# Project created by QtCreator 2010-07-17T14:57:33
#
#-------------------------------------------------

QT += core

QT -= gui

TARGET = CppSdlExample5
CONFIG += console
CONFIG -= app_bundle

TEMPLATE = app

LIBS += -L/usr/local/lib -lSDL
LIBS += -L/usr/local/lib -lGL
SOURCES += main.cpp

 

 

 

 

 

Source code

 

#include <cassert>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <boost/timer.hpp>
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>

int main()
{
  const bool full_screen = false;

  //Initialization
  if( SDL_Init( SDL_INIT_VIDEO) < 0 )
  {
    assert(!"Assume SDL initialization does not fail");
  }

  //Perform SDL_Quit at program exit
  std::atexit(SDL_Quit);

  //Load the background
  SDL_Surface * const background = SDL_LoadBMP("Background512x256.bmp");
  assert(background && "Assume background image is found in same folder as binary");
  int screen_width = background->w;
  int screen_height = background->h;

  // Check that the image's dimensions are a power of 2
  if ( (screen_width &amp; (screen_width - 1)) != 0 )
  {
    std::clog << "warning: background image width is not a power of 2\n";
  }
  if ( (screen_height &amp; (screen_height - 1)) != 0 )
  {
    std::clog << "warning: background image width is not a power of 2\n";
  }

  //Create screen of same size as background
  const int bits_per_pixel = 32;
  SDL_Surface * const screen = SDL_SetVideoMode( screen_width, screen_height, bits_per_pixel, SDL_OPENGL | (full_screen ? SDL_FULLSCREEN : 0));
  assert(screen && "Assume SDL video mode setting does not fail");
  if (full_screen)
  {
    screen_width = screen->w;
    screen_height = screen->h;
  }

  //Load the sprite
  SDL_Surface * const sprite = SDL_LoadBMP("Butterfly128x128_Alpha.bmp");
  assert(background && "Assume sprite image is found in same folder as binary");


  //Initialize OpenGL
  glClearColor( 0, 0, 0, 0 );
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glOrtho( 0, screen_width, screen_height, 0, -1, 1 );
  glMatrixMode( GL_MODELVIEW );
  glLoadIdentity();

  if( glGetError() != GL_NO_ERROR )
  {
    assert(!"Assume OpenGL initialization does not fail");
  }

  GLenum texture_format;
  const GLint bytes_per_pixel = background->format->BytesPerPixel;
  switch (bytes_per_pixel)
  {
    case 3: texture_format = (SDL_BYTEORDER != SDL_BIG_ENDIAN ? GL_BGR : GL_RGB ); break;
    case 4: texture_format = (SDL_BYTEORDER != SDL_BIG_ENDIAN ? GL_BGRA : GL_RGBA); break;
    default: assert(!"Should not get here");
  }
  //Generate a texture object handle for the background
  GLuint texture_background;
  glGenTextures( 1, &texture_background);
  // Bind the texture object
  glBindTexture( GL_TEXTURE_2D, texture_background);
  // Set the texture's stretching properties
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  // Edit the texture object's image data using the information SDL_Surface gives us
  glTexImage2D( GL_TEXTURE_2D, 0, bytes_per_pixel, background->w, background->h, 0,
                texture_format, GL_UNSIGNED_BYTE, background->pixels );

  //Generate a texture object handle for the sprite
  GLuint texture_sprite;
  glGenTextures( 1, &texture_sprite);
  // Bind the texture object
  glBindTexture( GL_TEXTURE_2D, texture_sprite);
  // Set the texture's stretching properties
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

  // Edit the texture object's image data using the information SDL_Surface gives us
  glTexImage2D( GL_TEXTURE_2D, 0, bytes_per_pixel, sprite->w, sprite->h, 0,
                GL_BGRA, GL_UNSIGNED_BYTE, sprite->pixels );

  //Set up sprite
  const int sprite_width = sprite->w;
  const int sprite_height = sprite->h;
  int sprite_x = (screen_width / 2) - (sprite_width / 2);
  int sprite_y = (screen_height / 2) - (sprite_height / 2);
  int sprite_dx = 1;
  int sprite_dy = 1;
  const int frames_per_second = 60;
  const int ticks_per_second = 1000 / frames_per_second;

  while (1)
  {
    //Use timer to keep frame rate constant
    boost::timer timer;

    //Enable user to terminate program
    SDL_Event event;
    SDL_PollEvent( &event );
    if( event.type == SDL_KEYDOWN
      || event.type == SDL_MOUSEBUTTONDOWN
      || event.type == SDL_QUIT) break;


    //Move the square
    sprite_x+=sprite_dx;
    sprite_y+=sprite_dy;
    //Make the square bounce
    if (sprite_x < 0 || sprite_x + sprite_width > screen_width ) sprite_dx = -sprite_dx;
    if (sprite_y < 0 || sprite_y + sprite_height > screen_height ) sprite_dy = -sprite_dy;

    //Clear the screen
    glClear( GL_COLOR_BUFFER_BIT );

    //Draw background
    glBindTexture( GL_TEXTURE_2D, texture_background );

    //glBlendFunc(GL_ZERO, GL_ZERO);
    //glDisable(GL_BLEND);

    glEnable(GL_TEXTURE_2D);
    glBegin( GL_QUADS );
    glTexCoord2i( 0, 0 ); glVertex2i( 0 , 0 );
    glTexCoord2i( 1, 0 ); glVertex2i( screen_width, 0 );
    glTexCoord2i( 1, 1 ); glVertex2i( screen_width, screen_height);
    glTexCoord2i( 0, 1 ); glVertex2i( 0 , screen_height);
    glEnd();

    //Draw the sprite
    glBindTexture( GL_TEXTURE_2D, texture_sprite );
    glBegin( GL_QUADS );
    glTexCoord2i( 0, 0 ); glVertex2i( sprite_x , sprite_y );
    glTexCoord2i( 1, 0 ); glVertex2i( sprite_x + sprite_width, sprite_y );
    glTexCoord2i( 1, 1 ); glVertex2i( sprite_x + sprite_width, sprite_y + sprite_height);
    glTexCoord2i( 0, 1 ); glVertex2i( sprite_x , sprite_y + sprite_height);
    glEnd();
    glDisable(GL_TEXTURE_2D);

    //Reset
    glLoadIdentity();

    //Update screen
    SDL_GL_SwapBuffers();

    //Keep frame rate constant
    const int ticks_elapsed = static_cast<int>(timer.elapsed() * 1000.0);
    if (ticks_elapsed < ticks_per_second)
    {
      SDL_Delay( ticks_per_second - ticks_elapsed );
    }
  }

  SDL_FreeSurface( screen );
  glDeleteTextures( 1, &texture_background );
}


 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict