////////////////////////////////////////////////////////////////////// // XLogical - A puzzle game // // Copyright (C) 2000 Neil Brown, Tom Warkentin // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // or at the website: http://www.gnu.org // //////////////////////////////////////////////////////////////////////// #include #include #include #include #ifdef WIN32 #else #include #include #endif #include #include #include "sdl_graph.h" #include "SDL_image.h" #include "exception.h" #include "defs.h" #include "graph_images.h" #include "properties.h" //#define DEBUG_FUNC const Uint32 kTicksPerLoop = 30; SDL_Surface *tile_images[NUM_DEFAULT_ICONS]; SDL_Surface *mainScreen; SDL_Surface *bgScreen; listrectList; int currentBGPixmap; void load_images( void ); void draw_background( void ); keysyms keycode_to_keysym( unsigned int ); Csdl_graph::Csdl_graph( void ) { // Load up the fonts fLoFont = new CText; fLoFont->set_font_info( BMP_FONT_1, 30, 30, 5, ' ', 'Z' ); fHiFont = new CText; fHiFont->set_font_info( BMP_FONT_2, 30, 30, 5, ' ', 'Z' ); } int Csdl_graph::graph_setup( int *argc, char ***argv, int width, int height ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_setup( )" << endl; #endif int fullscreen = 0; int depth = 0; // Set our boundaries reqWidth = width; reqHeight = height; string videoMode=properties::instance().get( "video.mode" ); if (videoMode == "fullscreen") { fullscreen = 1; get_std_resolution( width, height, mainWidth, mainHeight ); if ((mainWidth <= 0) || (mainHeight <= 0)) { ThrowEx( "no supported resolutions found" ); } mainXOffset = (mainWidth - width) / 2; mainYOffset = (mainHeight - height) / 2; } else { mainXOffset = 0; mainYOffset = 0; mainWidth = reqWidth; mainHeight = reqHeight; } // See if we can set up a video mode of any kind if( SDL_InitSubSystem( SDL_INIT_VIDEO ) < 0 ) { throw( CXLException( "Could not init video", "ack", 0 ) ); } // Try to get our requested depth if( fullscreen == 1 ) { depth = SDL_VideoModeOK( mainWidth, mainHeight, 16, SDL_FULLSCREEN ); if( depth ) { mainScreen = SDL_SetVideoMode( mainWidth, mainHeight, 16, SDL_FULLSCREEN ); } } else { depth = SDL_VideoModeOK( mainWidth, mainHeight, 16, 0 ); if( depth ) { mainScreen = SDL_SetVideoMode( mainWidth, mainHeight, 16, 0 ); } } // Set the window manager caption stuff SDL_WM_SetCaption( "XLogical", "XLogical" ); // Load up the image tiles load_images( ); // Set up the background screen bgScreen = SDL_CreateRGBSurface( SDL_HWSURFACE, mainWidth, mainHeight, 16, 0, 0, 0, 0); bgScreen = SDL_DisplayFormat( bgScreen ); SDL_FillRect( bgScreen, NULL, 0 ); return( 0 ); } void Csdl_graph::graph_start( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_start( )" << endl; #endif SDL_Event event; Uint32 start, elapsed; bool done = false; while( !done ) { start = SDL_GetTicks(); game_loop( ); while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_KEYDOWN: if( keyPressFunc == NULL ) { break; } keyPressFunc( keycode_to_keysym( event.key.keysym.sym ) ); break; case SDL_MOUSEMOTION: break; case SDL_MOUSEBUTTONDOWN: clickFunc( event.button.x - mainXOffset, event.button.y - mainYOffset, event.button.button ); break; case SDL_QUIT: done = true; break; default: break; } } if( rectList.size( ) > 0 ) { SDL_Rect *rects; int count = 0; rects = new SDL_Rect[ rectList.size( ) ]; list::iterator it = rectList.begin( ); for( ; it != rectList.end( ); it++ ) { rects[count].x = (*it)->x; rects[count].y = (*it)->y; rects[count].w = (*it)->w; rects[count].h = (*it)->h; #ifdef DEBUG_DRAW cerr << "("<< rects[count].x; cerr << ","<< rects[count].y << ") "; cerr << "("<< rects[count].w; cerr << ","<< rects[count].h << ") " << endl;; #endif count++; delete (*it); } rectList.clear( ); SDL_UpdateRects( mainScreen, count - 1, rects ); delete [] rects; } elapsed = SDL_GetTicks() - start; if (elapsed < kTicksPerLoop) { SDL_Delay( kTicksPerLoop - elapsed ); } } } void load_images( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : load_images( )" << endl; #endif SDL_Surface *image; for(int i = 0; i < NUM_DEFAULT_ICONS; i++ ) { image = IMG_Load( imageFiles[i] ); if( image == NULL ) { throw( CXLException( SDL_GetError( ), imageFiles[i], 0 ) ); } if( SDL_SetColorKey( image, (SDL_SRCCOLORKEY | SDL_RLEACCEL ), SDL_MapRGB( image->format, 0x00, 0xFF, 0xFF )) == -1 ) { throw( CXLException( "making transparent ", imageFiles[i], 0 ) ); } tile_images[i] = SDL_DisplayFormat( image ); if( tile_images[i] == NULL ) { throw( CXLException( "converting format ", imageFiles[i], 0 ) ); } SDL_FreeSurface( image ); } } void Csdl_graph::graph_reload( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_reload( )" << endl; #endif if( rectList.size( ) > 0 ) { list::iterator it = rectList.begin( ); for( ; it != rectList.end( ); it++ ) { delete (*it); } rectList.clear( ); } (void) SDL_QuitSubSystem( SDL_INIT_VIDEO ); int fullscreen = 0; int depth = 0; string videoMode=properties::instance().get( "video.mode" ); if (videoMode == "fullscreen") { fullscreen = 1; get_std_resolution( reqWidth, reqHeight, mainWidth, mainHeight ); if ((mainWidth <= 0) || (mainHeight <= 0)) { ThrowEx( "no supported resolutions found" ); } mainXOffset = (mainWidth - reqWidth) / 2; mainYOffset = (mainHeight - reqHeight) / 2; } else { mainXOffset = 0; mainYOffset = 0; mainWidth = reqWidth; mainHeight = reqHeight; } // See if we can set up a video mode of any kind if( SDL_InitSubSystem( SDL_INIT_VIDEO ) < 0 ) { throw( CXLException( "Could not init video", "ack", 0 ) ); } // Try to get our requested depth if( fullscreen == 1 ) { depth = SDL_VideoModeOK( mainWidth, mainHeight, 16, SDL_FULLSCREEN ); if( depth ) { mainScreen = SDL_SetVideoMode( mainWidth, mainHeight, 16, SDL_FULLSCREEN ); } } else { depth = SDL_VideoModeOK( mainWidth, mainHeight, 16, 0 ); if( depth ) { mainScreen = SDL_SetVideoMode( mainWidth, mainHeight, 16, 0 ); } } // Set the window manager caption stuff SDL_WM_SetCaption( "XLogical", "XLogical" ); // Load up the image tiles load_images( ); // Set up the background screen bgScreen = SDL_CreateRGBSurface( SDL_HWSURFACE, mainWidth, mainHeight, 16, 0, 0, 0, 0); bgScreen = SDL_DisplayFormat( bgScreen ); SDL_FillRect( bgScreen, NULL, 0 ); currentBGPixmap = 0; reloadFunc(); } void Csdl_graph::graph_shutdown( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_shutdown( )" << endl; #endif (void) SDL_QuitSubSystem( SDL_INIT_VIDEO ); } void Csdl_graph::game_loop( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " sdl_graph game_loop( )" << endl; #endif loopFunc( ); } void Csdl_graph::graph_refresh( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_refresh( )" << endl; #endif SDL_Rect *dstRect = new SDL_Rect; // Refresh the whole thing dstRect->x = 0; dstRect->y = 0; dstRect->w = mainWidth; dstRect->h = mainHeight; // Update the main display SDL_BlitSurface( bgScreen, dstRect, mainScreen, dstRect ); } void Csdl_graph::graph_set_background( int pm ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_set_background( )" << endl; #endif // Return if there's no change if( pm == currentBGPixmap ) { return; } // Erase the old graph_clear_rect_perm( 0, 0, mainWidth, mainHeight ); currentBGPixmap = pm; draw_background( ); } void Csdl_graph::draw_background( void ) { #ifdef DEBUG_DRAW cerr << __FILE__ << " : draw_background( )" << endl; #endif SDL_Rect srcRect; SDL_Rect *dstRect = new SDL_Rect; int width = tile_images[currentBGPixmap]->w; int height = tile_images[currentBGPixmap]->h; int row; int col; int yOffset; // check for special case where background is size of screen if (height >= reqHeight) { yOffset = 0; } else { yOffset = 50; } srcRect.x = 0; srcRect.y = 0; srcRect.w = width; srcRect.h = height; dstRect->w = width; dstRect->h = height; // Loop through the Clevel_map object // and draw background squares int tileAreaHeight = reqHeight - yOffset; for( row = 0; row < tileAreaHeight; row+=height ) { for( col = 0; col < reqWidth; col+=width ) { dstRect->x = col + mainXOffset; dstRect->y = row + yOffset + mainYOffset; SDL_BlitSurface( tile_images[currentBGPixmap], &srcRect, bgScreen, dstRect ); } } // Refresh the whole thing dstRect->x = mainXOffset; dstRect->y = mainYOffset; dstRect->w = reqWidth; dstRect->h = reqHeight; // Update the main display SDL_BlitSurface( bgScreen, dstRect, mainScreen, dstRect ); // Update the rectangle list rectList.insert( rectList.end( ), dstRect ); } // A smaller draw routine with some defaults // Hopefully this will be used in most cases void Csdl_graph::graph_draw( int pm, int ulX, int ulY ) { #ifdef DEBUG_DRAW cerr << __FILE__ << " : Csdl_graph::graph_draw( )" << endl; #endif graph_draw_pixmap( pm, 0, 0, ulX, ulY, 0, 0, USE_MASK ); } void Csdl_graph::graph_draw_pixmap( int pm, int srcX, int srcY, int destX, int destY, int xSize, int ySize, long flags ) { #ifdef DEBUG_DRAW cerr << __FILE__ << " : Csdl_graph::graph_draw_pixmap("; cerr << pm << "," << srcX << "," << srcY << "," ; cerr << destX << "," << destY << "," ; cerr << xSize << "," << ySize << ")" << endl; #endif SDL_Rect srcRect; SDL_Rect *dstRect = new SDL_Rect; srcRect.x = srcX; srcRect.y = srcY; srcRect.w = xSize==0?tile_images[pm]->w:xSize; srcRect.h = ySize==0?tile_images[pm]->h:ySize; dstRect->x = mainXOffset + destX; dstRect->y = mainYOffset + destY; dstRect->w = xSize==0?tile_images[pm]->w:xSize; dstRect->h = ySize==0?tile_images[pm]->h:ySize; SDL_BlitSurface( tile_images[pm], &srcRect, mainScreen, dstRect ); rectList.insert( rectList.end( ), dstRect ); } void Csdl_graph::graph_draw_perm( int pm, int srcX, int srcY, int destX, int destY, int xSize, int ySize ) { #ifdef DEBUG_DRAW cerr << __FILE__ << " : Csdl_graph::graph_draw_pixmap("; cerr << pm << "," << srcX << "," << srcY << "," ; cerr << destX << "," << destY << "," ; cerr << xSize << "," << ySize << ")" << endl; #endif SDL_Rect srcRect; SDL_Rect *dstRect = new SDL_Rect;; srcRect.x = srcX; srcRect.y = srcY; srcRect.w = xSize==0?tile_images[pm]->w:xSize; srcRect.h = ySize==0?tile_images[pm]->h:ySize; dstRect->x = destX + mainXOffset; dstRect->y = destY + mainYOffset; dstRect->w = xSize==0?tile_images[pm]->w:xSize; dstRect->h = ySize==0?tile_images[pm]->h:ySize; SDL_BlitSurface( tile_images[pm], &srcRect, bgScreen, dstRect ); } void Csdl_graph::graph_draw_rect( int ulx, int uly, int width, int height ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_draw_rect( ) " << endl; #endif } void Csdl_graph::graph_copy_area( int srcULX, int srcULY, int dstULX, int dstULY, int width, int height ) { #ifdef DEBUG_DRAW cerr << __FILE__ << " : Csdl_graph::graph_copy_area("; cerr << srcULX << "," << srcULY << "," ; cerr << dstULX << "," << dstULY << "," ; cerr << width << "," << height << ")" << endl; #endif SDL_Rect srcRect; SDL_Rect *dstRect = new SDL_Rect; srcRect.x = mainXOffset + srcULX; srcRect.y = mainYOffset + srcULY; srcRect.w = width; srcRect.h = height; dstRect->x = mainXOffset + dstULX; dstRect->y = mainYOffset + dstULY; dstRect->w = width; dstRect->h = height; SDL_BlitSurface( mainScreen, &srcRect, mainScreen, dstRect ); rectList.insert( rectList.end( ), dstRect ); } void Csdl_graph::graph_clear( void ) { #ifdef DEBUG_DRAW cerr << __FILE__ << " : Csdl_graph::graph_clear( )" << endl; #endif Uint32 color = 0; SDL_FillRect( mainScreen, NULL, color ); } void Csdl_graph::graph_clear_rect( int ulx, int uly, int width, int height ) { #ifdef DEBUG_DRAW cerr << __FILE__ << " : Csdl_graph::graph_clear_rect( ) " << endl; #endif SDL_Rect *dstRect = new SDL_Rect; Uint32 color = 0; dstRect->x = mainXOffset + ulx; dstRect->y = mainYOffset + uly; dstRect->w = width; dstRect->h = height; SDL_FillRect( mainScreen, dstRect, color ); rectList.insert( rectList.end( ), dstRect ); } void Csdl_graph::graph_clear_rect_perm( int ulx, int uly, int width, int height ) { #ifdef DEBUG_DRAW cerr << __FILE__ << " : Csdl_graph::graph_clear_rect( ) " << endl; #endif SDL_Rect *dstRect = new SDL_Rect; Uint32 color = 0; dstRect->x = mainXOffset + ulx; dstRect->y = mainYOffset + uly; dstRect->w = width; dstRect->h = height; SDL_FillRect( bgScreen, dstRect, color ); rectList.insert( rectList.end( ), dstRect ); } void Csdl_graph::graph_erase_rect( int ulx, int uly, int width, int height ) { #ifdef DEBUG_DRAW cerr << __FILE__ << " : Csdl_graph::graph_erase_rect( ) " << endl; #endif SDL_Rect *dstRect = new SDL_Rect; dstRect->x = mainXOffset + ulx; dstRect->y = mainYOffset + uly; dstRect->w = width; dstRect->h = height; SDL_BlitSurface( bgScreen, dstRect, mainScreen, dstRect ); rectList.insert( rectList.end( ), dstRect ); } void Csdl_graph::graph_erase_pixmap( int pm, int ulx, int uly ) { #ifdef DEBUG_DRAW cerr << __FILE__ << " : Csdl_graph::graph_erase_pixmap( ) " << endl; #endif SDL_Rect *dstRect = new SDL_Rect; dstRect->x = mainXOffset + ulx; dstRect->y = mainYOffset + uly; dstRect->w = tile_images[pm]->w; dstRect->h = tile_images[pm]->h; SDL_BlitSurface( bgScreen, dstRect, mainScreen, dstRect ); rectList.insert( rectList.end( ), dstRect ); } void Csdl_graph::graph_set_reload_func( void(*func)(void) ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_set_reload_func( )" << endl; #endif reloadFunc = func; } void Csdl_graph::graph_set_loop_func( void(*lFunc)(void) ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_set_loop_func( )" << endl; #endif loopFunc = lFunc; } void Csdl_graph::graph_set_click_func( void(*cFunc)(int, int, int) ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_set_click_func( )" << endl; #endif clickFunc = cFunc; } void Csdl_graph::graph_set_key_press_func( key_press_func_t kFunc ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " : Csdl_graph::graph_set_key_press_func( )" << endl; #endif keyPressFunc = kFunc; } int Csdl_graph::graph_main_width( void ) { return( reqWidth ); } int Csdl_graph::graph_main_height( void ) { return( reqHeight ); } CText * Csdl_graph::graph_hi_font( void ) { return( fHiFont ); } CText * Csdl_graph::graph_lo_font( void ) { return( fLoFont ); } ulong Csdl_graph::graph_get_time( void ) { return( SDL_GetTicks() ); } void Csdl_graph::graph_delay( long delay ) { SDL_Delay( delay * 1000 ); } keysyms keycode_to_keysym( unsigned int keycode ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " :keycode_to_keysym( )" << endl; #endif switch( keycode ) { case SDLK_a: return( eA ); case SDLK_b: return( eB ); case SDLK_c: return( eC ); case SDLK_d: return( eD ); case SDLK_e: return( eE ); case SDLK_f: return( eF ); case SDLK_g: return( eG ); case SDLK_h: return( eH ); case SDLK_i: return( eI ); case SDLK_j: return( eJ ); case SDLK_k: return( eK ); case SDLK_l: return( eL ); case SDLK_m: return( eM ); case SDLK_n: return( eN ); case SDLK_o: return( eO ); case SDLK_p: return( eP ); case SDLK_q: return( eQ ); case SDLK_r: return( eR ); case SDLK_s: return( eS ); case SDLK_t: return( eT ); case SDLK_u: return( eU ); case SDLK_v: return( eV ); case SDLK_w: return( eW ); case SDLK_x: return( eX ); case SDLK_y: return( eY ); case SDLK_z: return( eZ ); case SDLK_0: return( e0 ); case SDLK_1: return( e1 ); case SDLK_2: return( e2 ); case SDLK_3: return( e3 ); case SDLK_4: return( e4 ); case SDLK_5: return( e5 ); case SDLK_6: return( e6 ); case SDLK_7: return( e7 ); case SDLK_8: return( e8 ); case SDLK_9: return( e9 ); case SDLK_ESCAPE: return( eEsc ); case SDLK_UP: return( eUp ); case SDLK_DOWN: return( eDown ); case SDLK_LEFT: return( eLeft ); case SDLK_RIGHT: return( eRight ); case SDLK_SPACE: return( eSpace ); case SDLK_BACKSPACE: return( eBackSpace ); case SDLK_DELETE: return( eDelete ); case SDLK_PERIOD: return( ePeriod ); case SDLK_RETURN: return( eEnter ); } return( eSpace ); } void Csdl_graph::get_std_resolution( int inWidth, int inHeight, int& stdWidth, int& stdHeight ) { static struct { int width; int height; } stdResolutions[] = { { 640, 480 }, { 800, 600 }, {1024, 768 }, {1280, 1024}, {1600, 1200}, { -1, -1} // must be last }; int i; for(i=0; (stdResolutions[i].width != -1); i += 1) { if ((inWidth <= stdResolutions[i].width) && (inHeight <= stdResolutions[i].height)) { break; } } stdWidth = stdResolutions[i].width; stdHeight = stdResolutions[i].height; }