src/map/tile.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 "tile.h"
00021 #include "../include/app.h"
00022 #include "../map/camera.h"
00023 
00024 Tile::Tile(){
00025 }
00026 
00027 void Tile::FreeMem(){
00028     for (uint i=0; i<nbr_cell; ++i)
00029         delete item[i];
00030     nbr_cell = 0;
00031     item.clear();
00032 }
00033 
00034 Tile::~Tile(){ 
00035     FreeMem();
00036 }
00037 
00038 void Tile::InitTile(const Point2i &pSize){
00039     nbCells = pSize / CELL_SIZE;
00040 
00041     if( (pSize.x % CELL_SIZE.x) != 0 )
00042         nbCells.x++;
00043 
00044     if( (pSize.y % CELL_SIZE.y) != 0 )
00045         nbCells.y++;
00046 
00047     size = pSize;
00048 
00049     nbr_cell = nbCells.x * nbCells.y;
00050 }
00051 
00052 Point2i Tile::Clamp(const Point2i &v) const{
00053         return v.clamp(Point2i(0, 0), nbCells - 1);
00054 }
00055 
00056 void Tile::Dig(const Point2i &position, const Surface& dig){
00057    Rectanglei rect = Rectanglei(position, dig.GetSize());
00058         Point2i firstCell = Clamp(position/CELL_SIZE);
00059         Point2i lastCell = Clamp((position + dig.GetSize())/CELL_SIZE);
00060         Point2i c;
00061 
00062     for( c.y = firstCell.y; c.y <= lastCell.y; c.y++ )
00063         for( c.x = firstCell.x; c.x <= lastCell.x; c.x++){
00064             Point2i offset = position - c * CELL_SIZE;
00065 
00066             item[c.y*nbCells.x + c.x]->Dig(offset, dig);
00067         }
00068 }
00069 
00070 void Tile::Dig(const Point2i &center, const uint radius){  
00071    Point2i size = Point2i(2 * (radius + EXPLOSION_BORDER_SIZE),
00072                           2 * (radius + EXPLOSION_BORDER_SIZE));
00073    Point2i position = center - Point2i(radius + EXPLOSION_BORDER_SIZE,
00074                                        radius + EXPLOSION_BORDER_SIZE);
00075 
00076    Rectanglei rect = Rectanglei(position, size);
00077         Point2i firstCell = Clamp(position/CELL_SIZE);
00078         Point2i lastCell = Clamp((position+size)/CELL_SIZE);
00079         Point2i c;
00080 
00081     for( c.y = firstCell.y; c.y <= lastCell.y; c.y++ )
00082     for( c.x = firstCell.x; c.x <= lastCell.x; c.x++){
00083             Point2i offset = center - c * CELL_SIZE;
00084             item[c.y*nbCells.x + c.x]->Dig(offset, radius);
00085         }
00086 }
00087 
00088 void Tile::PutSprite(const Point2i pos, Sprite* spr)
00089 {
00090   Rectanglei rec = Rectanglei(pos, spr->GetSizeMax());
00091   Point2i firstCell = Clamp(pos/CELL_SIZE);
00092   Point2i lastCell = Clamp((pos + spr->GetSizeMax())/CELL_SIZE);
00093   Point2i c;
00094   Surface s = spr->GetSurface();
00095   s.SetAlpha(0, 0);
00096 
00097   for( c.y = firstCell.y; c.y <= lastCell.y; c.y++ )
00098   for( c.x = firstCell.x; c.x <= lastCell.x; c.x++)
00099   {
00100     if(item[c.y*nbCells.x + c.x]->IsTotallyEmpty())
00101     {
00102       delete item[c.y*nbCells.x + c.x];
00103       item[c.y*nbCells.x + c.x] = new TileItem_AlphaSoftware(CELL_SIZE);
00104       item[c.y*nbCells.x + c.x]->GetSurface().SetAlpha(0,0);
00105       item[c.y*nbCells.x + c.x]->GetSurface().Fill(0x00000000);
00106       item[c.y*nbCells.x + c.x]->GetSurface().SetAlpha(SDL_SRCALPHA,0);
00107     }
00108 
00109     Point2i cell_pos = c * CELL_SIZE;
00110     Rectanglei src;
00111     Rectanglei dst;
00112     src.SetPosition( rec.GetPosition() - cell_pos );
00113     if(src.GetPositionX() < 0) src.SetPositionX(0);
00114     if(src.GetPositionY() < 0) src.SetPositionY(0);
00115 
00116     src.SetSize( rec.GetPosition() + rec.GetSize() - cell_pos - src.GetPosition());
00117     if(src.GetSizeX() + src.GetPositionX() > CELL_SIZE.x) src.SetSizeX(CELL_SIZE.x - src.GetPositionX());
00118     if(src.GetSizeY() + src.GetPositionY() > CELL_SIZE.y) src.SetSizeY(CELL_SIZE.y - src.GetPositionY());
00119 
00120     dst.SetPosition( cell_pos - rec.GetPosition() );
00121     if(dst.GetPositionX() < 0) dst.SetPositionX(0);
00122     if(dst.GetPositionY() < 0) dst.SetPositionY(0);
00123     dst.SetSize(src.GetSize());
00124 
00125     item[c.y*nbCells.x + c.x]->GetSurface().Blit(s, dst, src.GetPosition());
00126     static_cast<TileItem_AlphaSoftware*>(item[c.y*nbCells.x + c.x])->ResetEmptyCheck();
00127   }
00128   s.SetAlpha(SDL_SRCALPHA, 0);
00129 }
00130 
00131 void Tile::MergeSprite(const Point2i &position, Surface& surf){
00132   Rectanglei rect = Rectanglei(position, surf.GetSize());
00133   Point2i firstCell = Clamp(position/CELL_SIZE);
00134   Point2i lastCell = Clamp((position + surf.GetSize())/CELL_SIZE);
00135   Point2i c;
00136 
00137   for( c.y = firstCell.y; c.y <= lastCell.y; c.y++ )
00138     for( c.x = firstCell.x; c.x <= lastCell.x; c.x++){
00139       Point2i offset = position - c * CELL_SIZE;
00140       if(item[c.y*nbCells.x + c.x]->IsTotallyEmpty()) {
00141         delete item[c.y*nbCells.x + c.x];
00142         item[c.y*nbCells.x + c.x] = new TileItem_AlphaSoftware(CELL_SIZE);
00143         item[c.y*nbCells.x + c.x]->GetSurface().SetAlpha(0,0);
00144         item[c.y*nbCells.x + c.x]->GetSurface().Fill(0x00000000);
00145         item[c.y*nbCells.x + c.x]->GetSurface().SetAlpha(SDL_SRCALPHA,0);
00146       }
00147       item[c.y*nbCells.x + c.x]->MergeSprite(offset, surf);
00148     }
00149 }
00150 void Tile::LoadImage (Surface& terrain){
00151     FreeMem();
00152 
00153     InitTile(terrain.GetSize());
00154     assert(nbr_cell != 0);
00155 
00156     // Create the TileItem objects
00157     for (uint i=0; i<nbr_cell; ++i)
00158        item.push_back ( new TileItem_AlphaSoftware(CELL_SIZE) );
00159 
00160     // Fill the TileItem objects
00161         Point2i i;
00162     for( i.y = 0; i.y < nbCells.y; i.y++ )
00163         for( i.x = 0; i.x < nbCells.x; i.x++ ){
00164             int piece = i.y * nbCells.x + i.x;
00165             Rectanglei sr( i * CELL_SIZE, CELL_SIZE);
00166 
00167             terrain.SetAlpha(0, 0);
00168             item[piece]->GetSurface().Blit(terrain, sr, Point2i(0, 0));
00169         }
00170 
00171     // Replace transparent tiles by TileItem_Empty tiles
00172     for( uint i=0; i<nbr_cell; ++i )
00173     {
00174       TileItem_AlphaSoftware* t = static_cast<TileItem_AlphaSoftware*>(item[i]);
00175       while(t->need_check_empty)
00176         t->CheckEmpty();
00177       if(t->NeedDelete())
00178       {
00179 #ifdef DBG_TILE
00180         printf("\nDeleting tile %i",i);
00181 #endif
00182         delete item[i];
00183         item[i] = (TileItem*)new TileItem_Empty;
00184       }
00185 #ifdef DBG_TILE
00186       else
00187       {
00188         if(i % nbCells.x % 2 == (i / nbCells.x) % 2)
00189           item[i]->FillWithRGB(0, 0, 255);
00190         else
00191           item[i]->FillWithRGB(0, 255, 0);
00192       }
00193 #endif
00194     }
00195 }
00196 
00197 uchar Tile::GetAlpha(const Point2i &pos) const{
00198         int cell = pos.y / CELL_SIZE.y * nbCells.x + pos.x / CELL_SIZE.x;
00199     return item[cell]->GetAlpha(pos % CELL_SIZE);
00200 }
00201 
00202 void Tile::DrawTile() {
00203     Point2i firstCell = Clamp(camera.GetPosition() / CELL_SIZE);
00204     Point2i lastCell = Clamp((camera.GetPosition() + camera.GetSize()) / CELL_SIZE);
00205         Point2i i;
00206     for( i.y = firstCell.y; i.y <= lastCell.y; i.y++ )
00207         for( i.x = firstCell.x; i.x <= lastCell.x; i.x++)
00208           item[i.y*nbCells.x + i.x]->Draw( i );
00209 }
00210 
00211 void Tile::DrawTile_Clipped(Rectanglei worldClip) const
00212 {
00213         worldClip.SetSize( worldClip.GetSize() + 1); // mmm, y aurait t-il quelque chose qui
00214         // donne des zones trops petites à redessiner ?
00215     Point2i firstCell = Clamp(worldClip.GetPosition() / CELL_SIZE);
00216     Point2i lastCell  = Clamp((worldClip.GetBottomRightPoint()) / CELL_SIZE);
00217         Point2i c;
00218 
00219     for( c.y = firstCell.y; c.y <= lastCell.y; c.y++ )
00220         for( c.x = firstCell.x; c.x <= lastCell.x; c.x++){
00221                 // For all selected items, clip source and destination blitting rectangles 
00222                         Rectanglei destRect(c * CELL_SIZE, CELL_SIZE);
00223 
00224                         destRect.Clip(worldClip);
00225                         if( destRect.Intersect( camera ) ){
00226                                 Point2i ptDest = destRect.GetPosition() - camera.GetPosition();
00227                                 Point2i ptSrc = destRect.GetPosition() - c * CELL_SIZE;
00228                         
00229                 AppWormux::GetInstance()->video.window.Blit( item[c.y*nbCells.x + c.x]->GetSurface(), Rectanglei(ptSrc, destRect.GetSize()) , ptDest); 
00230                         }
00231         }
00232 }
00233 
00234 Surface Tile::GetPart(Rectanglei& rec)
00235 {
00236   Surface part(rec.GetSize(), SDL_SWSURFACE|SDL_SRCALPHA, true);
00237   part.SetAlpha(0,0);
00238   part.Fill(0x00000000);
00239   part.SetAlpha(SDL_SRCALPHA,0);
00240 
00241   Point2i firstCell = Clamp(rec.GetPosition() / CELL_SIZE);
00242   Point2i lastCell = Clamp((rec.GetPosition() + rec.GetSize()) / CELL_SIZE);
00243   Point2i i = nbCells - 1;
00244 
00245   for( i.y = firstCell.y; i.y <= lastCell.y; i.y++ )
00246   for( i.x = firstCell.x; i.x <= lastCell.x; i.x++ )
00247   {
00248     if(item[i.y*nbCells.x + i.x]->IsTotallyEmpty()) continue;
00249 
00250     Point2i cell_pos = i * CELL_SIZE;
00251     Rectanglei src;
00252     Point2i dst;
00253     src.SetPosition( rec.GetPosition() - cell_pos );
00254     if(src.GetPositionX() < 0) src.SetPositionX(0);
00255     if(src.GetPositionY() < 0) src.SetPositionY(0);
00256 
00257     src.SetSize( rec.GetPosition() + rec.GetSize() - cell_pos - src.GetPosition());
00258     if(src.GetSizeX() + src.GetPositionX() > CELL_SIZE.x) src.SetSizeX(CELL_SIZE.x - src.GetPositionX());
00259     if(src.GetSizeY() + src.GetPositionY() > CELL_SIZE.y) src.SetSizeY(CELL_SIZE.y - src.GetPositionY());
00260 
00261     dst =  cell_pos - rec.GetPosition();
00262     if(dst.x < 0) dst.x = 0;
00263     if(dst.y < 0) dst.y = 0;
00264 
00265     item[i.y*nbCells.x + i.x]->GetSurface().SetAlpha(0, 0);
00266     part.Blit(item[i.y*nbCells.x + i.x]->GetSurface(), src, dst);
00267     item[i.y*nbCells.x + i.x]->GetSurface().SetAlpha(SDL_SRCALPHA, 0);
00268   }
00269   return part;
00270 }
00271 
00272 void Tile::CheckEmptyTiles()
00273 {
00274   for( int i = 0; i < nbCells.x * nbCells.y; i++ )
00275   {
00276     if(item[i]->IsTotallyEmpty()) continue;
00277 
00278     TileItem_AlphaSoftware* t = static_cast<TileItem_AlphaSoftware*>(item[i]);
00279     if(t->need_check_empty)
00280       t->CheckEmpty();
00281     if(t->need_delete)
00282    {
00283       // no need to display this tile as it can be deleted!
00284 #ifdef DBG_TILE
00285      printf("Deleting tile %i\n",i);
00286 #endif
00287       delete item[i];
00288       item[i] = (TileItem*)new TileItem_Empty;
00289     }
00290   }
00291 }

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