Main Page | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

CSTileMap.cpp

Go to the documentation of this file.
00001 /**
00002 */
00003 
00004 #ifdef WIN32
00005 #pragma warning(disable : 4786 )
00006 #endif
00007 
00008 #include "CSTileMap.h"
00009 #include "CSXMLHelper.h"
00010 
00011 CSTileMapLoader CSTileMapLoader::INSTANCE;
00012 const char *CSTileMap::CLASS = "CSTileMap";
00013 
00014 CSTileMap::CSTileMap(const std::string &filename)
00015 {
00016     static char *functionName="CSTileMap";
00017     LOG_ENTER 
00018     CSTileMapData data;
00019     loadTileMapData(filename, data);
00020     initialize(data);
00021     LOG_EXIT
00022 }
00023 
00024 // not Done!
00025 CSTileMap::CSTileMap(const CSTileMap &tileMap)
00026 {
00027     static char *functionName="CSTileMap";
00028     LOG_ENTER 
00029     initialize();
00030     mId = strdup(tileMap.mId);
00031     LOG_EXIT
00032 }
00033 
00034 void CSTileMap::initialize(void)
00035 {
00036     static char *functionName="initialize";
00037     LOG_ENTER 
00038     mScaleDisplay = false;
00039     mR = -1;
00040     mG = -1;
00041     mB = -1;
00042     mFactor = 0;
00043     mIsChangeable = false;
00044     mWorldNo = 0;
00045     mScaledMap = 0;
00046     mIsSolid = false;
00047     mId = 0;
00048     mTileSet = 0;
00049     mMap = 0;
00050     mRows = 0;
00051     mHeight = 0;
00052     mWidth = 0;
00053     mIsBackground = false;
00054     mIsParallax = false;
00055     mDisplayWidth = 0;
00056     mDisplayHeight = 0;
00057     mDisplayParams.mXDisplayStart = 0;
00058     mDisplayParams.mYDisplayStart = 0;
00059     mDisplayParams.mXWorldStart = 0;
00060     mDisplayParams.mYWorldStart = 0;
00061     mDisplayParams.mXPos = 0;
00062     mDisplayParams.mYPos = 0;
00063     mActive = false;
00064     LOG_EXIT
00065 }
00066 
00067 void CSTileMap::initialize(const CSTileMapData &data)
00068 {
00069     static char *functionName="initialize";
00070     LOG_ENTER 
00071     int xPos = 0;
00072     int yPos = 0;
00073     mXSize = 0;
00074     mYSize = 0;
00075     initialize();
00076     mId = strdup(data.id);
00077     mIsChangeable = data.isChangebale;
00078 
00079     mTileSet = CSTileSetLoader::INSTANCE.load(data.tileSet);
00080     mRows = new StringVector();
00081 
00082     for (StringVector::iterator iter = data.rows->begin(); iter != data.rows->end(); iter++)
00083     {
00084         char *row = (char *) *iter;
00085         mRows->push_back(strdup(row));
00086         if (mXSize < strlen(row))
00087         {
00088             mXSize = strlen(row);
00089         }
00090 
00091         mYSize++;
00092     }
00093 
00094     mMap = (CSTile ***) new void *[mYSize];
00095     
00096     iter = mRows->begin(); 
00097     for (int y=0; y< mYSize; y++)
00098     {
00099         char *row = (char *) *iter;
00100         mMap[y] = (CSTile **) new void* [mXSize];
00101         int yh = 0;
00102         xPos = 0;
00103         for (int x = 0; x < mXSize; x++)
00104         {
00105             if (x < strlen(row))
00106             {
00107                 if (row[x] == 0)
00108                 {
00109                     LOG_EXIT
00110                     SDLMain::shutdown((std::string)"TileMap includes characters not found in TileSet! ", 1);
00111                 }
00112                 mMap[y][x] = mTileSet->getTile(row[x]);
00113                 mMap[y][x]->setChanged(true);
00114                 mMap[y][x]->setX(xPos);
00115                 mMap[y][x]->setY(yPos);
00116                 mMap[y][x]->setMapPosition(x,y);
00117                 xPos += mMap[y][x]->getWitdh();
00118                 if (yh < mMap[y][x]->getHeight())
00119                 {
00120                     yh = mMap[y][x]->getHeight();
00121                 }
00122             }
00123             else
00124             {
00125                 mMap[y][x] = 0;
00126             }
00127         }
00128         yPos += yh;
00129         iter++;
00130     }
00131     mHeight = yPos;
00132     mWidth = xPos; // assumes all tiles have the same size -> which is not a MUST!
00133     mWorldHeight = mHeight;
00134     mWorldWidth = mWidth;
00135     if (!(mMap[0][0]->getAnimationState()->mPicture->isSolid()))
00136     {
00137         mMap[0][0]->getAnimationState()->mPicture->getRGB(mR,mB,mG);
00138     }
00139     LOG_EXIT
00140 }
00141 
00142 void CSTileMap::setOffset(int offsetX, int offsetY)
00143 {
00144     static char *functionName="setOffset";
00145     LOG_ENTER 
00146     mOffsetX = offsetX;
00147     mOffsetY = offsetY;
00148 
00149     int xPos = 0;
00150     int yPos = 0;
00151 
00152     for (int y=0; y< mYSize; y++)
00153     {
00154         int yh = 0;
00155         for (int x = 0; x < mXSize; x++)
00156         {
00157             if (mMap[y][x] != 0)
00158             {
00159                 mMap[y][x]->setX(xPos + mOffsetX);
00160                 mMap[y][x]->setY(yPos + mOffsetY);
00161                 xPos += mMap[y][x]->getWitdh();
00162                 if (yh < mMap[y][x]->getHeight())
00163                 {
00164                     yh = mMap[y][x]->getHeight();
00165                 }
00166             }
00167         }
00168         yPos += yh;
00169         xPos = 0;
00170     }
00171     LOG_EXIT
00172 }
00173 
00174 void CSTileMap::setSolid(bool b)
00175 {
00176     static char *functionName="setSolid";
00177     LOG_ENTER 
00178     mIsSolid = b;
00179     mTileSet->setSolid(b);
00180     mR=mG=mB = -1;
00181     LOG_EXIT
00182 }
00183 
00184 void CSTileMap::setSecPerFrame(float secPerFrame)
00185 {
00186     static char *functionName="setSecPerFrame";
00187     LOG_ENTER 
00188     mTileSet->setSecPerFrame(secPerFrame);
00189     LOG_EXIT
00190 }
00191 
00192 CSTileMap::~CSTileMap()
00193 {
00194     static char *functionName="~CSTileMap";
00195     LOG_ENTER 
00196     if (mScaledMap != 0)
00197     {
00198         SDLMain::freeSurface(mScaledMap);
00199         mScaledMap = 0;
00200     }
00201 
00202     if (mId != 0)
00203     {
00204         free(mId);
00205         mId = 0;
00206     }
00207     if (mTileSet != 0)
00208     {
00209         // TileSet are Singletons!
00210         mTileSet = 0;
00211     }
00212     if (mRows != 0)
00213     {
00214         for (StringVector::iterator iter = mRows->begin(); iter != mRows->end(); iter++)
00215         {
00216             char *help = (char *) *iter;
00217             free(help);
00218         }
00219         free(mRows);
00220         mRows = 0;
00221     }
00222 
00223     for (int y=0; y< mYSize; y++)
00224     {
00225         for (int x = 0; x < mXSize; x++)
00226         {
00227             if (mMap[y][x] != 0)
00228             {
00229                 delete mMap[y][x];
00230             }
00231         }
00232         delete[] mMap[y];
00233     }
00234     delete[] mMap;
00235     LOG_EXIT
00236 }
00237 
00238 // this is more an exchangeTile(), since it only does something, if there is allready a tile
00239 // on the x,y position!
00240 // deletes old tile at position!
00241 void CSTileMap::setTile(unsigned int x, unsigned int y, char idChar)
00242 {
00243     static char *functionName="setTile";
00244     if (!mIsChangeable)
00245     {
00246         return;
00247     }
00248     if (mMap[y][x] != 0)
00249     {
00250         int xPos = mMap[y][x]->getX();
00251         int yPos = mMap[y][x]->getY();
00252         delete mMap[y][x];
00253         mMap[y][x] = mTileSet->getTile(idChar);
00254         mMap[y][x]->setChanged(true);
00255         mMap[y][x]->setX(xPos);
00256         mMap[y][x]->setY(yPos);
00257         mMap[y][x]->setMapPosition(x,y);
00258     }
00259 }
00260 
00261 // this is more an exchangeTile(), since it only does something, if there is allready a tile
00262 // on the x,y position!
00263 // does not delete old tile at position!
00264 // if center is true AND the tileset is set to "IsOneSize" the tile that
00265 // is set, is "centered" at the position "regardless" of its own size.
00266 void CSTileMap::setTile(unsigned int x, unsigned int y, CSTile *tile, bool center)
00267 {
00268     static char *functionName="setTile";
00269     if (!mIsChangeable)
00270     {
00271         return;
00272     }
00273     if (mMap[y][x] != 0)
00274     {
00275         int xPos;
00276         int yPos;
00277         if ((center) && (mTileSet->isOneSize()))
00278         {
00279             xPos = x * mTileSet->getTileXSize() + mOffsetX;
00280             yPos = y * mTileSet->getTileYSize() + mOffsetY;
00281             
00282             int nh = tile->getHeight();
00283             int nw = tile->getWitdh();
00284             xPos += (mTileSet->getTileXSize()-nw)/2;
00285             yPos += (mTileSet->getTileYSize()-nh)/2;
00286         }
00287         else
00288         {
00289         xPos = mMap[y][x]->getX();
00290         yPos = mMap[y][x]->getY();
00291         }
00292         mMap[y][x] = tile;
00293         mMap[y][x]->setChanged(true);
00294         mMap[y][x]->setX(xPos);
00295         mMap[y][x]->setY(yPos);
00296         mMap[y][x]->setMapPosition(x,y);
00297     }
00298 }
00299 
00300 CSTile *CSTileMap::getTileAtPixel(unsigned int tx, unsigned int ty)
00301 {
00302     static char *functionName="getTileAtPixel";
00303     int x, y;
00304     CSTile *tile;
00305     for (y=0; y< mYSize; y++)
00306     {
00307         tile = mMap[y][0];
00308         if (ty > tile->getY() + tile->getHeight()) continue;    // i am y greater
00309 
00310         for (x = 0; x < mXSize; x++)
00311         {
00312             if (mMap[y][x] != 0)
00313             {
00314                 tile = mMap[y][x];
00315                 if (tx > tile->getX() + tile->getWitdh()) continue; // i am x greater
00316                 return mMap[y][x];
00317             }
00318         }
00319     }
00320     return 0;
00321 }
00322 
00323 CSTiles CSTileMap::getTouchingTiles(int tx,int ty, int tw, int th)
00324 {
00325     static char *functionName="getTouchingTiles";
00326     // assumes all tiles have the same size!
00327     CSTiles tiles;
00328     for (int y=0; y< mYSize; y++)
00329     {
00330         
00331         CSTile *tile = mMap[y][0];
00332         int oY = tile->getY();
00333         int oH = tile->getHeight();
00334         if ((ty < oY) && (ty + th < oY)) 
00335         {
00336             return tiles;   // i am y smaller
00337         }
00338         if ((ty > oY) && (ty > oY + oH)) continue;  // i am y greater
00339 
00340         for (int x = 0; x < mXSize; x++)
00341         {
00342             if (mMap[y][x] != 0)
00343             {
00344                 CSTile *tile = mMap[y][x];
00345                 int oX = tile->getX();
00346                 int oW = tile->getWitdh();
00347 
00348                 if ((tx < oX) && (tx + tw < oX)) break; // i am x smaller
00349                 if ((tx > oX) && (tx > oX + oW)) continue;  // i am x greater
00350         
00351                 tiles.push_back(mMap[y][x]);
00352             }
00353         }
00354     }
00355     return tiles;
00356 }
00357 
00358 void CSTileMap::display()
00359 {
00360     static char *functionName="display";
00361     int y,x;
00362     CSTile *tile;
00363     
00364     for (y=sy; y< ey; y++)
00365     {
00366         for (x = sx; x < ex; x++)
00367         {
00368             tile = mMap[y][x];
00369             if (tile)
00370             {
00371                 tile->display();
00372             }
00373         }
00374     }
00375     CSSprites::iterator iter = mSprites.begin();
00376     while (iter != mSprites.end())
00377     {
00378         CSSprite *sprite = *iter;
00379         if (mWorldNo == sprite->getWorldPos())
00380         {
00381             sprite->display();
00382         }
00383         iter++;
00384     }
00385 }
00386 
00387 void CSTileMap::update()
00388 {
00389     static char *functionName="update";
00390     if (mActive)
00391     {
00392         int y,x;
00393         CSTile *tile;
00394         sx = 0;
00395         sy = 0;
00396         ex = mXSize;
00397         ey = mYSize;
00398         int startX = mDisplayParams.mXWorldStart;
00399         int startY = mDisplayParams.mYWorldStart;
00400         int endX = startX + mDisplayWidth;
00401         int endY = startY + mDisplayHeight;
00402 
00403         // assuming tiles have appr. same size
00404         for (y = 0; ((y<mYSize) && (startY > (int) mMap[y][0]->getY()+(int)mMap[y][0]->getHeight())); y++);
00405         for (x = 0; ((x<mXSize) && (startX > (int) mMap[0][x]->getX()+(int)mMap[0][x]->getWitdh())); x++);
00406 
00407         sx = x;
00408         sy = y;
00409 
00410         for (; ((y<mYSize) && (endY > (int) mMap[y][0]->getY())); y++);
00411         for (; ((x<mXSize) && (endX > (int) mMap[0][x]->getX())); x++);
00412         ex = x; // changed from x;
00413         ey = y; // changed from y;
00414 
00415         for (y=sy; y< ey; y++)
00416         {
00417             for (x = sx; x < ex; x++)
00418             {
00419                 tile = mMap[y][x];
00420                 if (tile)
00421                 {
00422                     tile->next(mDisplayParams);
00423                 }
00424             }
00425         }
00426     }
00427     CSSprites::iterator iter = mSprites.begin();
00428     while (iter != mSprites.end())
00429     {
00430         CSSprite *sprite = *iter;
00431         if (mWorldNo == sprite->getWorldPos())
00432         {
00433             sprite->next();
00434         }
00435         iter++;
00436     }
00437 }
00438 
00439 void CSTileMap::setMapPosition(int px, int py)
00440 {
00441     static char *functionName="setMapPosition";
00442     if (mIsBackground)
00443     {
00444         px = 0;
00445         py = 0;
00446     }
00447     else if (mIsParallax)
00448     {
00449 /*
00450         float xRation;
00451         float yRation;
00452         xRation = (float)( ((float) px) / ((float)(mWorldWidth-mDisplayWidth)) ) ;
00453         yRation = (float)( ((float) py) / ((float)(mWorldHeight-mDisplayHeight)) ) ;
00454 
00455         px = (float)(((float) mWidth-mDisplayWidth) * xRation);
00456         py = (float)(((float) mHeight-mDisplayHeight) * yRation);
00457         same as:
00458 */
00459         px = (float)(((float) mWidth-mDisplayWidth) * (float)((float)( ((float) px) / ((float)(mWorldWidth-mDisplayWidth)) )));
00460         py = (float)(((float) mHeight-mDisplayHeight) * (float)((float)( ((float) py) / ((float)(mWorldHeight-mDisplayHeight)) )));
00461     }
00462     mDisplayParams.mXWorldStart = px;
00463     mDisplayParams.mYWorldStart = py;
00464 }
00465 
00466 void CSTileMap::setDisplayOffset(int xOffset, int yOffset)
00467 {
00468     static char *functionName="setDisplayOffset";
00469     mDisplayParams.mXDisplayStart = xOffset;
00470     mDisplayParams.mYDisplayStart = yOffset;
00471     CSSprites::iterator iter = mSprites.begin();
00472     while (iter != mSprites.end())
00473     {
00474         CSSprite *sprite = *iter;
00475         sprite->setDisplayOffset(xOffset, yOffset);
00476         iter++;
00477     }
00478 }
00479 
00480 void CSTileMap::addSprite(CSSprite *sprite)
00481 {
00482     static char *functionName="addSprite";
00483     LOG_ENTER 
00484     // savety meassure, not to add twice!
00485     removeSprite(sprite);
00486     mSprites.push_back(sprite);
00487     sprite->setDisplayOffset(mDisplayParams.mXDisplayStart, mDisplayParams.mYDisplayStart);
00488     LOG_EXIT
00489 }
00490 
00491 void CSTileMap::removeSprite(CSSprite *sprite)
00492 {
00493     static char *functionName="removeSprite";
00494     LOG_ENTER 
00495     CSSprites::iterator iter = mSprites.begin();
00496     while (iter != mSprites.end())
00497     {
00498         if ((*iter) == sprite)
00499         {
00500             mSprites.erase(iter);
00501             iter = mSprites.begin();    // restart!
00502         }
00503         else
00504         {
00505             iter++;
00506         }
00507     }
00508     LOG_EXIT
00509 }
00510 
00511 void CSTileMap::loadTileMapData(const std::string &filename, CSTileMapData &data)
00512 {
00513     static char *functionName="loadTileMapData";
00514     LOG_ENTER 
00515     char tmp[10];
00516     CSXMLHelper xmlSupport(filename, "TILEMAP");
00517     try
00518     {
00519         if (xmlSupport.getError())
00520         {
00521             LOG_EXIT
00522             throw "error";
00523         }
00524 
00525         data.id = strdup(xmlSupport.getString("ID").c_str());
00526         data.tileSet = strdup(xmlSupport.getString("SET").c_str());
00527 
00528         data.isChangebale = xmlSupport.getInt("CHANGEABLE") != 0;
00529         int rowCount = xmlSupport.getInt("count(ROWS/ROW)");
00530         for (int i=0; i<rowCount; i++)
00531         {
00532             // i+1, predicates in xpath start with 1
00533             std::string a = xmlSupport.getString((std::string)"ROWS/ROW["+itoa(i+1,tmp,10)+"]");
00534             data.rows->push_back(strdup(a.c_str()));
00535         }
00536     }
00537     catch(...)
00538     {
00539         LOG_EXIT
00540         SDLMain::shutdown((std::string)"XML error \"" + filename + "\": " + xmlSupport.getErrorMessage().c_str(), 1);
00541     }
00542     LOG_EXIT
00543 }
00544 
00545 void CSTileMap::setBackground(bool b) 
00546 {
00547     static char *functionName="setBackground";
00548     LOG_ENTER 
00549     mIsBackground = b;
00550     LOG_EXIT
00551 }
00552 
00553 void CSTileMap::scaleMapToFit(int width, int height)
00554 {
00555     static char *functionName="scaleMapToFit";
00556     LOG_ENTER 
00557     mTileSet->scaleToFit(width, mXSize,height,mYSize);
00558     mHeight = height;
00559     mWidth = width;
00560     mWorldHeight = mHeight;
00561     mWorldWidth = mWidth;
00562     LOG_EXIT
00563 }
00564 
00565 void CSTileMap::resetScaledMap()
00566 {
00567     static char *functionName="resetScaledMap";
00568     LOG_ENTER 
00569     if (mScaledMap != 0)
00570     {
00571         SDLMain::freeSurface(mScaledMap);
00572         mScaledMap = 0;
00573     }
00574     for (int y=0; y< mYSize; y++)
00575     {
00576         int yh = 0;
00577         for (int x = 0; x < mXSize; x++)
00578         {
00579             if (mMap[y][x] != 0)
00580             {
00581                 mMap[y][x]->setChanged(true);
00582             }
00583         }
00584     }
00585     LOG_EXIT
00586 }
00587 
00588 // scaled Map has color key of only the first tile!
00589 SDL_Surface *CSTileMap::getScaledMap(double factor, bool isSolid) 
00590 {
00591     static char *functionName="getScaledMap";
00592     if ((!mIsChangeable) && (mFactor == factor) && (mScaledMap != 0))
00593     {
00594         return mScaledMap;
00595     }
00596 
00597     if (!((mFactor == factor) && (mScaledMap != 0)))
00598     {
00599         if (mScaledMap != 0)
00600         {
00601             SDLMain::freeSurface(mScaledMap);
00602             mScaledMap = 0;
00603         }
00604         int width = ((double) mWorldWidth)*factor;
00605         int height = ((double) mWorldHeight)*factor;
00606         int flags = SDLMain::getScreen()->flags;
00607         
00608         // don't know why this is needed! Windows?
00609         if ((flags & SDL_HWSURFACE) == SDL_HWSURFACE)
00610         {
00611             flags -= SDL_HWSURFACE;
00612         }
00613         mScaledMap = SDL_CreateRGBSurface(flags, 
00614                                    width, 
00615                                    height, 
00616                                    SDLMain::getScreen()->format->BitsPerPixel, 
00617                                    SDLMain::getScreen()->format->Rmask, 
00618                                    SDLMain::getScreen()->format->Gmask, 
00619                                    SDLMain::getScreen()->format->Bmask, 
00620                                    SDLMain::getScreen()->format->Amask);
00621 
00622         if ((!(mMap[0][0]->getAnimationState()->mPicture->isSolid())) && (!isSolid))
00623         {
00624             if (mR+mG+mB != -3)
00625             {
00626                 int mColorKey = SDL_MapRGB(mScaledMap->format, mR, mG, mB);
00627                 SDL_SetColorKey(mScaledMap, SDL_SRCCOLORKEY, mColorKey);
00628             }
00629         }
00630     }
00631     mFactor = factor;
00632 
00633     SDL_Rect dstrect;
00634 
00635     int y,x,h;
00636     int ox = (double)(((double)(mOffsetX))*factor);
00637     int oy = (double)(((double)(mOffsetY))*factor);
00638 
00639     dstrect.y = oy;
00640     for (y=0; y< mYSize; y++)
00641     {
00642         dstrect.x = ox;
00643         h = 0;
00644         for (x = 0; x < mXSize; x++)
00645         {
00646             SDL_Surface *src = mMap[y][x]->getScaledTile(factor);
00647             dstrect.w = src->w;
00648             dstrect.h = src->h;
00649             if (dstrect.h > h)
00650             {
00651                 h = dstrect.h;
00652             }
00653             
00654             // during a scale at runtime-> all tiles are
00655             // probably a unchanged, but we need an 
00656             // update of all tiles -> so we better don't even ask!
00657             // if (mMap[y][x]->isChanged())
00658             {
00659                 //mMap[y][x]->setChanged(false);
00660                 if (mR+mG+mB != -3)
00661                 {
00662                     int mColorKey = SDL_MapRGB(mScaledMap->format, mR, mG, mB);
00663                     SDL_FillRect(mScaledMap, &dstrect, mColorKey);
00664                 }
00665 
00666                 SDL_BlitSurface(src, 0, mScaledMap, &dstrect);
00667             }
00668             dstrect.x += dstrect.w;
00669         }
00670         dstrect.y += h;
00671     }
00672     return mScaledMap;
00673 }
00674 
00675 void CSTileMap::addScaledSprites(double factor, const SDL_Rect &offsetRect, SDL_Surface *destination, const SDL_Rect &displayRect)
00676 {
00677     static char *functionName="addScaledSprites";
00678     CSSprites::iterator iter = mSprites.begin();
00679     SDL_Rect dstrect;
00680     while (iter != mSprites.end())
00681     {
00682         CSSprite *sprite = *iter;
00683         if (mWorldNo == sprite->getWorldPos())
00684         {
00685             SDL_Surface *src = sprite->getScaledSprite(factor);
00686             register int x = sprite->getState().mActionState.mAnimationState.mDisplayParams.mXPos;
00687             register int y = sprite->getState().mActionState.mAnimationState.mDisplayParams.mYPos;
00688             dstrect.x = - offsetRect.x  + displayRect.x + (double)(((double)(x))*factor);
00689             dstrect.y = - offsetRect.y + displayRect.y + (double)(((double)(y))*factor);
00690             dstrect.w = src->w;
00691             dstrect.h = src->h;
00692 
00693             SDL_BlitSurface(src, 0, destination, &dstrect);
00694         }
00695         iter++;
00696     }
00697 }
00698 

Generated on Wed Jul 14 00:43:43 2004 for CSLib by doxygen 1.3.6