src/graphic/surface.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  *  Wormux is a convivial mass murder game.
00003  *  Copyright (C) 2001-2004 Lawrence Azzoug.
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A ARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU GeneralPublic License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00018  ******************************************************************************
00019  * Handle a SDL Surface
00020  *****************************************************************************/
00021 
00022 #include "surface.h"
00023 #include <SDL.h>
00024 #include <SDL_endian.h>
00025 #include <SDL_gfxPrimitives.h>
00026 #include <SDL_image.h>
00027 #include <SDL_rotozoom.h>
00028 #include "../tool/debug.h"
00029 #include "../tool/error.h"
00030 #include "../tool/i18n.h"
00031 #include "../include/base.h"
00032 
00038 Surface::Surface(){
00039         surface = NULL;
00040         autoFree = true;
00041 }
00042 
00048 Surface::Surface(SDL_Surface *sdl_surface){
00049         surface = sdl_surface;
00050         autoFree = true;
00051 }
00052 
00061 Surface::Surface(const Point2i &size, Uint32 flags, bool useAlpha){
00062         surface = NULL;
00063         autoFree = true;
00064         NewSurface(size, flags, useAlpha);
00065 }
00066 
00072 Surface::Surface(const std::string &filename){
00073         surface = NULL;
00074         autoFree = true;
00075         if( !ImgLoad(filename) )
00076                 Error( Format("Unable to open image file : %s", filename.c_str() ) );
00077 }
00078 
00084 Surface::Surface(const Surface &src){
00085         surface = src.surface;
00086         autoFree = true;
00087         if( !IsNull() )
00088                 surface->refcount++;
00089 }
00090 
00096 Surface::~Surface(){
00097         AutoFree();
00098 }
00099 
00100 Surface &Surface::operator=(const Surface & src){
00101         AutoFree();
00102         surface = src.surface;
00103         if( !IsNull() )
00104                 surface->refcount++;
00105 
00106         return *this;
00107 }
00108 
00114 void Surface::Free(){
00115         if( !IsNull() ){
00116                 SDL_FreeSurface( surface );
00117                 surface = NULL;
00118         }
00119 }
00120 
00121 void Surface::AutoFree(){
00122         if( autoFree )
00123                 Free();
00124 }
00125 
00132 void Surface::SetAutoFree( bool newAutoFree ){
00133         autoFree = newAutoFree;
00134 }
00135 
00141 SDL_Surface *Surface::GetSurface(){
00142         return surface;
00143 }
00144 
00151 void Surface::SetSurface(SDL_Surface *newSurface, bool freePrevious){
00152         if( freePrevious )
00153                 Free();
00154 
00155         surface = newSurface;
00156 }
00157 
00165 void Surface::NewSurface(const Point2i &size, Uint32 flags, bool useAlpha){
00166         Uint32 alphaMask;
00167         Uint32 redMask;
00168         Uint32 greenMask;
00169         Uint32 blueMask;
00170 
00171         if( autoFree )
00172                 Free();
00173 
00174 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
00175         redMask = 0xff000000;
00176         greenMask = 0x00ff0000;
00177         blueMask = 0x0000ff00;
00178         alphaMask =     0x000000ff;
00179 #else
00180         redMask = 0x000000ff;
00181         greenMask = 0x0000ff00;
00182         blueMask = 0x00ff0000;
00183         alphaMask = 0xff000000;
00184 #endif
00185 
00186         if( !useAlpha )
00187                 alphaMask = 0;
00188 
00189         surface = SDL_CreateRGBSurface(flags, size.x, size.y, 32,
00190                         redMask, greenMask, blueMask, alphaMask );
00191 
00192         if( surface == NULL )
00193                 Error( std::string("Can't create SDL RGBA surface: ") + SDL_GetError() );
00194 }
00195 
00200 int Surface::SetAlpha(Uint32 flags, Uint8 alpha){
00201         return SDL_SetAlpha( surface, flags, alpha );
00202 }
00203 
00208 int Surface::Lock(){
00209         return SDL_LockSurface( surface );
00210 }
00211 
00216 void Surface::Unlock(){
00217         SDL_UnlockSurface( surface );
00218 }
00219 
00220 int Surface::Blit(const Surface& src, SDL_Rect *srcRect, SDL_Rect *dstRect){
00221         return SDL_BlitSurface( src.surface, srcRect, surface, dstRect );
00222 }
00223 
00229 int Surface::Blit(const Surface& src){
00230         return Blit(src, NULL, NULL);
00231 }
00232 
00239 int Surface::Blit(const Surface& src, const Point2i &dst){
00240         SDL_Rect dstRect = GetSDLRect( dst );;
00241 
00242         return Blit(src, NULL, &dstRect);
00243 }
00244 
00252 int Surface::Blit(const Surface& src, const Rectanglei &srcRect, const Point2i &dstPoint){
00253         SDL_Rect sdlSrcRect = GetSDLRect( srcRect );
00254         SDL_Rect sdlDstRect = GetSDLRect( dstPoint );
00255 
00256         return Blit(src, &sdlSrcRect, &sdlDstRect);
00257 }
00258 
00264 int Surface::SetColorKey(Uint32 flag, Uint32 key){
00265         return SDL_SetColorKey( surface, flag, key );
00266 }
00267 
00277 int Surface::SetColorKey(Uint32 flag, Uint8 r, Uint8 g, Uint8 b, Uint8 a){
00278         return SetColorKey( flag, MapRGBA(r, g, b, a) );
00279 }
00280 
00288 void Surface::GetRGBA(Uint32 color, Uint8 &r, Uint8 &g, Uint8 &b, Uint8 &a) const
00289 {
00290   SDL_GetRGBA(color, surface->format, &r, &g, &b, &a);
00291 }
00292 
00299 Uint32 Surface::MapRGBA(Uint8 r, Uint8 g, Uint8 b, Uint8 a) const
00300 {
00301   return SDL_MapRGBA(surface->format, r, g, b, a);
00302 }
00303 
00308 Color Surface::GetColor(Uint32 color) const
00309 {
00310   Uint8 r, g, b, a;
00311   GetRGBA(color, r, g, b, a);
00312   return Color(r, g, b, a);
00313 }
00314 
00319 Uint32 Surface::MapColor(Color color) const
00320 {
00321   return MapRGBA(color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00322 }
00323 
00327 void Surface::SetClipRect(const Rectanglei &rect){
00328         SDL_Rect sdlRect = GetSDLRect( rect );
00329         SDL_SetClipRect( surface, &sdlRect );
00330 }
00331 
00332 void Surface::Flip(){
00333         SDL_Flip( surface );
00334 }
00335 
00336 int Surface::BoxColor(const Rectanglei &rect, const Color &color){
00337         if( rect.IsSizeZero() )
00338                 return 0;
00339 
00340         Point2i ptBR = rect.GetBottomRightPoint();
00341 
00342         return boxRGBA( surface, rect.GetPositionX(), rect.GetPositionY(), ptBR.GetX(), ptBR.GetY(), color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00343 }
00344 
00345 int Surface::RectangleColor(const Rectanglei &rect, const Color &color, const uint &border_size)
00346 {
00347   if( rect.IsSizeZero() )
00348     return 0;
00349 
00350   Point2i ptBR = rect.GetBottomRightPoint();
00351 
00352   if (border_size == 1)
00353     return rectangleRGBA( surface, rect.GetPositionX(), rect.GetPositionY(), ptBR.GetX(), ptBR.GetY(), color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00354 
00355   // top border
00356   boxRGBA (surface,
00357            rect.GetPositionX(), rect.GetPositionY(), ptBR.GetX(), rect.GetPositionY()+border_size,
00358            color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00359 
00360   // bottom border
00361   boxRGBA (surface,
00362            rect.GetPositionX(), ptBR.GetY() - border_size, ptBR.GetX(), ptBR.GetY(),
00363            color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00364 
00365   // left border
00366   boxRGBA (surface,
00367            rect.GetPositionX(), rect.GetPositionY() + border_size, rect.GetPositionX()+border_size, ptBR.GetY()-border_size,
00368            color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00369 
00370   // right border
00371   boxRGBA (surface,
00372            ptBR.GetX() - border_size, rect.GetPositionY() + border_size, ptBR.GetX(), ptBR.GetY()-border_size,
00373            color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00374 
00375   return 1;
00376 }
00377 
00378 int Surface::VlineColor(const uint &x1, const uint &y1, const uint &y2, const Color &color){
00379         return vlineRGBA( surface, x1, y1, y2, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00380 }
00381 
00382 int Surface::LineColor(const uint &x1, const uint &x2, const uint &y1, const uint &y2, const Color &color){
00383   return lineRGBA( surface, x1, y1, x2, y2, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00384 }
00385 
00386 int Surface::AALineColor(const uint &x1, const uint &x2, const uint &y1, const uint &y2, const Color &color){
00387   return aalineRGBA( surface, x1, y1, x2, y2, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00388 }
00389 
00390 int Surface::CircleColor(const uint &x, const uint &y, const uint &rad, const Color &color){
00391     return circleRGBA( surface, x, y, rad, color.GetRed(), color.GetGreen(), color.GetBlue(), color.GetAlpha() );
00392 }
00393 
00398 int Surface::Fill(Uint32 color) const {
00399     return SDL_FillRect( surface, NULL, color);
00400 }
00401 
00402 int Surface::Fill(const Color &color) const{
00403         return Fill( MapColor(color) );
00404 }
00405 
00411 int Surface::FillRect(const Rectanglei &dstRect, Uint32 color) const{
00412         SDL_Rect sdlDstRect = GetSDLRect( dstRect );
00413 
00414         return SDL_FillRect( surface, &sdlDstRect, color);
00415 }
00416 
00422 int Surface::FillRect(const Rectanglei &dstRect, const Color &color) const{
00423 
00424         return FillRect( dstRect, MapColor(color) );
00425 }
00426 
00431 int Surface::ImgLoad(std::string filename){
00432         AutoFree();
00433         surface = IMG_Load( filename.c_str() );
00434 
00435         return !IsNull();
00436 }
00437 
00447 static const double ratio_deg_to_rad = 180 / M_PI;
00448 Surface Surface::RotoZoom(double angle, double zoomx, double zoomy, int smooth){
00449         Surface newSurf;
00450 
00451         newSurf.SetSurface( rotozoomSurfaceXY(surface, angle * ratio_deg_to_rad , zoomx, zoomy, smooth) );
00452 
00453         if( newSurf.IsNull() )
00454                 Error( "Unable to make a rotozoom on the surface !" );
00455 
00456         return newSurf;
00457 }
00458 
00462 Surface Surface::DisplayFormatAlpha(){
00463         Surface newSurf;
00464 
00465         newSurf.SetSurface( SDL_DisplayFormatAlpha( surface ) );
00466 
00467         if( newSurf.IsNull() )
00468                 Error( "Unable to convert the surface to a surface compatible with the display format with alpha." );
00469 
00470         return newSurf;
00471 }
00472 
00476 Surface Surface::DisplayFormat(){
00477         Surface newSurf;
00478 
00479         newSurf.SetSurface( SDL_DisplayFormat( surface ) );
00480 
00481         if( newSurf.IsNull() )
00482                 Error( "Unable to convert the surface to a surface compatible with the display format." );
00483 
00484         return newSurf;
00485 }
00486 
00487 
00495 Uint32 Surface::GetPixel(int x, int y){
00496     int bpp = surface->format->BytesPerPixel;
00497     /* Here p is the address to the pixel we want to retrieve */
00498     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
00499 
00500     switch(bpp) {
00501     case 1:
00502         return *p;
00503 
00504     case 2:
00505         return *(Uint16 *)p;
00506 
00507     case 3:
00508         if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
00509             return p[0] << 16 | p[1] << 8 | p[2];
00510         else
00511             return p[0] | p[1] << 8 | p[2] << 16;
00512 
00513     case 4:
00514         return *(Uint32 *)p;
00515 
00516     default:
00517                 Error("Unknow bpp!");
00518         return 0;   // To make gcc happy
00519     }
00520 }
00521 
00528 void Surface::PutPixel(int x, int y, Uint32 pixel){
00529     int bpp = surface->format->BytesPerPixel;
00530     /* Here p is the address to the pixel we want to set */
00531     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
00532 
00533     switch(bpp) {
00534     case 1:
00535         *p = pixel;
00536         break;
00537 
00538     case 2:
00539         *(Uint16 *)p = pixel;
00540         break;
00541 
00542     case 3:
00543         if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
00544             p[0] = (pixel >> 16) & 0xff;
00545             p[1] = (pixel >> 8) & 0xff;
00546             p[2] = pixel & 0xff;
00547         } else {
00548             p[0] = pixel & 0xff;
00549             p[1] = (pixel >> 8) & 0xff;
00550             p[2] = (pixel >> 16) & 0xff;
00551         }
00552         break;
00553 
00554     case 4:
00555         *(Uint32 *)p = pixel;
00556         break;
00557     }
00558 }
00559 
00560 SDL_Rect Surface::GetSDLRect(const Rectanglei &r) const
00561 {
00562   SDL_Rect sdlRect;
00563   
00564   sdlRect.x = r.GetPositionX();
00565   sdlRect.y = r.GetPositionY();
00566   sdlRect.w = r.GetSizeX();
00567   sdlRect.h = r.GetSizeY();
00568   
00569   return sdlRect;
00570 }
00571 
00572 SDL_Rect Surface::GetSDLRect(const Point2i &pt) const
00573 {
00574   SDL_Rect sdlRect;
00575   
00576   sdlRect.x = pt.GetX();
00577   sdlRect.y = pt.GetY();
00578   sdlRect.w = 0;
00579   sdlRect.h = 0;
00580   
00581   return sdlRect;
00582 }

Generated on Mon Jan 1 13:10:56 2007 for Wormux by  doxygen 1.4.7