1
0
mirror of https://github.com/ScrelliCopter/tmx2gba.git synced 2025-02-21 03:29:25 +11:00

Tiles are now local IDs (relative to the tileset), making collision data usable.

Palettes can be overridden per-tile thru a layer.
This commit is contained in:
2015-10-26 17:09:27 +11:00
parent f213fca3cc
commit b7e320824b
11 changed files with 269 additions and 67 deletions

2
.gitignore vendored
View File

@@ -38,3 +38,5 @@ Release/
# Some files I used for testing.
*.tmx
*.raw
plains.png
editor.png

BIN
palette.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

View File

@@ -31,11 +31,12 @@
#include <XGetopt.h>
static const std::string g_strUsage = "Usage: tmx2gba [-h] [-r offset] [-lc name] [-p 0-15] <-i inpath> <-o outpath>\nRun 'tmx2gba -h' to view all available options.";
static const std::string g_strFullHelp = R"(Usage: tmx2gba [-hr] [-p index] <-i inpath> <-o outpath>
static const std::string g_strUsage = "Usage: tmx2gba [-h] [-r offset] [-lyc name] [-p 0-15] <-i inpath> <-o outpath>\nRun 'tmx2gba -h' to view all available options.";
static const std::string g_strFullHelp = R"(Usage: tmx2gba [-h] [-r offset] [-lyc name] [-p 0-15] <-i inpath> <-o outpath>
-h ---------- Display this help & command info.
-l <name> --- Name of layer to use (default first layer in TMX).
-y <name> --- Layer for palette mappings.
-c <name> --- Output a separate 8bit collision map of the specified layer.
-r <offset> - Offset tile indices (default 0).
-p <0-15> --- Select which palette to use for 4-bit tilesets.
@@ -154,23 +155,34 @@ int main ( int argc, char** argv )
}
// Convert to GBA-friendly charmap data.
const uint16_t* pRead = (const uint16_t*)pLayerGfx->GetData ();
//const uint16_t* pPalRead = (const uint16_t*)pLayerPal->GetData ();
const uint32_t* pRead = pLayerGfx->GetData ();
const uint32_t* pPalRead = pLayerPal == nullptr ? nullptr : pLayerPal->GetData ();
std::vector<uint16_t> vucCharDat;
vucCharDat.reserve ( pLayerGfx->GetWidth () * pLayerGfx->GetHeight () );
for ( size_t i = 0; i < size_t(pLayerGfx->GetWidth () * pLayerGfx->GetHeight () * 2); ++i )
{
uint16_t usTile = std::max<uint16_t> ( (*pRead++) + (uint16_t)params.offset, 0 );
bool bFlipH = ( 0x8000 & *pRead ) ? true : false;
bool bFlipV = ( 0x4000 & *pRead++ ) ? true : false;
uint32_t uiRead = (*pRead++);
uint8_t ucTile = (uint8_t)std::max<uint32_t> ( 0, tmx.LidFromGid ( uiRead & ~FLIP_MASK ) + params.offset );
uint8_t ucFlags = 0x0;
ucFlags |= ( bFlipH ) ? 0x4 : 0x0;
ucFlags |= ( bFlipV ) ? 0x8 : 0x0;
ucFlags |= params.palette << 4;
vucCharDat.push_back ( usTile | ucFlags << 8 );
// Get flipped!
ucFlags |= ( uiRead & FLIP_HORZ ) ? 0x4 : 0x0;
ucFlags |= ( uiRead & FLIP_VERT ) ? 0x8 : 0x0;
// Determine palette ID.
uint32_t uiIndex = 0;
if ( pPalRead != nullptr )
{
uiIndex = tmx.LidFromGid ( *pPalRead++ & ~FLIP_MASK );
}
if ( uiIndex == 0 )
{
uiIndex = ( params.palette << 4 ) + 1;
}
ucFlags |= (uint8_t)(uiIndex - 1);
vucCharDat.push_back ( (uint16_t)ucTile | (uint16_t)ucFlags << 8 );
}
// Save out charmap.
@@ -189,11 +201,10 @@ int main ( int argc, char** argv )
std::vector<uint8_t> vucCollisionDat;
vucCollisionDat.reserve ( pLayerCls->GetWidth () * pLayerCls->GetHeight () );
const uint8_t* pRead = (const uint8_t*)pLayerCls->GetData ();
const uint32_t* pRead = pLayerCls->GetData ();
for ( size_t i = 0; i < pLayerCls->GetWidth () * pLayerCls->GetHeight (); ++i )
{
uint8_t ucTile = *pRead;
pRead += 4;
uint8_t ucTile = (uint8_t)tmx.LidFromGid ( (*pRead++) & ~FLIP_MASK );
vucCollisionDat.push_back ( ucTile );
}

