src/map/tileitem.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 PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public 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 
00020 #include "tileitem.h"
00021 #include <iostream>
00022 #include <SDL.h>
00023 #include <SDL_endian.h>
00024 #include "tile.h"
00025 #include "../game/config.h"
00026 #include "../include/app.h"
00027 #include "../map/camera.h"
00028 #include "../tool/error.h"
00029 #include "../tool/point.h"
00030 #include "../tool/stats.h"
00031 #ifdef DBG_TILE
00032 #include "../graphic/colors.h"
00033 #endif
00034 
00035 // === Common to all TileItem_* except TileItem_Emtpy ==============================
00036 void TileItem_AlphaSoftware::Draw(const Point2i &pos){
00037   AppWormux::GetInstance()->video.window.Blit(GetSurface(),
00038         pos * CELL_SIZE - camera.GetPosition());
00039 }
00040 
00041 void TileItem_Empty::Draw(const Point2i &pos)
00042 {
00043 #ifdef DBG_TILE
00044   AppWormux::GetInstance()->video.window.FillRect(Rectanglei(pos * CELL_SIZE - camera.GetPosition(),CELL_SIZE), c_red);
00045 #endif
00046 }
00047 // === Implemenation of TileItem_Software_ALpha ==============================
00048 TileItem_AlphaSoftware::TileItem_AlphaSoftware(const Point2i &size){
00049     m_size = size;
00050     m_surface = Surface(size, SDL_SWSURFACE|SDL_SRCALPHA, true).DisplayFormatAlpha();
00051     need_delete = false;
00052     ResetEmptyCheck();
00053 
00054     _GetAlpha = &TileItem_AlphaSoftware::GetAlpha_Generic;
00055     if( m_surface.GetBytesPerPixel() == 4 ){
00056        if( m_surface.GetSurface()->format->Amask == 0x000000ff ){
00057            if( SDL_BYTEORDER == SDL_LIL_ENDIAN )
00058                _GetAlpha = &TileItem_AlphaSoftware::GetAlpha_Index0;
00059            else
00060                _GetAlpha = &TileItem_AlphaSoftware::GetAlpha_Index3;
00061        }else{
00062            if( m_surface.GetSurface()->format->Amask == 0xff000000 ){
00063                 if (SDL_BYTEORDER == SDL_LIL_ENDIAN )
00064                     _GetAlpha = &TileItem_AlphaSoftware::GetAlpha_Index3;
00065                 else
00066                     _GetAlpha = &TileItem_AlphaSoftware::GetAlpha_Index0;
00067             }
00068         }
00069     }
00070 }
00071 
00072 TileItem_AlphaSoftware::~TileItem_AlphaSoftware(){
00073 }
00074 
00075 void TileItem_AlphaSoftware::ResetEmptyCheck()
00076 {
00077   need_check_empty = true;
00078   last_filled_pixel = m_surface.GetPixels();
00079 }
00080 
00081 unsigned char TileItem_AlphaSoftware::GetAlpha(const Point2i &pos){
00082     return (this->*_GetAlpha)(pos);
00083 }
00084 
00085 unsigned char TileItem_AlphaSoftware::GetAlpha_Index0 (const Point2i &pos){
00086     return *(m_surface.GetPixels() + pos.y*m_surface.GetPitch() + pos.x * 4 + 0);
00087 }
00088 
00089 unsigned char TileItem_AlphaSoftware::GetAlpha_Index3 (const Point2i &pos){
00090     return *(m_surface.GetPixels() + pos.y*m_surface.GetPitch() + pos.x * 4 + 3);
00091 }
00092 
00093 unsigned char TileItem_AlphaSoftware::GetAlpha_Generic (const Point2i &pos){
00094     unsigned char r, g, b, a;
00095 
00096     Uint32 pixel = *(Uint32 *)(m_surface.GetPixels() + pos.y*m_surface.GetPitch() + pos.x*m_surface.GetBytesPerPixel()); 
00097     m_surface.GetRGBA(pixel, r, g, b, a);
00098 
00099     return a;
00100 }
00101 
00102 void TileItem_AlphaSoftware::Dig(const Point2i &position, const Surface& dig){
00103     need_check_empty = true;
00104     int starting_x = position.x >= 0 ? position.x : 0;
00105     int starting_y = position.y >= 0 ? position.y : 0;
00106     int ending_x = position.x+dig.GetWidth() <= m_surface.GetWidth() ? position.x+dig.GetWidth() : m_surface.GetWidth();
00107     int ending_y = position.y+dig.GetHeight() <= m_surface.GetHeight() ? position.y+dig.GetHeight() : m_surface.GetHeight();
00108 
00109     for( int py = starting_y ; py < ending_y ; py++) 
00110         for( int px = starting_x ; px < ending_x ; px++)
00111             if ( *(dig.GetPixels() + (py-position.y)*dig.GetPitch() + (px-position.x) * 4 + 3) != 0)
00112                 *(m_surface.GetPixels() + py*m_surface.GetPitch() + px * 4 + 3) = 0;
00113 }
00114 
00115 void TileItem_AlphaSoftware::Dig(const Point2i &center, const uint radius){
00116   need_check_empty = true;
00117   unsigned char* buf   = m_surface.GetPixels();
00118   const uint line_size = m_surface.GetPitch();
00119   const uint bpp       = m_surface.GetBytesPerPixel();
00120 
00121   int y = (center.y - (int)radius - (int)EXPLOSION_BORDER_SIZE >= 0) ? (center.y - (int)radius - EXPLOSION_BORDER_SIZE) : 0;
00122   buf += y * line_size;
00123 
00124   //Empties each line of the tile horizontaly that are in the circle
00125   while ( (uint) y <= center.y + radius + EXPLOSION_BORDER_SIZE&& y < CELL_SIZE.y )
00126   {
00127     //Abscisse distance from the center of the circle to the circle
00128     int dac = center.y - y;
00129 
00130     //Angle on the circle
00131     float angle = asin( (float)dac / (float)radius);
00132 
00133     //Zone of the line which needs to be emptied
00134     int start_x, end_x, lenght;
00135     lenght = (int) ((float) radius * cos (angle));
00136     lenght = lenght > 0 ? lenght : - lenght;
00137     start_x = center.x - lenght;
00138     lenght *= 2;
00139     end_x = start_x + lenght;
00140     Empty(start_x, end_x, buf, bpp);
00141 
00142     //Darken the border of the removed ground
00143     // Left half of the circle
00144     int bstart_x, bend_x, blenght;
00145     angle = asin( (float)dac / (float)(radius + EXPLOSION_BORDER_SIZE));
00146     blenght = (int) ((float) (radius + EXPLOSION_BORDER_SIZE) * cos (angle));
00147     blenght = blenght > 0 ? blenght : - blenght;
00148     bstart_x = center.x - blenght;
00149     bend_x = bstart_x + (blenght - lenght/2);
00150     Darken(bstart_x, bend_x, buf, bpp);
00151 
00152     // Right half of the circle
00153     bstart_x = center.x + lenght/2 + 1;
00154     bend_x = bstart_x + (blenght - lenght/2);
00155     Darken(bstart_x, bend_x, buf, bpp);
00156 
00157     buf += line_size;
00158     y++;
00159   }
00160 }
00161 
00162 void TileItem_AlphaSoftware::MergeSprite(const Point2i &position, Surface& spr)
00163 {
00164   need_check_empty = true;
00165   int starting_x = position.x >= 0 ? position.x : 0;
00166   int starting_y = position.y >= 0 ? position.y : 0;
00167   int ending_x = position.x+spr.GetWidth() <= m_surface.GetWidth() ? position.x+spr.GetWidth() : m_surface.GetWidth();
00168   int ending_y = position.y+spr.GetHeight() <= m_surface.GetHeight() ? position.y+spr.GetHeight() : m_surface.GetHeight();
00169   unsigned char r,g,b,a,p_r,p_g,p_b,p_a;
00170   unsigned char* spr_buf = spr.GetPixels();
00171   unsigned char* tile_buf = m_surface.GetPixels();
00172 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
00173   int r_offset = 0;
00174   int g_offset = 1;
00175   int b_offset = 2;
00176   int a_offset = 3;
00177 #else
00178   int r_offset = 3;
00179   int g_offset = 2;
00180   int b_offset = 1;
00181   int a_offset = 0;
00182 #endif
00183 
00184   // Really dirty hack: there is no obvious reason it should work, but with this it works (TM)
00185   spr_buf++;
00186 
00187   for( int py = starting_y ; py < ending_y ; py++) {
00188     for( int px = starting_x ; px < ending_x ; px++) {
00189       a = *(spr_buf+((py-position.y)*spr.GetPitch()) + ((px-position.x) * 4 + a_offset));
00190       p_a = *(tile_buf + py*m_surface.GetPitch() + (px * 4) + a_offset);
00191       if (p_a > 0) {
00192         p_r = *(tile_buf + py*m_surface.GetPitch() + (px * 4) + r_offset);
00193         p_g = *(tile_buf + py*m_surface.GetPitch() + (px * 4) + g_offset);
00194         p_b = *(tile_buf + py*m_surface.GetPitch() + (px * 4) + b_offset);
00195       } else {
00196         p_r = p_g = p_b = 255;
00197       }
00198       if (a == SDL_ALPHA_OPAQUE || (p_a == 0 && a > 0)) {
00199         r = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + r_offset);
00200         g = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + g_offset);
00201         b = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + b_offset);
00202         *(tile_buf + py*m_surface.GetPitch() + (px * 4) + r_offset) = r;
00203         *(tile_buf + py*m_surface.GetPitch() + (px * 4) + g_offset) = g;
00204         *(tile_buf + py*m_surface.GetPitch() + (px * 4) + b_offset) = b;
00205         *(tile_buf + py*m_surface.GetPitch() + (px * 4) + a_offset) = a;
00206       } else if (a > 0) {
00207         r = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + r_offset);
00208         g = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + g_offset);
00209         b = *(spr_buf + (py-position.y)*spr.GetPitch() + (px-position.x) * 4 + b_offset);
00210         *(tile_buf + py*m_surface.GetPitch() + (px * 4) + r_offset) = (r * a + p_r * p_a) / (a + p_a);
00211         *(tile_buf + py*m_surface.GetPitch() + (px * 4) + g_offset) = (g * a + p_g * p_a) / (a + p_a);
00212         *(tile_buf + py*m_surface.GetPitch() + (px * 4) + b_offset) = (b * a + p_b * p_a) / (a + p_a);
00213         *(tile_buf + py*m_surface.GetPitch() + (px * 4) + a_offset) = (a > p_a ? a : p_a);
00214       }
00215     }
00216   }
00217 }
00218 
00219 void TileItem_AlphaSoftware::Empty(const int start_x, const int end_x, unsigned char* buf, const int bpp)
00220 {
00221   if( start_x < CELL_SIZE.x && end_x >= 0)
00222   {
00223     //Clamp the value to empty only the in this tile
00224     int tile_start_x = (start_x < 0) ? 0 : (start_x >= CELL_SIZE.x) ? CELL_SIZE.x - 1 : start_x;
00225     assert( tile_start_x >= 0 && tile_start_x < CELL_SIZE.x);
00226     int tile_lenght = (end_x >= CELL_SIZE.x) ? CELL_SIZE.x - tile_start_x : end_x - tile_start_x + 1;
00227     assert( tile_lenght > 0);
00228     assert( tile_start_x + tile_lenght <= CELL_SIZE.x);
00229 
00230     assert(buf + tile_start_x * bpp + bpp * (tile_lenght-1) < m_surface.GetPixels() + CELL_SIZE.x * CELL_SIZE.y * bpp); //Check for overflow
00231     memset(buf + tile_start_x * bpp, 0 , bpp * tile_lenght);
00232 
00233 /*    unsigned int* tmpbuf = (unsigned int*)(buf + tile_start_x * bpp);
00234 
00235     while(tile_lenght--)
00236       *(tmpbuf++) = 0;*/
00237   }
00238 }
00239 
00240 void TileItem_AlphaSoftware::Darken(const int start_x, const int end_x, unsigned char* buf, const int bpp)
00241 {
00242   if( start_x < CELL_SIZE.x && end_x >= 0)
00243   {
00244     //Clamp the value to empty only the in this tile
00245     int tile_start_x = (start_x < 0) ? 0 : (start_x >= CELL_SIZE.x) ? CELL_SIZE.x - 1 : start_x;
00246     assert( tile_start_x >= 0 && tile_start_x < CELL_SIZE.x);
00247     int tile_lenght = (end_x >= CELL_SIZE.x) ? CELL_SIZE.x - tile_start_x : end_x - tile_start_x + 1;
00248     assert( tile_lenght > 0);
00249     assert( tile_start_x + tile_lenght <= CELL_SIZE.x);
00250 
00251     buf += tile_start_x * bpp;
00252     while(tile_lenght--)
00253     {
00254 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
00255       *(buf++) /= 2;
00256       *(buf++) /= 2;
00257       *(buf++) /= 2;
00258       buf++; //skip alpha chanel
00259 #else
00260       buf++; //skip alpha chanel
00261       *(buf++) /= 2;
00262       *(buf++) /= 2;
00263       *(buf++) /= 2;
00264 #endif
00265     }
00266   }
00267 }
00268 
00269 Surface TileItem_AlphaSoftware::GetSurface(){
00270     return m_surface;
00271 }
00272 
00273 #ifdef DBG_TILE
00274 void TileItem_AlphaSoftware::FillWithRGB(Uint8 r, Uint8 g, Uint8 b)
00275 {
00276   int x=0, y=0;
00277   while(y < CELL_SIZE.y)
00278   {
00279     Uint32 pixel = *(Uint32 *)(m_surface.GetPixels() + y*m_surface.GetPitch() + x*m_surface.GetBytesPerPixel()); 
00280     Uint8 tmp,a;
00281     m_surface.GetRGBA(pixel, tmp, tmp, tmp, a);
00282     if(a != SDL_ALPHA_TRANSPARENT)
00283     {
00284       Uint32 col = m_surface.MapRGBA(r, g, b, a);
00285       m_surface.PutPixel(x, y, col);
00286     }
00287     x++;
00288     if(x == CELL_SIZE.y)
00289     {
00290       x = 0;
00291       y++;
00292     }
00293   }
00294 }
00295 #endif
00296 
00297 void TileItem_AlphaSoftware::CheckEmpty()
00298 {
00299   assert(need_check_empty);
00300   unsigned char alpha;
00301 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
00302   alpha = last_filled_pixel[3];
00303 #else
00304   alpha = last_filled_pixel[0];
00305 #endif
00306 
00307   if(alpha == SDL_ALPHA_TRANSPARENT)
00308   {
00309     last_filled_pixel += 4;
00310     if( last_filled_pixel >= m_surface.GetPixels() + (m_surface.GetPitch() * CELL_SIZE.y))
00311     {
00312       need_delete = true;
00313       need_check_empty = false;
00314     }
00315   }
00316   else
00317   {
00318     need_check_empty = false;
00319   }
00320 }

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