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

Added object exporting & the ability to store arguments in a parameters file, woo!

I'll update the readme when I can be bothered.
This commit is contained in:
2016-04-04 02:51:24 +10:00
parent cacfa29501
commit 29b64fffaf
10 changed files with 439 additions and 128 deletions

3
.gitignore vendored
View File

@@ -43,3 +43,6 @@ editor.png
.vs/ .vs/
*.opendb *.opendb
gfx/ gfx/
res/
*.tmx2gba
map/

View File

@@ -15,9 +15,10 @@
#ifndef XGETOPT_H #ifndef XGETOPT_H
#define XGETOPT_H #define XGETOPT_H
extern int optind, opterr; extern int optind;
extern char *optarg; extern char *optarg, *next;
void getoptClear ();
int getopt(int argc, char *argv[], char *optstring); int getopt(int argc, char *argv[], char *optstring);
#endif //XGETOPT_H #endif //XGETOPT_H

View File

@@ -146,11 +146,18 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
char *optarg; // global argument pointer char *optarg; // global argument pointer
char *next;
int optind = 0; // global argv index int optind = 0; // global argv index
void getoptClear ()
{
optarg = nullptr;
next = nullptr;
optind = 0;
}
int getopt(int argc, char *argv[], char *optstring) int getopt(int argc, char *argv[], char *optstring)
{ {
static char *next = nullptr;
if (optind == 0) if (optind == 0)
next = nullptr; next = nullptr;

View File

@@ -22,47 +22,67 @@
#include "tmxreader.h" #include "tmxreader.h"
#include "tmxlayer.h" #include "tmxlayer.h"
#include "tmxobject.h"
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include <map>
#include <string> #include <string>
#include <cstdint> #include <cstdint>
#include <algorithm> #include <algorithm>
#include <XGetopt.h> #include <XGetopt.h>
using std::cout;
using std::cerr;
using std::endl;
using std::string;
using std::vector;
using std::map;
using std::ifstream;
using std::ofstream;
using std::stoi;
using std::min;
using std::max;
using std::ios;
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 string g_strUsage = "Usage: tmx2gba [-h] [-f file] [-r offset] [-lyc name] [-p 0-15] [-m name;id] <-i inpath> <-o outpath>";
static const std::string g_strFullHelp = R"(Usage: tmx2gba [-h] [-r offset] [-lyc name] [-p 0-15] <-i inpath> <-o outpath> static const string g_strHelpShort = "Run 'tmx2gba -h' to view all available options.";
static const string g_strHelpFull = R"(
-h ---------- Display this help & command info. -h ------------ Display this help & command info.
-l <name> --- Name of layer to use (default first layer in TMX). -l <name> ----- Name of layer to use (default first layer in TMX).
-y <name> --- Layer for palette mappings. -y <name> ----- Layer for palette mappings.
-c <name> --- Output a separate 8bit collision map of the specified layer. -c <name> ----- Output a separate 8bit collision map of the specified layer.
-r <offset> - Offset tile indices (default 0). -r <offset> --- Offset tile indices (default 0).
-p <0-15> --- Select which palette to use for 4-bit tilesets. -p <0-15> ----- Select which palette to use for 4-bit tilesets.
-i <path> --- Path to input TMX file. -m <name;id> -- Map an object name to an ID, will enable object exports.
-o <path> --- Path to output files.)"; -i <path> ----- Path to input TMX file.
-o <path> ----- Path to output files.
-f <file> ----- Specify a file to use for flags, will override any options specified in the cmd line.)";
struct SParams struct SParams
{ {
std::string inPath, outPath; bool help = false;
std::string layer, collisionlay, paletteLay; string inPath, outPath;
string layer, collisionlay, paletteLay;
string flagFile;
int offset = 0; int offset = 0;
int palette = 0; int palette = 0;
vector<string> objMappings;
bool objExport = false;
}; };
bool ParseArgs ( int argc, char** argv, SParams* params ) void ParseArgs ( int argc, char** argv, SParams* params )
{ {
char cOption; char cOption;
while ( ( cOption = (char)getopt ( argc, argv, "hr:l:c:p:y:i:o:" ) ) > 0 ) getoptClear ();
while ( ( cOption = (char)getopt ( argc, argv, "hr:l:c:p:y:m:i:o:f:" ) ) > 0 )
{ {
switch ( cOption ) switch ( cOption )
{ {
case ( 'h' ): case ( 'h' ):
std::cout << g_strFullHelp << std::endl; params->help = true;
return 0; return;
case ( 'l' ): case ( 'l' ):
params->layer = optarg; params->layer = optarg;
@@ -77,11 +97,16 @@ bool ParseArgs ( int argc, char** argv, SParams* params )
break; break;
case ( 'r' ): case ( 'r' ):
params->offset = std::stoi ( optarg ); params->offset = stoi ( optarg );
break; break;
case ( 'p' ): case ( 'p' ):
params->palette = std::stoi ( optarg ); params->palette = stoi ( optarg );
break;
case ( 'm' ):
params->objExport = true;
params->objMappings.push_back ( optarg );
break; break;
case ( 'i' ): case ( 'i' ):
@@ -92,28 +117,35 @@ bool ParseArgs ( int argc, char** argv, SParams* params )
params->outPath = optarg; params->outPath = optarg;
break; break;
case ( 'f' ):
params->flagFile = optarg;
break;
default: default:
break; break;
} }
} }
}
bool CheckArgs ( const SParams* params )
{
// Check my paranoia. // Check my paranoia.
if ( params->inPath.empty () ) if ( params->inPath.empty () )
{ {
std::cerr << "No input file specified." << std::endl; cerr << "No input file specified." << endl;
std::cout << g_strUsage << std::endl; cout << g_strUsage << endl << g_strHelpShort << endl;
return false; return false;
} }
if ( params->outPath.empty () ) if ( params->outPath.empty () )
{ {
std::cerr << "No output file specified." << std::endl; cerr << "No output file specified." << endl;
std::cout << g_strUsage << std::endl; cout << g_strUsage << endl << g_strHelpShort << endl;
return false; return false;
} }
if ( params->palette < 0 || params->palette > 15 ) if ( params->palette < 0 || params->palette > 15 )
{ {
std::cerr << "Invalid palette index." << std::endl; cerr << "Invalid palette index." << endl;
std::cout << g_strUsage << std::endl; cout << g_strUsage << endl << g_strHelpShort << endl;
return false; return false;
} }
@@ -122,12 +154,12 @@ bool ParseArgs ( int argc, char** argv, SParams* params )
template <typename T> template <typename T>
void WriteArray ( std::ofstream& a_fout, const std::vector<T>& a_dat, int a_perCol = 16 ) void WriteArray ( ofstream& a_fout, const vector<T>& a_dat, int a_perCol = 16 )
{ {
const int w = sizeof(T) * 2; const int w = sizeof(T) * 2;
int col = 0; int col = 0;
std::string datType = "ERR"; string datType = "ERR";
if ( sizeof(T) == 1 ) if ( sizeof(T) == 1 )
{ {
datType = ".byte"; datType = ".byte";
@@ -143,8 +175,8 @@ void WriteArray ( std::ofstream& a_fout, const std::vector<T>& a_dat, int a_perC
datType = ".word"; datType = ".word";
} }
a_fout.setf ( std::ios::hex, std::ios::basefield ); a_fout.setf ( ios::hex, ios::basefield );
a_fout.setf ( std::ios::showbase ); a_fout.setf ( ios::showbase );
size_t i = 0; size_t i = 0;
for ( T element : a_dat ) for ( T element : a_dat )
@@ -154,7 +186,6 @@ void WriteArray ( std::ofstream& a_fout, const std::vector<T>& a_dat, int a_perC
a_fout << "\t" << datType << " "; a_fout << "\t" << datType << " ";
} }
//a_fout << "0x" << std::hex << std::setw ( w ) << std::setfill ( '0' ) << (int)element;
a_fout << std::hex << (int)element; a_fout << std::hex << (int)element;
if ( i < a_dat.size () - 1 ) if ( i < a_dat.size () - 1 )
@@ -165,7 +196,7 @@ void WriteArray ( std::ofstream& a_fout, const std::vector<T>& a_dat, int a_perC
} }
else else
{ {
a_fout << "" << std::endl; a_fout << "" << endl;
col = 0; col = 0;
} }
} }
@@ -177,17 +208,119 @@ void WriteArray ( std::ofstream& a_fout, const std::vector<T>& a_dat, int a_perC
int main ( int argc, char** argv ) int main ( int argc, char** argv )
{ {
SParams params; SParams params;
if ( !ParseArgs ( argc, argv, &params ) ) ParseArgs ( argc, argv, &params );
if ( params.help )
{
cout << g_strUsage << endl << g_strHelpFull << endl;
return 0;
}
if ( params.flagFile.length () != 0 )
{
ifstream paramFile ( params.flagFile );
if ( !paramFile.is_open () )
{
cerr << "Failed to open param file." << endl;
return -1;
}
vector<string> fileArgTokens;
fileArgTokens.push_back ( "auu~~" );
bool carry = false;
string token;
while ( !paramFile.eof () )
{
if ( carry )
{
string tmp;
paramFile >> tmp;
token += " ";
token += tmp;
}
else
{
token.clear ();
paramFile >> token;
}
if ( token == "" )
{
continue;
}
bool qFr = token[0] == '"';
bool qBk = token[token.length () - 1] == '"';
if ( qFr && qBk )
{
fileArgTokens.push_back ( token.substr ( 1, token.length () - 2 ) );
}
else
if ( qFr )
{
fileArgTokens.push_back ( token.substr ( 1, token.length () - 1 ) );
carry = true;
}
else
if ( qBk )
{
fileArgTokens.push_back ( token.substr ( 0, token.length () - 1 ) );
carry = false;
}
else
{
fileArgTokens.push_back ( token );
}
}
vector<const char*> fileArgs;
fileArgs.reserve ( fileArgTokens.size () );
for ( auto& token : fileArgTokens )
{
fileArgs.push_back ( token.c_str () );
}
ParseArgs ( fileArgs.size (), (char**)fileArgs.data (), &params );
}
if ( !CheckArgs ( &params ) )
{ {
return -1; return -1;
} }
// Object mappings.
map<string, uint32_t> objMapping;
if ( params.objExport )
{
for ( auto token : params.objMappings )
{
int splitter = token.find_last_of ( ';' );
if ( splitter == -1 )
{
cerr << "Malformed mapping (missing a splitter)." << endl;
return -1;
}
try
{
string name = token.substr ( 0, splitter );
int id = stoi ( token.substr ( splitter + 1 ) );
objMapping[name] = id;
}
catch ( std::exception )
{
cerr << "Malformed mapping, make sure id is numeric." << endl;
}
}
}
// Open & read input file. // Open & read input file.
CTmxReader tmx; CTmxReader tmx;
std::ifstream fin ( params.inPath ); ifstream fin ( params.inPath );
if ( !fin.is_open () ) if ( !fin.is_open () )
{ {
std::cerr << "Failed to open input file." << std::endl; cerr << "Failed to open input file." << endl;
return -1; return -1;
} }
tmx.Open ( fin ); tmx.Open ( fin );
@@ -195,7 +328,7 @@ int main ( int argc, char** argv )
// Get layers. // Get layers.
if ( tmx.GetLayerCount () == 0 ) if ( tmx.GetLayerCount () == 0 )
{ {
std::cerr << "No layers found." << std::endl; cerr << "No layers found." << endl;
return -1; return -1;
} }
const CTmxLayer* pLayerGfx = params.layer.empty () ? tmx.GetLayer ( 0 ) : tmx.GetLayer ( params.layer ); const CTmxLayer* pLayerGfx = params.layer.empty () ? tmx.GetLayer ( 0 ) : tmx.GetLayer ( params.layer );
@@ -204,46 +337,46 @@ int main ( int argc, char** argv )
if ( pLayerGfx == nullptr ) if ( pLayerGfx == nullptr )
{ {
std::cerr << "Input layer not found." << std::endl; cerr << "Input layer not found." << endl;
return -1; return -1;
} }
// Open output files. // Open output files.
std::ofstream foutS ( params.outPath + ".s", std::ios::binary ); ofstream foutS ( params.outPath + ".s" );
std::ofstream foutH ( params.outPath + ".h", std::ios::binary ); ofstream foutH ( params.outPath + ".h" );
if ( !foutS.is_open () || !foutH.is_open () ) if ( !foutS.is_open () || !foutH.is_open () )
{ {
std::cerr << "Failed to create output file(s)."; cerr << "Failed to create output file(s).";
return -1; return -1;
} }
int slashPos = std::max ( (int)params.outPath.find_last_of ( '/' ), (int)params.outPath.find_last_of ( '\\' ) ); int slashPos = max ( (int)params.outPath.find_last_of ( '/' ), (int)params.outPath.find_last_of ( '\\' ) );
std::string name = params.outPath; string name = params.outPath;
if ( slashPos != -1 ) if ( slashPos != -1 )
{ {
name = name.substr ( slashPos + 1 ); name = name.substr ( slashPos + 1 );
} }
// Write header guards. // Write header guards.
std::string guard = "__TMX2GBA_" + name + "__"; string guard = "__TMX2GBA_" + name + "__";
for ( auto& c: guard ) c = (char)toupper ( (int)c ); for ( auto& c: guard ) c = (char)toupper ( (int)c );
foutH << "#ifndef " << guard << std::endl; foutH << "#ifndef " << guard << endl;
foutH << "#define " << guard << std::endl; foutH << "#define " << guard << endl;
foutH << std::endl; foutH << endl;
foutH << "#define " << name << "Width " << tmx.GetWidth () << std::endl; foutH << "#define " << name << "Width " << tmx.GetWidth () << endl;
foutH << "#define " << name << "Height " << tmx.GetHeight () << std::endl; foutH << "#define " << name << "Height " << tmx.GetHeight () << endl;
foutH << std::endl; foutH << endl;
// Convert to GBA-friendly charmap data. // Convert to GBA-friendly charmap data.
const uint32_t* pRead = pLayerGfx->GetData (); const uint32_t* pRead = pLayerGfx->GetData ();
const uint32_t* pPalRead = pLayerPal == nullptr ? nullptr : pLayerPal->GetData (); const uint32_t* pPalRead = pLayerPal == nullptr ? nullptr : pLayerPal->GetData ();
std::vector<uint16_t> vucCharDat; vector<uint16_t> vucCharDat;
vucCharDat.reserve ( pLayerGfx->GetWidth () * pLayerGfx->GetHeight () ); vucCharDat.reserve ( pLayerGfx->GetWidth () * pLayerGfx->GetHeight () );
for ( size_t i = 0; i < size_t(pLayerGfx->GetWidth () * pLayerGfx->GetHeight ()); ++i ) for ( size_t i = 0; i < size_t(pLayerGfx->GetWidth () * pLayerGfx->GetHeight ()); ++i )
{ {
uint32_t uiRead = (*pRead++); uint32_t uiRead = (*pRead++);
uint16_t usTile = (uint16_t)std::max<int32_t> ( 0, tmx.LidFromGid ( uiRead & ~FLIP_MASK ) + params.offset ); uint16_t usTile = (uint16_t)max<int32_t> ( 0, tmx.LidFromGid ( uiRead & ~FLIP_MASK ) + params.offset );
uint8_t ucFlags = 0x0; uint8_t ucFlags = 0x0;
// Get flipped! // Get flipped!
@@ -266,36 +399,25 @@ int main ( int argc, char** argv )
} }
// Save out charmap. // Save out charmap.
foutH << "#define " << name << "TilesLen " << vucCharDat.size () * 2 << std::endl; foutH << "#define " << name << "TilesLen " << vucCharDat.size () * 2 << endl;
foutH << "extern const unsigned short " << name << "Tiles[" << vucCharDat.size () << "];" << std::endl; foutH << "extern const unsigned short " << name << "Tiles[" << vucCharDat.size () << "];" << endl;
foutH << std::endl; foutH << endl;
foutS << "\t.section .rodata" << std::endl; foutS << "\t.section .rodata" << endl;
foutS << "\t.align 2" << std::endl; foutS << "\t.align 2" << endl;
foutS << "\t.global " << name << "Tiles" << std::endl; foutS << "\t.global " << name << "Tiles" << endl;
foutS << "\t.hidden " << name << "Tiles" << std::endl; foutS << "\t.hidden " << name << "Tiles" << endl;
foutS << name << "Tiles" << ":" << std::endl; foutS << name << "Tiles" << ":" << endl;
WriteArray<uint16_t> ( foutS, vucCharDat ); WriteArray<uint16_t> ( foutS, vucCharDat );
foutS << std::endl; foutS << endl;
/*
std::ofstream fout ( params.outPath, std::ios::binary );
if ( !fout.is_open () )
{
std::cerr << "Failed to create output file.";
return -1;
}
fout.write ( (const char*)vucCharDat.data (), vucCharDat.size () * sizeof(uint16_t) );
fout.close ();
*/
// Convert collision map & save it out. // Convert collision map & save it out.
if ( pLayerCls != nullptr ) if ( pLayerCls != nullptr )
{ {
std::vector<uint8_t> vucCollisionDat; vector<uint8_t> vucCollisionDat;
vucCollisionDat.reserve ( pLayerCls->GetWidth () * pLayerCls->GetHeight () ); vucCollisionDat.reserve ( pLayerCls->GetWidth () * pLayerCls->GetHeight () );
const uint32_t* pRead = pLayerCls->GetData (); pRead = pLayerCls->GetData ();
for ( int i = 0; i < pLayerCls->GetWidth () * pLayerCls->GetHeight (); ++i ) for ( int i = 0; i < pLayerCls->GetWidth () * pLayerCls->GetHeight (); ++i )
{ {
uint8_t ucTile = (uint8_t)tmx.LidFromGid ( (*pRead++) & ~FLIP_MASK ); uint8_t ucTile = (uint8_t)tmx.LidFromGid ( (*pRead++) & ~FLIP_MASK );
@@ -303,9 +425,9 @@ int main ( int argc, char** argv )
} }
// Try to nicely append "_collision" to the output name. // Try to nicely append "_collision" to the output name.
std::string strPath; string strPath;
size_t extPos = params.outPath.find_last_of ( '.' ); size_t extPos = params.outPath.find_last_of ( '.' );
if ( extPos != std::string::npos ) if ( extPos != string::npos )
{ {
strPath = params.outPath.insert ( extPos, "_collision" ); strPath = params.outPath.insert ( extPos, "_collision" );
} }
@@ -315,30 +437,56 @@ int main ( int argc, char** argv )
} }
// Save it out. // Save it out.
foutH << "#define " << name << "CollisionLen " << vucCollisionDat.size () << std::endl; foutH << "#define " << name << "CollisionLen " << vucCollisionDat.size () << endl;
foutH << "extern const unsigned char " << name << "Collision[" << vucCollisionDat.size () << "];" << std::endl; foutH << "extern const unsigned char " << name << "Collision[" << vucCollisionDat.size () << "];" << endl;
foutH << std::endl; foutH << endl;
foutS << std::endl; foutS << endl;
foutS << "\t.section .rodata" << std::endl; foutS << "\t.section .rodata" << endl;
foutS << "\t.align 2" << std::endl; foutS << "\t.align 2" << endl;
foutS << "\t.global " << name << "Collision" << std::endl; foutS << "\t.global " << name << "Collision" << endl;
foutS << "\t.hidden " << name << "Collision" << std::endl; foutS << "\t.hidden " << name << "Collision" << endl;
foutS << name << "Collision" << ":" << std::endl; foutS << name << "Collision" << ":" << endl;
WriteArray<uint8_t> ( foutS, vucCollisionDat ); WriteArray<uint8_t> ( foutS, vucCollisionDat );
foutS << std::endl; foutS << endl;
}
/* if ( params.objExport )
fout.open ( strPath, std::ios::binary );
if ( fout.is_open () )
{ {
fout.write ( (const char*)vucCollisionDat.data (), vucCollisionDat.size () * sizeof(uint8_t) ); vector<uint32_t> objDat;
fout.close (); for ( int i = 0; i < tmx.GetObjectCount (); ++i )
} {
*/ auto obj = tmx.GetObject ( i );
auto it = objMapping.find ( obj->GetName () );
if ( it == objMapping.end () )
{
continue;
} }
foutH << "#endif//" << guard << std::endl; float x, y;
obj->GetPos ( &x, &y );
objDat.push_back ( it->second );
objDat.push_back ( (int)( x * 256.0f ) );
objDat.push_back ( (int)( y * 256.0f ) );
}
// Save it out.
foutH << "#define " << name << "ObjCount " << objDat.size () / 3 << endl;
foutH << "#define " << name << "ObjdatLen " << objDat.size () * sizeof(int) << endl;
foutH << "extern const unsigned int " << name << "Objdat[" << objDat.size () << "];" << endl;
foutH << endl;
foutS << endl;
foutS << "\t.section .rodata" << endl;
foutS << "\t.align 2" << endl;
foutS << "\t.global " << name << "Objdat" << endl;
foutS << "\t.hidden " << name << "Objdat" << endl;
foutS << name << "Objdat" << ":" << endl;
WriteArray<uint32_t> ( foutS, objDat );
foutS << endl;
}
foutH << "#endif//" << guard << endl;
foutH.close (); foutH.close ();
foutS.close (); foutS.close ();