View File

@@ -32,7 +32,7 @@ CTmxLayer::CTmxLayer () :
}
CTmxLayer::CTmxLayer ( int a_iWidth, int a_iHeight, const char* a_szName, uint8_t* a_pTileDat ) :
CTmxLayer::CTmxLayer ( int a_iWidth, int a_iHeight, const char* a_szName, uint32_t* a_pTileDat ) :
m_iWidth ( a_iWidth ),
m_iHeight ( a_iHeight ),
m_strName ( a_szName ),
@@ -62,7 +62,7 @@ int CTmxLayer::GetHeight () const
return m_iHeight;
}
const uint8_t* CTmxLayer::GetData () const
const uint32_t* CTmxLayer::GetData () const
{
return m_pTileDat;
}

View File

@@ -4,22 +4,27 @@
#include <string>
#include <cstdint>
const uint32_t FLIP_HORZ = 0x80000000;
const uint32_t FLIP_VERT = 0x40000000;
const uint32_t FLIP_DIAG = 0x20000000;
const uint32_t FLIP_MASK = 0xE0000000;
class CTmxLayer
{
public:
CTmxLayer ();
CTmxLayer ( int a_iWidth, int a_iHeight, const char* a_szName, uint8_t* a_pTileDat );
CTmxLayer ( int a_iWidth, int a_iHeight, const char* a_szName, uint32_t* a_pTileDat );
~CTmxLayer ();
const std::string& GetName () const;
int GetWidth () const;
int GetHeight () const;
const uint8_t* GetData () const;
const uint32_t* GetData () const;
private:
std::string m_strName;
int m_iWidth, m_iHeight;
uint8_t* m_pTileDat;
uint32_t* m_pTileDat;
};

View File

