#include "cmap.hpp" #include "cgameobjectvirtual.hpp" #include "cgameobjectshape.hpp" #include "cgameobjectshapeex.hpp" #include "cgameobjectsprite.hpp" #include "ctilelayer.hpp" #include "cobjectlayer.hpp" #include "../graphics/cprimitives.hpp" #include "../graphics/cshapegroupmanager.hpp" #include "../ui/cuithememanager.hpp" using namespace EE::Graphics; namespace EE { namespace Gaming { cMap::cMap() : mWindow( cEngine::instance()->GetCurrentWindow() ), mLayers( NULL ), mFlags( 0 ), mMaxLayers( 0 ), mLayerCount( 0 ), mViewSize( 800, 600 ), mTileTex( NULL ) { ViewSize( mViewSize ); } cMap::~cMap() { DeleteLayers(); } void cMap::Reset() { DeleteLayers(); mWindow = NULL; mLayers = NULL; mFlags = 0; mMaxLayers = 0; mViewSize = eeSize( 800, 600 ); } void cMap::DeleteLayers() { for ( Uint32 i = 0; i < mLayerCount; i++ ) eeSAFE_DELETE( mLayers[i] ); eeSAFE_DELETE( mLayers ); mLayerCount = 0; } void cMap::Create( eeSize Size, Uint32 MaxLayers, eeSize TileSize, Uint32 Flags, eeSize viewSize, Window::cWindow * Window ) { Reset(); mWindow = Window; if ( NULL == mWindow ) mWindow = cEngine::instance()->GetCurrentWindow(); mFlags = Flags; mMaxLayers = MaxLayers; mSize = Size; mTileSize = TileSize; mPixelSize = Size * TileSize; mLayers = eeNewArray( cLayer*, mMaxLayers ); for ( Uint32 i = 0; i < mMaxLayers; i++ ) mLayers[i] = NULL; ViewSize( viewSize ); CreateEmptyTile(); } void cMap::CreateEmptyTile() { //! I create a texture representing an empty tile to render instead of rendering with primitives because is a lot faster, at least with NVIDIA GPUs. cTextureFactory * TF = cTextureFactory::instance(); std::string tileName( "maptile-" + toStr( mTileSize.Width() ) + "x" + toStr( mTileSize.Height() ) ); cTexture * Tex = TF->GetByName( tileName ); if ( NULL == Tex ) { Uint32 x, y; eeColorA Col( 255, 255, 255, 255 ); cImage Img( mTileSize.Width(), mTileSize.Height(), 4 ); Img.FillWithColor( eeColorA( 0, 0, 0, 0 ) ); for ( x = 0; x < Img.Width(); x++ ) { Img.SetPixel( x, 0, Col ); Img.SetPixel( x, mTileSize.y - 1, Col ); } for ( y = 0; y < Img.Height(); y++ ) { Img.SetPixel( 0, y, Col ); Img.SetPixel( mTileSize.x - 1, y, Col ); } Uint32 TileTexId = TF->LoadFromPixels( Img.GetPixelsPtr(), Img.Width(), Img.Height(), Img.Channels(), false, EE_CLAMP_TO_EDGE, false, false, tileName ); mTileTex = TF->GetTexture( TileTexId ); } else { mTileTex = Tex; } } cLayer * cMap::AddLayer( Uint32 Type, Uint32 flags, std::string name ) { eeASSERT( NULL != mLayers ); if ( mLayerCount >= mMaxLayers ) return NULL; switch ( Type ) { case MAP_LAYER_TILED: mLayers[ mLayerCount ] = eeNew( cTileLayer, ( this, mSize, flags, name ) ); break; case MAP_LAYER_OBJECT: mLayers[ mLayerCount ] = eeNew( cObjectLayer, ( this, flags, name ) ); break; default: return NULL; } mLayerCount++; return mLayers[ mLayerCount - 1 ]; } cLayer* cMap::GetLayer( Uint32 index ) { eeASSERT( index < mLayerCount ); return mLayers[ index ]; } cLayer* cMap::GetLayerByHash( Uint32 hash ) { for ( Uint32 i = 0; i < mLayerCount; i++ ) { if ( mLayers[i]->Id() == hash ) return mLayers[i]; } return NULL; } Uint32 cMap::GetLayerIndex( cLayer * Layer ) { if ( NULL != Layer ) { for ( Uint32 i = 0; i < mLayerCount; i++ ) { if ( mLayers[i] == Layer ) return i; } } return MAP_LAYER_UNKNOWN; } cLayer* cMap::GetLayer( const std::string& name ) { return GetLayerByHash( MakeHash( name ) ); } void cMap::Draw() { cGlobalBatchRenderer::instance()->Draw(); if ( ClipedArea() ) { mWindow->ClipEnable( mScreenPos.x, mScreenPos.y, mViewSize.x, mViewSize.y ); } mOffsetFixed = eeVector2f( (eeFloat)mScreenPos.x, (eeFloat)mScreenPos.y ) + FixOffset(); GetMouseOverTile(); GridDraw(); for ( Uint32 i = 0; i < mLayerCount; i++ ) { mLayers[i]->Draw( mOffsetFixed ); } MouseOverDraw(); if ( ClipedArea() ) { mWindow->ClipDisable(); } } void cMap::MouseOverDraw() { if ( !DrawTileOver() ) return; cPrimitives P; P.SetColor( eeColorA( 255, 0, 0, 255 ) ); P.DrawRectangle( mOffsetFixed.x + mMouseOverTileFinal.x * mTileSize.x, mOffsetFixed.y + mMouseOverTileFinal.y * mTileSize.y, mTileSize.x, mTileSize.y, 0.f, 1.f, EE_DRAW_LINE ); } void cMap::GridDraw() { cPrimitives P; P.SetColor( eeColorA( 0, 0, 0, 50 ) ); P.DrawRectangle( mScreenPos.x, mScreenPos.y, mViewSize.x, mViewSize.y, 0.f, 1.f ); P.SetColor( eeColorA( 255, 255, 255, 255 ) ); if ( !DrawGrid() ) return; if ( 0 == mSize.x || 0 == mSize.y ) return; cGlobalBatchRenderer::instance()->Draw(); GLi->LoadIdentity(); GLi->PushMatrix(); GLi->Translatef( mOffsetFixed.x, mOffsetFixed.y, 0.0f ); eeVector2i start = StartTile(); eeVector2i end = EndTile(); eeFloat tx, ty; for ( Int32 x = start.x; x < end.x; x++ ) { for ( Int32 y = start.y; y < end.y; y++ ) { tx = x * mTileSize.x; ty = y * mTileSize.y; mTileTex->Draw( tx, ty ); } } cGlobalBatchRenderer::instance()->Draw(); GLi->PopMatrix(); } void cMap::GetMouseOverTile() { eeVector2i mouse = mWindow->GetInput()->GetMousePos(); eeVector2i MapPos( mouse.x - mScreenPos.x - mOffset.x, mouse.y - mScreenPos.y - mOffset.y ); if ( MapPos.x < 0 ) MapPos.x = 0; if ( MapPos.y < 0 ) MapPos.y = 0; if ( MapPos.x > mPixelSize.x ) MapPos.x = mPixelSize.x; if ( MapPos.y > mPixelSize.y ) MapPos.y = mPixelSize.y; mMouseOverTile.x = MapPos.x / mTileSize.Width(); mMouseOverTile.y = MapPos.y / mTileSize.Height(); if ( mMouseOverTile.x < 0 ) mMouseOverTile.x = 0; if ( mMouseOverTile.y < 0 ) mMouseOverTile.y = 0; if ( mMouseOverTile.x >= mSize.Width() ) mMouseOverTile.x = mSize.Width() - 1; if ( mMouseOverTile.y >= mSize.Height() ) mMouseOverTile.y = mSize.Height() - 1; // Clamped pos mMouseOverTileFinal = eeVector2i( mMouseOverTile.x, mMouseOverTile.y ); mMouseMapPos = eeVector2i( MapPos.x, MapPos.y ); } void cMap::Update() { for ( Uint32 i = 0; i < mLayerCount; i++ ) mLayers[i]->Update(); } const eeSize& cMap::ViewSize() const { return mViewSize; } const eeVector2i& cMap::GetMouseTilePos() const { return mMouseOverTileFinal; } const eeVector2i& cMap::GetMouseMapPos() const { return mMouseMapPos; } void cMap::ViewSize( const eeSize& viewSize ) { mViewSize = viewSize; Clamp(); CalcTilesClip(); } const eeVector2i& cMap::Position() const { return mScreenPos; } void cMap::Position( const eeVector2i& position ) { mScreenPos = position; } const eeVector2f& cMap::Offset() const { return mOffset; } const eeVector2i& cMap::StartTile() const { return mStartTile; } const eeVector2i& cMap::EndTile() const { return mEndTile; } void cMap::Offset( const eeVector2f& offset ) { mOffset = offset; Clamp(); CalcTilesClip(); } void cMap::CalcTilesClip() { if ( mTileSize.x > 0 && mTileSize.y > 0 ) { eeVector2f ffoff( FixOffset() ); eeVector2i foff( (Int32)ffoff.x, (Int32)ffoff.y ); mStartTile.x = -foff.x / mTileSize.x; mStartTile.y = -foff.y / mTileSize.y; mEndTile.x = mStartTile.x + eeRound( (eeFloat)mViewSize.x / (eeFloat)mTileSize.x ) + 1; mEndTile.y = mStartTile.y + eeRound( (eeFloat)mViewSize.y / (eeFloat)mTileSize.y ) + 1; if ( mStartTile.x < 0 ) mStartTile.x = 0; if ( mStartTile.y < 0 ) mStartTile.y = 0; if ( mEndTile.x > mSize.x ) mEndTile.x = mSize.x; if ( mEndTile.y > mSize.y ) mEndTile.y = mSize.y; } } void cMap::Clamp() { if ( !ClampBorders() ) return; if ( mOffset.x > 0 ) mOffset.x = 0; if ( mOffset.y > 0 ) mOffset.y = 0; eeSize totSize( mTileSize * mSize ); if ( -mOffset.x + mViewSize.x > totSize.x ) mOffset.x = -( totSize.x - mViewSize.x ); if ( -mOffset.y + mViewSize.y > totSize.y ) mOffset.y = -( totSize.y - mViewSize.y ); if ( totSize.x < mViewSize.x ) mOffset.x = 0; if ( totSize.y < mViewSize.y ) mOffset.y = 0; } void cMap::DrawGrid( const bool& draw ) { SetFlagValue( &mFlags, MAP_FLAG_DRAW_GRID, draw ? 1 : 0 ); } Uint32 cMap::DrawGrid() const { return mFlags & MAP_FLAG_DRAW_GRID; } Uint32 cMap::ClipedArea() const { return mFlags & MAP_FLAG_CLIP_AREA; } Uint32 cMap::ClampBorders() const { return mFlags & MAP_FLAG_CLAMP_BODERS; } Uint32 cMap::DrawTileOver() const { return mFlags & MAP_FLAG_DRAW_TILE_OVER; } void cMap::DrawTileOver( const bool& draw ) { SetFlagValue( &mFlags, MAP_FLAG_DRAW_TILE_OVER, draw ? 1 : 0 ); } eeVector2f cMap::FixOffset() { return eeVector2f( (eeFloat)static_cast( mOffset.x ), (eeFloat)static_cast( mOffset.y ) ); } void cMap::Move( const eeVector2f& offset ) { Move( offset.x, offset.y ); } void cMap::Move( const eeFloat& offsetx, const eeFloat& offsety ) { Offset( eeVector2f( mOffset.x + offsetx, mOffset.y + offsety ) ); } cGameObject * cMap::CreateGameObject( const Uint32& Type, const Uint32& Flags, const Uint32& DataId ) { switch ( Type ) { case GAMEOBJECT_TYPE_SHAPE: { cGameObjectShape * tShape = eeNew( cGameObjectShape, ( Flags ) ); tShape->DataId( DataId ); return tShape; } case GAMEOBJECT_TYPE_SHAPEEX: { cGameObjectShapeEx * tShapeEx = eeNew( cGameObjectShapeEx, ( Flags ) ); tShapeEx->DataId( DataId ); return tShapeEx; } case GAMEOBJECT_TYPE_SPRITE: { cGameObjectSprite * tSprite = eeNew( cGameObjectSprite, ( Flags ) ); tSprite->DataId( DataId ); return tSprite; } default: { if ( mCreateGOCb.IsSet() ) { return mCreateGOCb( Type, Flags, DataId ); } else { cGameObjectVirtual * tVirtual; cShape * tIsShape = cShapeGroupManager::instance()->GetShapeById( DataId ); if ( NULL != tIsShape ) { tVirtual = eeNew( cGameObjectVirtual, ( tIsShape, Flags, Type ) ); } else { tVirtual = eeNew( cGameObjectVirtual, ( DataId, Flags, Type ) ); } return tVirtual; } } } return NULL; } const eeSize& cMap::TotalSize() const { return mPixelSize; } const eeSize& cMap::TileSize() const { return mTileSize; } const eeSize& cMap::Size() const { return mSize; } const Uint32& cMap::LayerCount() const { return mLayerCount; } const Uint32& cMap::MaxLayers() const { return mMaxLayers; } bool cMap::MoveLayerUp( cLayer * Layer ) { Uint32 Lindex = GetLayerIndex( Layer ); if ( Lindex != MAP_LAYER_UNKNOWN && mLayerCount > 1 && ( Lindex < mLayerCount - 1 ) && ( Lindex + 1 < mLayerCount ) ) { cLayer * tLayer = mLayers[ Lindex + 1 ]; mLayers[ Lindex ] = tLayer; mLayers[ Lindex + 1 ] = Layer; return true; } return false; } bool cMap::MoveLayerDown( cLayer * Layer ) { Uint32 Lindex = GetLayerIndex( Layer ); if ( Lindex != MAP_LAYER_UNKNOWN && mLayerCount > 1 && Lindex >= 1 ) { cLayer * tLayer = mLayers[ Lindex - 1 ]; mLayers[ Lindex ] = tLayer; mLayers[ Lindex - 1 ] = Layer; return true; } return false; } bool cMap::RemoveLayer( cLayer * Layer ) { Uint32 Lindex = GetLayerIndex( Layer ); if ( Lindex != MAP_LAYER_UNKNOWN ) { eeSAFE_DELETE( mLayers[ Lindex ] ); cLayer * LastLayer = NULL; // Reorder layers, to clean empty layers in between layers. for ( Uint32 i = 0; i < mLayerCount; i++ ) { if ( i > 0 && NULL != mLayers[i] && NULL == LastLayer ) { mLayers[ i - 1 ] = mLayers[ i ]; mLayers[ i ] = NULL; } LastLayer = mLayers[i]; } mLayerCount--; return true; } return false; } void cMap::ClearProperties() { mProperties.clear(); } void cMap::AddProperty( std::string Text, std::string Value ) { mProperties[ Text ] = Value; } void cMap::EditProperty( std::string Text, std::string Value ) { mProperties[ Text ] = Value; } void cMap::RemoveProperty( std::string Text ) { mProperties.erase( Text ); } cMap::PropertiesMap& cMap::GetProperties() { return mProperties; } void cMap::AddVirtualObjectType( const std::string& name ) { mObjTypes.push_back( name ); mObjTypes.unique(); } void cMap::RemoveVirtualObjectType( const std::string& name ) { mObjTypes.remove( name ); } void cMap::ClearVirtualObjectTypes() { mObjTypes.clear(); } cMap::GOTypesList& cMap::GetVirtualObjectTypes() { return mObjTypes; } void cMap::SetCreateGameObjectCallback( const CreateGOCb& Cb ) { mCreateGOCb = Cb; } #define MAP_PROPERTY_SIZE (64) #define LAYER_NAME_SIZE (64) #define MAP_SHAPEGROUP_PATH_SIZE (128) typedef struct sPropertyHdrS { char Name[ MAP_PROPERTY_SIZE ]; char Value[ MAP_PROPERTY_SIZE ]; } sPropertyHdr; typedef struct sMapShapeGroupS { char Path[ MAP_SHAPEGROUP_PATH_SIZE ]; } sMapShapeGroup; typedef struct sVirtualObjS { char Name[ MAP_PROPERTY_SIZE ]; } sVirtualObj; typedef struct sMapHdrS { Uint32 Magic; Uint32 SizeX; Uint32 SizeY; Uint32 TileSizeX; Uint32 TileSizeY; Uint32 MaxLayers; Uint32 LayerCount; Uint32 Flags; Uint32 PropertyCount; Uint32 ShapeGroupCount; Uint32 VirtualObjectTypesCount; } sMapHdr; typedef struct sLayerHdrS { char Name[ LAYER_NAME_SIZE ]; Uint32 Type; Uint32 Flags; Int32 OffsetX; Int32 OffsetY; Uint32 PropertyCount; Uint32 ObjectCount; //! Only used by the Object Layer } sLayerHdr; typedef struct sMapTileGOHdrS { Uint32 Type; Uint32 Id; Uint32 Flags; } sMapTileGOHdr; typedef struct sMapObjGOHdrS { Uint32 Type; Uint32 Id; Uint32 Flags; Int32 PosX; Int32 PosY; } sMapObjGOHdr; bool cMap::LoadFromStream( cIOStream& IOS ) { sMapHdr MapHdr; Uint32 i, z; if ( IOS.IsOpen() ) { IOS.Read( (char*)&MapHdr, sizeof(sMapHdr) ); if ( MapHdr.Magic == ( ( 'E' << 0 ) | ( 'E' << 8 ) | ( 'M' << 16 ) | ( 'P' << 24 ) ) ) { Create( eeSize( MapHdr.SizeX, MapHdr.SizeY ), MapHdr.MaxLayers, eeSize( MapHdr.TileSizeX, MapHdr.TileSizeY ), MapHdr.Flags ); //! Load Properties if ( MapHdr.PropertyCount ) { sPropertyHdr tProp[ MapHdr.PropertyCount ]; IOS.Read( (char*)&tProp[0], sizeof(sPropertyHdr) * MapHdr.PropertyCount ); for ( i = 0; i < MapHdr.PropertyCount; i++ ) { AddProperty( std::string( tProp[i].Name ), std::string( tProp[i].Value ) ); } } //! Load Shape Groups if ( MapHdr.ShapeGroupCount ) { sMapShapeGroup tSG[ MapHdr.ShapeGroupCount ]; IOS.Read( (char*)&tSG[0], sizeof(sMapShapeGroup) * MapHdr.ShapeGroupCount ); std::vector ShapeGroups; for ( i = 0; i < MapHdr.ShapeGroupCount; i++ ) { ShapeGroups.push_back( std::string( tSG[i].Path ) ); } //! Load the Texture groups if needed //! @TODO: Load TGPs } //! Load Virtual Object Types if ( MapHdr.VirtualObjectTypesCount ) { sVirtualObj tVObj[ MapHdr.VirtualObjectTypesCount ]; IOS.Read( (char*)&tVObj[0], sizeof(sVirtualObj) * MapHdr.VirtualObjectTypesCount ); for ( i = 0; i < MapHdr.VirtualObjectTypesCount; i++ ) { AddVirtualObjectType( std::string( tVObj[i].Name ) ); } } //! Load Layers if ( MapHdr.LayerCount ) { sLayerHdr tLayersHdr[ MapHdr.LayerCount ]; sLayerHdr * tLayerHdr; IOS.Read( (char*)&tLayersHdr[0], sizeof(sLayerHdr) * MapHdr.LayerCount ); for ( i = 0; i < MapHdr.LayerCount; i++ ) { tLayerHdr = &(tLayersHdr[i]); cLayer * tLayer = AddLayer( tLayerHdr->Type, tLayerHdr->Flags, std::string( tLayerHdr->Name ) ); tLayer->Offset( eeVector2f( (eeFloat)tLayerHdr->OffsetX, (eeFloat)tLayerHdr->OffsetY ) ); sPropertyHdr tProps[ tLayerHdr->PropertyCount ]; IOS.Read( (char*)&tProps[0], sizeof(sPropertyHdr) * tLayerHdr->PropertyCount ); for ( z = 0; z < tLayerHdr->PropertyCount; z++ ) { tLayer->AddProperty( std::string( tProps[z].Name ), std::string( tProps[z].Value ) ); } } bool ThereIsTiled = false; for ( i = 0; i < mLayerCount; i++ ) { if ( NULL != mLayers[i] && mLayers[i]->Type() == MAP_LAYER_TILED ) { ThereIsTiled = true; } } Int32 x, y; Uint32 tReadFlag = 0; cTileLayer * tTLayer; cGameObject * tGO; if ( ThereIsTiled ) { //! First we read the tiled layers. for ( y = 0; y < mSize.y; y++ ) { for ( x = 0; x < mSize.x; x++ ) { //! Read the current tile flags IOS.Read( (char*)&tReadFlag, sizeof(Uint32) ); //! Read every game object header corresponding to this tile for ( i = 0; i < mLayerCount; i++ ) { if ( tReadFlag & ( 1 << i ) ) { tTLayer = reinterpret_cast ( mLayers[i] ); sMapTileGOHdr tTGOHdr; IOS.Read( (char*)&tTGOHdr, sizeof(sMapTileGOHdr) ); tGO = CreateGameObject( tTGOHdr.Type, tTGOHdr.Flags, tTGOHdr.Id ); tTLayer->AddGameObject( tGO, eeVector2i( x, y ) ); } } } } } //! Load the game objects from the object layers cObjectLayer * tOLayer; for ( i = 0; i < mLayerCount; i++ ) { if ( NULL != mLayers[i] && mLayers[i]->Type() == MAP_LAYER_OBJECT ) { tLayerHdr = &( tLayersHdr[i] ); tOLayer = reinterpret_cast ( mLayers[i] ); sMapObjGOHdr tOGOsHdr[ tLayerHdr->ObjectCount ]; sMapObjGOHdr * tOGOHdr; IOS.Read( (char*)&tOGOsHdr, sizeof(sMapObjGOHdr) * tLayerHdr->ObjectCount ); for ( z = 0; z < tLayerHdr->ObjectCount; z++ ) { tOGOHdr = &( tOGOsHdr[z] ); tGO = CreateGameObject( tOGOHdr->Type, tOGOHdr->Flags, tOGOHdr->Id ); tGO->Pos( eeVector2f( tOGOHdr->PosX, tOGOHdr->PosY ) ); tOLayer->AddGameObject( tGO ); } } } } return true; } } return false; } bool cMap::Load( const std::string& path ) { if ( FileExists( path ) ) { cIOStreamFile IOS( path, std::ios::in | std::ios::binary ); return LoadFromStream( IOS ); } return false; } void cMap::SaveToStream( cIOStream& IOS ) { Uint32 i; sMapHdr MapHdr; cLayer * tLayer; std::vector ShapeGroups = GetShapeGroups(); MapHdr.Magic = ( ( 'E' << 0 ) | ( 'E' << 8 ) | ( 'M' << 16 ) | ( 'P' << 24 ) ); MapHdr.Flags = mFlags; MapHdr.MaxLayers = mMaxLayers; MapHdr.SizeX = mSize.Width(); MapHdr.SizeY = mSize.Height(); MapHdr.TileSizeX = mTileSize.Width(); MapHdr.TileSizeY = mTileSize.Height(); MapHdr.LayerCount = mLayerCount; MapHdr.PropertyCount = mProperties.size(); MapHdr.ShapeGroupCount = ShapeGroups.size(); MapHdr.VirtualObjectTypesCount = mObjTypes.size(); //! This is only usefull for the Map Editor, to auto add on the load the virtual object types that where used to create the map. if ( IOS.IsOpen() ) { //! Writes the map header IOS.Write( (const char*)&MapHdr, sizeof(sMapHdr) ); //! Writes the properties of the map for ( cMap::PropertiesMap::iterator it = mProperties.begin(); it != mProperties.end(); it++ ) { sPropertyHdr tProp; memset( tProp.Name, 0, MAP_PROPERTY_SIZE ); memset( tProp.Value, 0, MAP_PROPERTY_SIZE ); StrCopy( tProp.Name, (*it).first.c_str(), MAP_PROPERTY_SIZE ); StrCopy( tProp.Value, (*it).second.c_str(), MAP_PROPERTY_SIZE ); IOS.Write( (const char*)&tProp, sizeof(sPropertyHdr) ); } //! Writes the shape groups that the map will need and load for ( i = 0; i < ShapeGroups.size(); i++ ) { sMapShapeGroup tSG; memset( tSG.Path, 0, MAP_SHAPEGROUP_PATH_SIZE ); StrCopy( tSG.Path, ShapeGroups[i].c_str(), MAP_SHAPEGROUP_PATH_SIZE ); IOS.Write( (const char*)&tSG, sizeof(sMapShapeGroup) ); } //! Writes the names of the virtual object types created in the map editor for ( GOTypesList::iterator votit = mObjTypes.begin(); votit != mObjTypes.end(); votit++ ) { sVirtualObj tVObjH; memset( tVObjH.Name, 0, MAP_PROPERTY_SIZE ); StrCopy( tVObjH.Name, (*votit).c_str(), MAP_PROPERTY_SIZE ); IOS.Write( (const char*)&tVObjH, sizeof(sVirtualObj) ); } //! Writes every layer header for ( i = 0; i < mLayerCount; i++ ) { tLayer = mLayers[i]; sLayerHdr tLayerH; memset( tLayerH.Name, 0, LAYER_NAME_SIZE ); StrCopy( tLayerH.Name, tLayer->Name().c_str(), LAYER_NAME_SIZE ); tLayerH.Type = tLayer->Type(); tLayerH.Flags = tLayer->Flags(); tLayerH.OffsetX = tLayer->Offset().x; tLayerH.OffsetY = tLayer->Offset().y; if ( MAP_LAYER_OBJECT == tLayerH.Type ) tLayerH.ObjectCount = reinterpret_cast ( tLayer )->GetObjectCount(); else tLayerH.ObjectCount = 0; cLayer::PropertiesMap& tLayerProp = tLayer->GetProperties(); tLayerH.PropertyCount = tLayerProp.size(); //! Writes the layer header IOS.Write( (const char*)&tLayerH, sizeof(sLayerHdr) ); //! Writes the properties of the current layer for ( cLayer::PropertiesMap::iterator lit = tLayerProp.begin(); lit != tLayerProp.end(); lit++ ) { sPropertyHdr tProp; memset( tProp.Name, 0, MAP_PROPERTY_SIZE ); memset( tProp.Value, 0, MAP_PROPERTY_SIZE ); StrCopy( tProp.Name, (*lit).first.c_str(), MAP_PROPERTY_SIZE ); StrCopy( tProp.Value, (*lit).second.c_str(), MAP_PROPERTY_SIZE ); IOS.Write( (const char*)&tProp, sizeof(sPropertyHdr) ); } } bool ThereIsTiled = false; for ( i = 0; i < mLayerCount; i++ ) { if ( NULL != mLayers[i] && mLayers[i]->Type() == MAP_LAYER_TILED ) { ThereIsTiled = true; } } //! This method is slow, but allows to save big maps with little space needed, i'll add an alternative save method ( just plain layer -> tile object saving ) Int32 x, y; Uint32 tReadFlag = 0, z; cTileLayer * tTLayer; cGameObject * tObj; cGameObject * tObjects[ mLayerCount ]; if ( ThereIsTiled ) { //! First we save the tiled layers. for ( y = 0; y < mSize.y; y++ ) { for ( x = 0; x < mSize.x; x++ ) { //! Reset Layer Read Flags and temporal objects tReadFlag = 0; for ( z = 0; z < mLayerCount; z++ ) tObjects[z] = NULL; //! Look at every layer if it's some data on the current tile, in that case it will write a bit flag to //! inform that it's an object on the current tile layer, and it will store a temporal reference to the //! object to write layer the object header information for ( i = 0; i < mLayerCount; i++ ) { tLayer = mLayers[i]; if ( NULL != tLayer && tLayer->Type() == MAP_LAYER_TILED ) { tTLayer = reinterpret_cast ( tLayer ); tObj = tTLayer->GetGameObject( eeVector2i( x, y ) ); if ( NULL != tObj ) { tReadFlag |= 1 << i; tObjects[i] = tObj; } } } //! Writes the current tile flags IOS.Write( (const char*)&tReadFlag, sizeof(Uint32) ); //! Writes every game object header corresponding to this tile for ( i = 0; i < mLayerCount; i++ ) { if ( tReadFlag & ( 1 << i ) ) { tObj = tObjects[i]; sMapTileGOHdr tTGOHdr; //! The DataId should be the Shape hash name ( at least in the cases of type Shape, ShapeEx and Sprite. tTGOHdr.Id = tObj->DataId(); //! If the object type is virtual, means that the real type is stored elsewhere. if ( tObj->Type() != GAMEOBJECT_TYPE_VIRTUAL ) { tTGOHdr.Type = tObj->Type(); } else { cGameObjectVirtual * tObjV = reinterpret_cast ( tObj ); tTGOHdr.Type = tObjV->RealType(); } tTGOHdr.Flags = tObj->Flags(); IOS.Write( (const char*)&tTGOHdr, sizeof(sMapTileGOHdr) ); } } } } } //! Then we save the Object layers. cObjectLayer * tOLayer; for ( i = 0; i < mLayerCount; i++ ) { tLayer = mLayers[i]; if ( NULL != tLayer && tLayer->Type() == MAP_LAYER_OBJECT ) { tOLayer = reinterpret_cast ( tLayer ); cObjectLayer::ObjList ObjList = tOLayer->GetObjectList(); for ( cObjectLayer::ObjList::iterator MapObjIt = ObjList.begin(); MapObjIt != ObjList.end(); MapObjIt++ ) { tObj = (*MapObjIt); sMapObjGOHdr tOGOHdr; //! The DataId should be the Shape hash name ( at least in the cases of type Shape, ShapeEx and Sprite. tOGOHdr.Id = tObj->DataId(); //! If the object type is virtual, means that the real type is stored elsewhere. if ( tObj->Type() != GAMEOBJECT_TYPE_VIRTUAL ) { tOGOHdr.Type = tObj->Type(); } else { cGameObjectVirtual * tObjV = reinterpret_cast ( tObj ); tOGOHdr.Type = tObjV->RealType(); } tOGOHdr.Flags = tObj->Flags(); tOGOHdr.PosX = (Int32)tObj->Pos().x; tOGOHdr.PosY = (Int32)tObj->Pos().y; IOS.Write( (const char*)&tOGOHdr, sizeof(sMapObjGOHdr) ); } } } } } void cMap::Save( const std::string& path ) { cIOStreamFile IOS( path, std::ios::out | std::ios::binary ); SaveToStream( IOS ); } std::vector cMap::GetShapeGroups() { cShapeGroupManager * SGM = cShapeGroupManager::instance(); std::list& Res = SGM->GetResources(); std::vector items; //! Ugly ugly ugly, but i don't see another way Uint32 Restricted1 = MakeHash( std::string( "global" ) ); Uint32 Restricted2 = MakeHash( UI::cUIThemeManager::instance()->DefaultTheme()->ShapeGroup()->Name() ); for ( std::list::iterator it = Res.begin(); it != Res.end(); it++ ) { if ( (*it)->Id() != Restricted1 && (*it)->Id() != Restricted2 ) items.push_back( (*it)->Path() ); } return items; } }}