mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-18 06:55:48 +03:00
1029 lines
24 KiB
C++
1029 lines
24 KiB
C++
#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<Int32>( mOffset.x ), (eeFloat)static_cast<Int32>( 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<std::string> 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<cTileLayer*> ( 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<cObjectLayer*> ( 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<std::string> 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<cObjectLayer*> ( 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<cTileLayer*> ( 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<cGameObjectVirtual*> ( 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<cObjectLayer*> ( 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<cGameObjectVirtual*> ( 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<std::string> cMap::GetShapeGroups() {
|
|
cShapeGroupManager * SGM = cShapeGroupManager::instance();
|
|
std::list<cShapeGroup*>& Res = SGM->GetResources();
|
|
|
|
std::vector<std::string> 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<cShapeGroup*>::iterator it = Res.begin(); it != Res.end(); it++ ) {
|
|
if ( (*it)->Id() != Restricted1 && (*it)->Id() != Restricted2 )
|
|
items.push_back( (*it)->Path() );
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
}}
|