@@ -21,9 +21,11 @@
*/
#include "tmxreader.h"
#include "tmxtileset.h"
#include "tmxlayer.h"
#include <cstdint>
#include <sstream>
#include <algorithm>
#include <rapidxml/rapidxml.hpp>
#include <base64.h>
#include <miniz.h>
@@ -36,6 +38,13 @@ CTmxReader::CTmxReader ()
CTmxReader::~CTmxReader ()
{
// Delete old tilesets.
for ( auto pTileset : m_vpTileset )
{
delete pTileset;
}
m_vpTileset.clear ();
// Delete old layers.
for ( auto pLay : m_vpLayers )
{
@@ -45,7 +54,7 @@ CTmxReader::~CTmxReader ()
}
bool DecodeMap ( uint8_t* a_szOut, size_t a_outSize, const std::string& a_strIn )
bool CTmxReader::DecodeMap ( uint32_t* a_pOut, size_t a_outSize, const std::string& a_strIn )
{
// Decode base64 string.
size_t cutTheCrap = a_strIn.find_first_not_of ( " \t\n\r" );
@@ -54,8 +63,8 @@ bool DecodeMap ( uint8_t* a_szOut, size_t a_outSize, const std::string& a_strIn
// Decompress compressed data.
mz_ulong uiDstSize = a_outSize;
int iRes = uncompress (
a_szOut, &uiDstSize,
(const uint8_t*)strDec.data (), strDec.size ()
(unsigned char*)a_pOut, &uiDstSize,
(const unsigned char*)strDec.data (), strDec.size ()
);
strDec.clear ();
if ( iRes < 0 )
@@ -66,8 +75,91 @@ bool DecodeMap ( uint8_t* a_szOut, size_t a_outSize, const std::string& a_strIn
return true;
}
void CTmxReader::ReadTileset ( rapidxml::xml_node<>* a_xNode )
{
rapidxml::xml_attribute<>* xAttrib;
const char* szName = "";
const char* szSource = "";
uint32_t uiFirstGid = 0;
// Read name.
xAttrib = a_xNode->first_attribute ( "name" );
if ( xAttrib != nullptr )
{
szName = xAttrib->value ();
}
// Read source.
xAttrib = a_xNode->first_attribute ( "source" );
if ( xAttrib != nullptr )
{
szSource = xAttrib->value ();
}
// Read first global ID.
xAttrib = a_xNode->first_attribute ( "firstgid" );
if ( xAttrib != nullptr )
{
uiFirstGid = std::stoul ( xAttrib->value () );
}
m_vpTileset.push_back ( new CTmxTileset ( szName, szSource, uiFirstGid ) );
}
void CTmxReader::ReadLayer ( rapidxml::xml_node<>* a_xNode )
{
rapidxml::xml_attribute<>* xAttrib;
const char* szName = "";
int iWidth = 0;
int iHeight = 0;
uint32_t* pTileDat = nullptr;
// Read name.
xAttrib = a_xNode->first_attribute ( "name" );
if ( xAttrib != nullptr )
{
szName = xAttrib->value ();
}
// Read width.
xAttrib = a_xNode->first_attribute ( "width" );
if ( xAttrib != nullptr )
{
iWidth = std::stoi ( xAttrib->value () );
}
// Read height.
xAttrib = a_xNode->first_attribute ( "height" );
if ( xAttrib != nullptr )
{
iHeight = std::stoi ( xAttrib->value () );
}
// Read tile data.
auto xData = a_xNode->first_node ( "data" );
if ( xData != nullptr )
{
// TODO: don't assume base64 & zlib.
pTileDat = new uint32_t[iWidth * iHeight];
if ( !DecodeMap ( pTileDat, iWidth * iHeight * sizeof(uint32_t), std::string ( xData->value () ) ) )
{
pTileDat = nullptr;
}
}
m_vpLayers.push_back ( new CTmxLayer ( iWidth, iHeight, szName, pTileDat ) );
}
void CTmxReader::Open ( std::istream& a_in )
{
// Delete old tilesets.
for ( auto pTileset : m_vpTileset )
{
delete pTileset;
}
m_vpTileset.clear ();
// Delete old layers.
for ( auto pLay : m_vpLayers )
{
@@ -75,6 +167,8 @@ void CTmxReader::Open ( std::istream& a_in )
}
m_vpLayers.clear ();
m_vuiGidTable.clear ();
// Read string into a buffer.
std::stringstream buf;
buf << a_in.rdbuf ();
@@ -103,56 +197,27 @@ void CTmxReader::Open ( std::istream& a_in )
m_iHeight = std::stoi ( xAttrib->value () );
}
// Read layer nodes.
// Read nodes.
for ( auto xNode = xMap->first_node (); xNode != nullptr; xNode = xNode->next_sibling () )
{
// Make sure it's a layer.
if ( strcmp ( xNode->name (), "layer" ) != 0 )
// Read layer nodes.
if ( strcmp ( xNode->name (), "layer" ) == 0 )
{
continue;
ReadLayer ( xNode );
}
rapidxml::xml_attribute<>* xAttrib;
const char* szName = nullptr;
int iWidth = 0;
int iHeight = 0;
uint8_t* pTileDat = nullptr;
// Read name.
xAttrib = xNode->first_attribute ( "name" );
if ( xAttrib != nullptr )
else
if ( strcmp ( xNode->name (), "tileset" ) == 0 )
{
szName = xAttrib->value ();
}
// Read width.
xAttrib = xNode->first_attribute ( "width" );
if ( xAttrib != nullptr )
{
iWidth = std::stoi ( xAttrib->value () );
}
// Read height.
xAttrib = xNode->first_attribute ( "height" );
if ( xAttrib != nullptr )
{
iHeight = std::stoi ( xAttrib->value () );
}
// Read tile data.
auto xData = xNode->first_node ( "data" );
if ( xData != nullptr )
{
// TODO: don't assume base64 & zlib.
pTileDat = new uint8_t[iWidth * iHeight * 4];
if ( !DecodeMap ( pTileDat, iWidth * iHeight * 4, std::string ( xData->value () ) ) )
{
pTileDat = nullptr;
ReadTileset ( xNode );
}
}
m_vpLayers.push_back ( new CTmxLayer ( iWidth, iHeight, szName, pTileDat ) );
// Generate global id table.
for ( auto pTileset : m_vpTileset )
{
m_vuiGidTable.push_back ( pTileset->GetFirstGid () );
}
std::sort ( m_vuiGidTable.rbegin (), m_vuiGidTable.rend () );
}
@@ -189,3 +254,17 @@ int CTmxReader::GetLayerCount () const
{
return m_vpLayers.size ();
}
uint32_t CTmxReader::LidFromGid ( uint32_t a_uiGid )
{
for ( uint32_t uiFirst : m_vuiGidTable )
{
if ( uiFirst <= a_uiGid )
{
return a_uiGid - ( uiFirst - 1 );
}
}
return a_uiGid;
}

View File

@@ -3,8 +3,12 @@
#include <istream>
#include <vector>
#include <string>
#include <cstdint>
class CTmxTileset;
class CTmxLayer;
namespace rapidxml { template<class Ch = char> class xml_node; }
class CTmxReader
{
@@ -21,9 +25,17 @@ public:
const CTmxLayer* GetLayer ( std::string a_strName ) const;
int GetLayerCount () const;
uint32_t LidFromGid ( uint32_t a_uiGid );
private:
bool DecodeMap ( uint32_t* a_pOut, size_t a_outSize, const std::string& a_strIn );
void ReadTileset ( rapidxml::xml_node<>* a_xNode );
void ReadLayer ( rapidxml::xml_node<>* a_xNode );
int m_iWidth, m_iHeight;
std::vector<CTmxTileset*> m_vpTileset;
std::vector<CTmxLayer*> m_vpLayers;
std::vector<uint32_t> m_vuiGidTable;
};

60
src/tmxtileset.cpp Normal file
View File

@@ -0,0 +1,60 @@
/* tmxtileset.cpp
Copyright (C) 2015 Nicholas Curtis
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "tmxtileset.h"
CTmxTileset::CTmxTileset () :
m_strName ( "" ),
m_strSource ( "" ),
m_uiFirstGid ( 0 )
{
}
CTmxTileset::CTmxTileset ( const char* a_szName, const char* a_szSource, uint32_t a_uiFirstGid ) :
m_strName ( a_szName ),
m_strSource ( a_szSource ),
m_uiFirstGid ( a_uiFirstGid )
{
}
CTmxTileset::~CTmxTileset ()
{
}
const std::string& CTmxTileset::GetName () const
{
return m_strName;
}
const std::string& CTmxTileset::GetSource () const
{
return m_strSource;
}
uint32_t CTmxTileset::GetFirstGid () const
{
return m_uiFirstGid;
}

25
src/tmxtileset.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef __TMXTILESET_H__
#define __TMXTILESET_H__
#include <string>
#include <cstdint>
class CTmxTileset
{
public:
CTmxTileset ();
CTmxTileset ( const char* a_szName, const char* a_szSource, uint32_t a_uiFirstGid );
~CTmxTileset ();
const std::string& GetName () const;
const std::string& GetSource () const;
uint32_t GetFirstGid () const;
private:
std::string m_strName;
std::string m_strSource;
uint32_t m_uiFirstGid;
};
#endif//__TMXTILESET_H__

View File

@@ -71,6 +71,7 @@
<ClCompile Include="src\tmxlayer.cpp" />
<ClCompile Include="src\tmxreader.cpp" />
<ClCompile Include="src\XGetopt.cpp" />
<ClCompile Include="src\tmxtileset.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="inc\base64.h" />
@@ -82,6 +83,7 @@
<ClInclude Include="inc\XGetopt.h" />
<ClInclude Include="src\tmxlayer.h" />
<ClInclude Include="src\tmxreader.h" />
<ClInclude Include="src\tmxtileset.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -30,6 +30,9 @@
<ClCompile Include="src\tmxlayer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tmxtileset.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="inc\base64.h">
@@ -59,5 +62,8 @@
<ClInclude Include="src\tmxlayer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\tmxtileset.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>