61
src/tmxobject.cpp Normal file
View File

@@ -0,0 +1,61 @@
/* tmxobject.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 "tmxobject.h"
CTmxObject::CTmxObject () :
m_name ( "" ),
m_x ( 0.0f ), m_y ( 0.0f )
{
}
CTmxObject::CTmxObject ( const std::string& a_name, float a_x, float a_y ) :
m_name ( a_name ),
m_x ( a_x ), m_y ( a_y )
{
}
CTmxObject::~CTmxObject ()
{
}
const std::string& CTmxObject::GetName () const
{
return m_name;
}
void CTmxObject::GetPos ( float* a_outX, float* a_outY ) const
{
if ( a_outX != nullptr )
{
*a_outX = m_x;
}
if ( a_outY != nullptr )
{
*a_outY = m_y;
}
}

21
src/tmxobject.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef __TMXOBJECT_H__
#define __TMXOBJECT_H__
#include <string>
class CTmxObject
{
public:
CTmxObject ();
CTmxObject ( const std::string& a_name, float a_x, float a_y );
~CTmxObject ();
const std::string& GetName () const;
void GetPos ( float* a_outX, float* a_outY ) const;
private:
std::string m_name;
float m_x, m_y;
};
#endif//__TMXOBJECT_H__

View File

@@ -22,6 +22,7 @@
#include "tmxreader.h" #include "tmxreader.h"
#include "tmxtileset.h" #include "tmxtileset.h"
#include "tmxobject.h"
#include "tmxlayer.h" #include "tmxlayer.h"
#include <cstdint> #include <cstdint>
#include <sstream> #include <sstream>
@@ -39,18 +40,18 @@ CTmxReader::CTmxReader ()
CTmxReader::~CTmxReader () CTmxReader::~CTmxReader ()
{ {
// Delete old tilesets. // Delete old tilesets.
for ( auto pTileset : m_vpTileset ) for ( auto pTileset : m_tileset )
{ {
delete pTileset; delete pTileset;
} }
m_vpTileset.clear (); m_tileset.clear ();
// Delete old layers. // Delete old layers.
for ( auto pLay : m_vpLayers ) for ( auto pLay : m_layers )
{ {
delete pLay; delete pLay;
} }
m_vpLayers.clear (); m_layers.clear ();
} }
@@ -104,7 +105,7 @@ void CTmxReader::ReadTileset ( rapidxml::xml_node<>* a_xNode )
uiFirstGid = std::stoul ( xAttrib->value () ); uiFirstGid = std::stoul ( xAttrib->value () );
} }
m_vpTileset.push_back ( new CTmxTileset ( szName, szSource, uiFirstGid ) ); m_tileset.push_back ( new CTmxTileset ( szName, szSource, uiFirstGid ) );
} }
void CTmxReader::ReadLayer ( rapidxml::xml_node<>* a_xNode ) void CTmxReader::ReadLayer ( rapidxml::xml_node<>* a_xNode )
@@ -149,26 +150,65 @@ void CTmxReader::ReadLayer ( rapidxml::xml_node<>* a_xNode )
} }
} }
m_vpLayers.push_back ( new CTmxLayer ( iWidth, iHeight, szName, pTileDat ) ); m_layers.push_back ( new CTmxLayer ( iWidth, iHeight, szName, pTileDat ) );
}
void CTmxReader::ReadObjects ( rapidxml::xml_node<>* a_xNode )
{
for ( auto xNode = a_xNode->first_node (); xNode != nullptr; xNode = xNode->next_sibling () )
{
if ( strcmp ( xNode->name (), "object" ) != 0 )
{
continue;
}
rapidxml::xml_attribute<>* xAttrib;
const char* name = "";
float x = 0.0f;
float y = 0.0f;
// Read name.
xAttrib = xNode->first_attribute ( "name" );
if ( xAttrib != nullptr )
{
name = xAttrib->value ();
}
// Read X pos.
xAttrib = xNode->first_attribute ( "x" );
if ( xAttrib != nullptr )
{
x = std::stof ( xAttrib->value () );
}
// Read Y pos.
xAttrib = xNode->first_attribute ( "y" );
if ( xAttrib != nullptr )
{
y = std::stof ( xAttrib->value () );
}
m_objects.push_back ( new CTmxObject ( name, x, y ) );
}
} }
void CTmxReader::Open ( std::istream& a_in ) void CTmxReader::Open ( std::istream& a_in )
{ {
// Delete old tilesets. // Delete old tilesets.
for ( auto pTileset : m_vpTileset ) for ( auto pTileset : m_tileset )
{ {
delete pTileset; delete pTileset;
} }
m_vpTileset.clear (); m_tileset.clear ();
// Delete old layers. // Delete old layers.
for ( auto pLay : m_vpLayers ) for ( auto pLay : m_layers )
{ {
delete pLay; delete pLay;
} }
m_vpLayers.clear (); m_layers.clear ();
m_vuiGidTable.clear (); m_gidTable.clear ();
// Read string into a buffer. // Read string into a buffer.
std::stringstream buf; std::stringstream buf;
@@ -191,11 +231,11 @@ void CTmxReader::Open ( std::istream& a_in )
rapidxml::xml_attribute<>* xAttrib = nullptr; rapidxml::xml_attribute<>* xAttrib = nullptr;
if ( ( xAttrib = xMap->first_attribute ( "width" ) ) != nullptr ) if ( ( xAttrib = xMap->first_attribute ( "width" ) ) != nullptr )
{ {
m_iWidth = std::stoi ( xAttrib->value () ); m_width = std::stoi ( xAttrib->value () );
} }
if ( ( xAttrib = xMap->first_attribute ( "height" ) ) != nullptr ) if ( ( xAttrib = xMap->first_attribute ( "height" ) ) != nullptr )
{ {
m_iHeight = std::stoi ( xAttrib->value () ); m_height = std::stoi ( xAttrib->value () );
} }
// Read nodes. // Read nodes.
@@ -211,36 +251,41 @@ void CTmxReader::Open ( std::istream& a_in )
{ {
ReadTileset ( xNode ); ReadTileset ( xNode );
} }
else
if ( strcmp ( xNode->name (), "objectgroup" ) == 0 )
{
ReadObjects ( xNode );
}
} }
// Generate global id table. // Generate global id table.
for ( auto pTileset : m_vpTileset ) for ( auto pTileset : m_tileset )
{ {
m_vuiGidTable.push_back ( pTileset->GetFirstGid () ); m_gidTable.push_back ( pTileset->GetFirstGid () );
} }
std::sort ( m_vuiGidTable.rbegin (), m_vuiGidTable.rend () ); std::sort ( m_gidTable.rbegin (), m_gidTable.rend () );
} }
int CTmxReader::GetWidth () const int CTmxReader::GetWidth () const
{ {
return m_iWidth; return m_width;
} }
int CTmxReader::GetHeight () const int CTmxReader::GetHeight () const
{ {
return m_iHeight; return m_height;
} }
const CTmxLayer* CTmxReader::GetLayer ( int a_iId ) const const CTmxLayer* CTmxReader::GetLayer ( int a_id ) const
{ {
return m_vpLayers[a_iId]; return m_layers[a_id];
} }
const CTmxLayer* CTmxReader::GetLayer ( std::string a_strName ) const const CTmxLayer* CTmxReader::GetLayer ( std::string a_strName ) const
{ {
for ( auto pLay : m_vpLayers ) for ( auto pLay : m_layers )
{ {
if ( pLay->GetName ().compare ( a_strName ) == 0 ) if ( pLay->GetName ().compare ( a_strName ) == 0 )
{ {
@@ -253,13 +298,24 @@ const CTmxLayer* CTmxReader::GetLayer ( std::string a_strName ) const
int CTmxReader::GetLayerCount () const int CTmxReader::GetLayerCount () const
{ {
return m_vpLayers.size (); return m_layers.size ();
}
const CTmxObject* CTmxReader::GetObject ( int a_id ) const
{
return m_objects[a_id];
}
int CTmxReader::GetObjectCount () const
{
return m_objects.size ();
} }
uint32_t CTmxReader::LidFromGid ( uint32_t a_uiGid ) uint32_t CTmxReader::LidFromGid ( uint32_t a_uiGid )
{ {
for ( uint32_t uiFirst : m_vuiGidTable ) for ( uint32_t uiFirst : m_gidTable )
{ {
if ( uiFirst <= a_uiGid ) if ( uiFirst <= a_uiGid )
{ {

View File

@@ -8,6 +8,7 @@
class CTmxTileset; class CTmxTileset;
class CTmxLayer; class CTmxLayer;
class CTmxObject;
namespace rapidxml { template<class Ch = char> class xml_node; } namespace rapidxml { template<class Ch = char> class xml_node; }
class CTmxReader class CTmxReader
@@ -21,21 +22,26 @@ public:
int GetWidth () const; int GetWidth () const;
int GetHeight () const; int GetHeight () const;
const CTmxLayer* GetLayer ( int a_iId ) const; const CTmxLayer* GetLayer ( int a_id ) const;
const CTmxLayer* GetLayer ( std::string a_strName ) const; const CTmxLayer* GetLayer ( std::string a_strName ) const;
int GetLayerCount () const; int GetLayerCount () const;
uint32_t LidFromGid ( uint32_t a_uiGid ); const CTmxObject* GetObject ( int a_id ) const;
int GetObjectCount () const;
uint32_t LidFromGid ( uint32_t a_gid );
private: private:
bool DecodeMap ( uint32_t* a_pOut, size_t a_outSize, const std::string& a_strIn ); bool DecodeMap ( uint32_t* a_out, size_t a_outSize, const std::string& a_strIn );
void ReadTileset ( rapidxml::xml_node<>* a_xNode ); void ReadTileset ( rapidxml::xml_node<>* a_xNode );
void ReadLayer ( rapidxml::xml_node<>* a_xNode ); void ReadLayer ( rapidxml::xml_node<>* a_xNode );
void ReadObjects ( rapidxml::xml_node<>* a_xNode );
int m_iWidth, m_iHeight; int m_width, m_height;
std::vector<CTmxTileset*> m_vpTileset; std::vector<CTmxTileset*> m_tileset;
std::vector<CTmxLayer*> m_vpLayers; std::vector<CTmxLayer*> m_layers;
std::vector<uint32_t> m_vuiGidTable; std::vector<CTmxObject*> m_objects;
std::vector<uint32_t> m_gidTable;
}; };

View File

@@ -69,6 +69,7 @@
<ClCompile Include="src\base64.cpp" /> <ClCompile Include="src\base64.cpp" />
<ClCompile Include="src\tmx2gba.cpp" /> <ClCompile Include="src\tmx2gba.cpp" />
<ClCompile Include="src\tmxlayer.cpp" /> <ClCompile Include="src\tmxlayer.cpp" />
<ClCompile Include="src\tmxobject.cpp" />
<ClCompile Include="src\tmxreader.cpp" /> <ClCompile Include="src\tmxreader.cpp" />
<ClCompile Include="src\XGetopt.cpp" /> <ClCompile Include="src\XGetopt.cpp" />
<ClCompile Include="src\tmxtileset.cpp" /> <ClCompile Include="src\tmxtileset.cpp" />
@@ -82,6 +83,7 @@
<ClInclude Include="inc\rapidxml\rapidxml_utils.hpp" /> <ClInclude Include="inc\rapidxml\rapidxml_utils.hpp" />
<ClInclude Include="inc\XGetopt.h" /> <ClInclude Include="inc\XGetopt.h" />
<ClInclude Include="src\tmxlayer.h" /> <ClInclude Include="src\tmxlayer.h" />
<ClInclude Include="src\tmxobject.h" />
<ClInclude Include="src\tmxreader.h" /> <ClInclude Include="src\tmxreader.h" />
<ClInclude Include="src\tmxtileset.h" /> <ClInclude Include="src\tmxtileset.h" />
</ItemGroup> </ItemGroup>

View File

@@ -33,6 +33,9 @@
<ClCompile Include="src\tmxtileset.cpp"> <ClCompile Include="src\tmxtileset.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\tmxobject.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="inc\base64.h"> <ClInclude Include="inc\base64.h">
@@ -65,5 +68,8 @@
<ClInclude Include="src\tmxtileset.h"> <ClInclude Include="src\tmxtileset.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\tmxobject.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>