00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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 ¢er, 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
00157 for (uint i=0; i<nbr_cell; ++i)
00158 item.push_back ( new TileItem_AlphaSoftware(CELL_SIZE) );
00159
00160
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
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);
00214
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
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
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 }