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

19 Commits

Author SHA1 Message Date
5937455000 Linux build fixes 2025-01-23 19:00:16 +11:00
224e1e53e9 fix empty objects list triggering an assertion failure 2024-04-11 16:31:17 +10:00
b8d7d43899 argparse: fix unknown flags not being reported 2024-04-11 16:21:33 +10:00
056612667b update readme 2024-04-11 15:34:53 +10:00
e6053f9472 restore object reading 2024-04-11 10:36:16 +10:00
6b786d36fb try to add pdbs to windows artifacts 2024-04-11 07:41:58 +10:00
708fd13d08 use modern pugixml target 2024-04-11 07:27:43 +10:00
6a6d589817 refactor tmxmap 2024-04-11 07:16:13 +10:00
fcb9eceec3 collect string handling utility functions into strtools 2024-04-11 06:37:09 +10:00
2638bf2667 merge help and version commands 2024-04-11 04:37:49 +10:00
b29c61774c normalise license snippets/copyright & cmake stuff 2024-04-11 04:25:28 +10:00
835b80256f implement remaining encodings 2024-04-10 20:31:55 +10:00
677d59f096 fix tilesets & implement xml tile reader 2024-04-10 19:37:32 +10:00
b6308816ae msvc fixes 2024-04-10 12:46:34 +10:00
0dd9074e27 restore full compression support 2024-04-10 10:21:37 +10:00
5daf57ffe1 remove masm hex generator 2024-04-10 06:47:12 +10:00
6c52897942 fix include 2024-04-10 06:45:45 +10:00
e6bb098e15 replace rapidxml uses with pugixml 2024-04-10 06:42:58 +10:00
c2e9f5c974 break map reader into its own class 2024-04-10 02:49:52 +10:00
32 changed files with 553 additions and 3780 deletions

View File

@@ -54,4 +54,4 @@ jobs:
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: ${{env.ARTIFACT_NAME}}-${{matrix.config.artifact}} name: ${{env.ARTIFACT_NAME}}-${{matrix.config.artifact}}
path: build/src/${{env.ARTIFACT_NAME}}${{startsWith(matrix.config.os, 'windows') && '.exe' || ''}} path: build/src/${{env.ARTIFACT_NAME}}${{startsWith(matrix.config.os, 'windows') && '.[ep][xd][eb]' || ''}}

View File

@@ -8,7 +8,6 @@ project(tmx2gba
option(USE_ZLIB "Use zlib instead of bundled miniz" "${UNIX}") option(USE_ZLIB "Use zlib instead of bundled miniz" "${UNIX}")
option(USE_BUNDLED_PUGIXML "Use bundled PUGIXML" ON) option(USE_BUNDLED_PUGIXML "Use bundled PUGIXML" ON)
option(USE_BUNDLED_ZSTD "Use bundled libzstd" ON) option(USE_BUNDLED_ZSTD "Use bundled libzstd" ON)
option(USE_BUNDLED_TMXLITE "Use bundled tmxlite" ON)
option(TMX2GBA_DKP_INSTALL "Install into DEVKITPRO prefix" OFF) option(TMX2GBA_DKP_INSTALL "Install into DEVKITPRO prefix" OFF)
@@ -41,7 +40,6 @@ else()
endif() endif()
add_subdirectory(ext/base64) add_subdirectory(ext/base64)
add_subdirectory(ext/rapidxml)
# Main tmx2gba sources # Main tmx2gba sources
add_subdirectory(src) add_subdirectory(src)

View File

@@ -10,13 +10,12 @@ tmx2gba is a simple command line utility that converts [Tiled](http://www.mapedi
## Usage ## ## Usage ##
``` ```
tmx2gba [-hv] [-r offset] [-lyc name] [-p 0-15] [-m name;id] <-i inpath> <-o outpath> tmx2gba [-h] [-r offset] [-lyc name] [-p 0-15] [-m name;id] <-i inpath> <-o outpath>
``` ```
| Command | Required | Notes | | Command | Required | Notes |
|--------------|----------|------------------------------------------------------------------------------------| |--------------|----------|------------------------------------------------------------------------------------|
| -h | N/A | Display help & command info | | -h | N/A | Display program help & command info then quit |
| -v | No | Display version & quit |
| -l (name) | No | Name of layer to use (default first layer in TMX) | | -l (name) | No | Name of layer to use (default first layer in TMX) |
| -y (name) | No | Layer for palette mappings | | -y (name) | No | Layer for palette mappings |
| -c (name) | No | Output a separate 8bit collision map of the specified layer | | -c (name) | No | Output a separate 8bit collision map of the specified layer |
@@ -60,7 +59,6 @@ sudo cmake --install build
## License ## ## License ##
[tmx2gba](https://github.com/ScrelliCopter/tmx2gba) is licensed under the [Zlib license](COPYING.txt). [tmx2gba](https://github.com/ScrelliCopter/tmx2gba) is licensed under the [Zlib license](COPYING.txt).
- A modified [tmxlite](https://github.com/fallahn/tmxlite) is licensed under the [Zlib license](ext/tmxlite/LICENSE).
- [pugixml](https://pugixml.org/) is licensed under the [MIT license](ext/pugixml/LICENSE.md). - [pugixml](https://pugixml.org/) is licensed under the [MIT license](ext/pugixml/LICENSE.md).
- [René Nyffenegger's base64.cpp](https://github.com/ReneNyffenegger/cpp-base64) is licensed under the [Zlib license](ext/base64/LICENSE). - [René Nyffenegger's base64.cpp](https://github.com/ReneNyffenegger/cpp-base64) is licensed under the [Zlib license](ext/base64/LICENSE).
- [miniz](https://github.com/richgel999/miniz) is licensed under the [MIT license](ext/miniz/LICENSE). - [miniz](https://github.com/richgel999/miniz) is licensed under the [MIT license](ext/miniz/LICENSE).

View File

@@ -1,6 +1,7 @@
add_library(base64 add_library(base64
base64.cpp base64.h) base64.cpp base64.h)
add_library(base64::base64 ALIAS base64) add_library(base64::base64 ALIAS base64)
set_target_properties(base64 PROPERTIES CXX_STANDARD 17) set_target_properties(base64 PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON)
target_compile_options(base64 PUBLIC $<$<CXX_COMPILER_ID:MSVC>:/Zc:__cplusplus>)
target_include_directories(base64 target_include_directories(base64
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -22,6 +22,7 @@ add_library(pugixml STATIC
src/pugixml.hpp src/pugixml.hpp
src/pugixml.cpp) src/pugixml.cpp)
add_library(pugixml::static ALIAS pugixml) add_library(pugixml::static ALIAS pugixml)
add_library(pugixml::pugixml ALIAS pugixml)
set_target_properties(pugixml PROPERTIES set_target_properties(pugixml PROPERTIES
CXX_STANDARD_REQUIRED ON CXX_STANDARD_REQUIRED ON

View File

@@ -1,4 +0,0 @@
add_library(rapidxml INTERFACE)
add_library(External::rapidxml ALIAS rapidxml)
target_include_directories(rapidxml
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -1,52 +0,0 @@
Use of this software is granted under one of the following two licenses,
to be chosen freely by the user.
1. Boost Software License - Version 1.0 - August 17th, 2003
===============================================================================
Copyright (c) 2006, 2007 Marcin Kalicinski
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
2. The MIT License
===============================================================================
Copyright (c) 2006, 2007 Marcin Kalicinski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@@ -1,174 +0,0 @@
#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
#define RAPIDXML_ITERATORS_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_iterators.hpp This file contains rapidxml iterators
#include "rapidxml.hpp"
namespace rapidxml
{
//! Iterator of child nodes of xml_node
template<class Ch>
class node_iterator
{
public:
typedef typename xml_node<Ch> value_type;
typedef typename xml_node<Ch> &reference;
typedef typename xml_node<Ch> *pointer;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
node_iterator()
: m_node(0)
{
}
node_iterator(xml_node<Ch> *node)
: m_node(node->first_node())
{
}
reference operator *() const
{
assert(m_node);
return *m_node;
}
pointer operator->() const
{
assert(m_node);
return m_node;
}
node_iterator& operator++()
{
assert(m_node);
m_node = m_node->next_sibling();
return *this;
}
node_iterator operator++(int)
{
node_iterator tmp = *this;
++this;
return tmp;
}
node_iterator& operator--()
{
assert(m_node && m_node->previous_sibling());
m_node = m_node->previous_sibling();
return *this;
}
node_iterator operator--(int)
{
node_iterator tmp = *this;
++this;
return tmp;
}
bool operator ==(const node_iterator<Ch> &rhs)
{
return m_node == rhs.m_node;
}
bool operator !=(const node_iterator<Ch> &rhs)
{
return m_node != rhs.m_node;
}
private:
xml_node<Ch> *m_node;
};
//! Iterator of child attributes of xml_node
template<class Ch>
class attribute_iterator
{
public:
typedef typename xml_attribute<Ch> value_type;
typedef typename xml_attribute<Ch> &reference;
typedef typename xml_attribute<Ch> *pointer;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
attribute_iterator()
: m_attribute(0)
{
}
attribute_iterator(xml_node<Ch> *node)
: m_attribute(node->first_attribute())
{
}
reference operator *() const
{
assert(m_attribute);
return *m_attribute;
}
pointer operator->() const
{
assert(m_attribute);
return m_attribute;
}
attribute_iterator& operator++()
{
assert(m_attribute);
m_attribute = m_attribute->next_attribute();
return *this;
}
attribute_iterator operator++(int)
{
attribute_iterator tmp = *this;
++this;
return tmp;
}
attribute_iterator& operator--()
{
assert(m_attribute && m_attribute->previous_attribute());
m_attribute = m_attribute->previous_attribute();
return *this;
}
attribute_iterator operator--(int)
{
attribute_iterator tmp = *this;
++this;
return tmp;
}
bool operator ==(const attribute_iterator<Ch> &rhs)
{
return m_attribute == rhs.m_attribute;
}
bool operator !=(const attribute_iterator<Ch> &rhs)
{
return m_attribute != rhs.m_attribute;
}
private:
xml_attribute<Ch> *m_attribute;
};
}
#endif

View File

@@ -1,421 +0,0 @@
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
#define RAPIDXML_PRINT_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
#include "rapidxml.hpp"
// Only include streams if not disabled
#ifndef RAPIDXML_NO_STREAMS
#include <ostream>
#include <iterator>
#endif
namespace rapidxml
{
///////////////////////////////////////////////////////////////////////
// Printing flags
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
///////////////////////////////////////////////////////////////////////
// Internal
//! \cond internal
namespace internal
{
///////////////////////////////////////////////////////////////////////////
// Internal character operations
// Copy characters from given range to given output iterator
template<class OutIt, class Ch>
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
{
while (begin != end)
*out++ = *begin++;
return out;
}
// Copy characters from given range to given output iterator and expand
// characters into references (&lt; &gt; &apos; &quot; &amp;)
template<class OutIt, class Ch>
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
{
while (begin != end)
{
if (*begin == noexpand)
{
*out++ = *begin; // No expansion, copy character
}
else
{
switch (*begin)
{
case Ch('<'):
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('>'):
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('\''):
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
break;
case Ch('"'):
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('&'):
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
break;
default:
*out++ = *begin; // No expansion, copy character
}
}
++begin; // Step to next character
}
return out;
}
// Fill given output iterator with repetitions of the same character
template<class OutIt, class Ch>
inline OutIt fill_chars(OutIt out, int n, Ch ch)
{
for (int i = 0; i < n; ++i)
*out++ = ch;
return out;
}
// Find character
template<class Ch, Ch ch>
inline bool find_char(const Ch *begin, const Ch *end)
{
while (begin != end)
if (*begin++ == ch)
return true;
return false;
}
///////////////////////////////////////////////////////////////////////////
// Internal printing operations
// Print node
template<class OutIt, class Ch>
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
// Print proper node type
switch (node->type())
{
// Document
case node_document:
out = print_children(out, node, flags, indent);
break;
// Element
case node_element:
out = print_element_node(out, node, flags, indent);
break;
// Data
case node_data:
out = print_data_node(out, node, flags, indent);
break;
// CDATA
case node_cdata:
out = print_cdata_node(out, node, flags, indent);
break;
// Declaration
case node_declaration:
out = print_declaration_node(out, node, flags, indent);
break;
// Comment
case node_comment:
out = print_comment_node(out, node, flags, indent);
break;
// Doctype
case node_doctype:
out = print_doctype_node(out, node, flags, indent);
break;
// Pi
case node_pi:
out = print_pi_node(out, node, flags, indent);
break;
// Unknown
default:
assert(0);
break;
}
// If indenting not disabled, add line break after node
if (!(flags & print_no_indenting))
*out = Ch('\n'), ++out;
// Return modified iterator
return out;
}
// Print children of the node
template<class OutIt, class Ch>
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
out = print_node(out, child, flags, indent);
return out;
}
// Print attributes of the node
template<class OutIt, class Ch>
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
{
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
{
if (attribute->name() && attribute->value())
{
// Print attribute name
*out = Ch(' '), ++out;
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
*out = Ch('='), ++out;
// Print attribute value using appropriate quote type
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
{
*out = Ch('\''), ++out;
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
*out = Ch('\''), ++out;
}
else
{
*out = Ch('"'), ++out;
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
*out = Ch('"'), ++out;
}
}
}
return out;
}
// Print data node
template<class OutIt, class Ch>
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_data);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
return out;
}
// Print data node
template<class OutIt, class Ch>
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_cdata);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'); ++out;
*out = Ch('!'); ++out;
*out = Ch('['); ++out;
*out = Ch('C'); ++out;
*out = Ch('D'); ++out;
*out = Ch('A'); ++out;
*out = Ch('T'); ++out;
*out = Ch('A'); ++out;
*out = Ch('['); ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch(']'); ++out;
*out = Ch(']'); ++out;
*out = Ch('>'); ++out;
return out;
}
// Print element node
template<class OutIt, class Ch>
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_element);
// Print element name and attributes, if any
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
out = print_attributes(out, node, flags);
// If node is childless
if (node->value_size() == 0 && !node->first_node())
{
// Print childless node tag ending
*out = Ch('/'), ++out;
*out = Ch('>'), ++out;
}
else
{
// Print normal node tag ending
*out = Ch('>'), ++out;
// Test if node contains a single data node only (and no other nodes)
xml_node<Ch> *child = node->first_node();
if (!child)
{
// If node has no children, only print its value without indenting
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
}
else if (child->next_sibling() == 0 && child->type() == node_data)
{
// If node has a sole data child, only print its value without indenting
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
}
else
{
// Print all children with full indenting
if (!(flags & print_no_indenting))
*out = Ch('\n'), ++out;
out = print_children(out, node, flags, indent + 1);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
}
// Print node end
*out = Ch('<'), ++out;
*out = Ch('/'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
*out = Ch('>'), ++out;
}
return out;
}
// Print declaration node
template<class OutIt, class Ch>
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
// Print declaration start
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('?'), ++out;
*out = Ch('x'), ++out;
*out = Ch('m'), ++out;
*out = Ch('l'), ++out;
// Print attributes
out = print_attributes(out, node, flags);
// Print declaration end
*out = Ch('?'), ++out;
*out = Ch('>'), ++out;
return out;
}
// Print comment node
template<class OutIt, class Ch>
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_comment);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('!'), ++out;
*out = Ch('-'), ++out;
*out = Ch('-'), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('-'), ++out;
*out = Ch('-'), ++out;
*out = Ch('>'), ++out;
return out;
}
// Print doctype node
template<class OutIt, class Ch>
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_doctype);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('!'), ++out;
*out = Ch('D'), ++out;
*out = Ch('O'), ++out;
*out = Ch('C'), ++out;
*out = Ch('T'), ++out;
*out = Ch('Y'), ++out;
*out = Ch('P'), ++out;
*out = Ch('E'), ++out;
*out = Ch(' '), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('>'), ++out;
return out;
}
// Print pi node
template<class OutIt, class Ch>
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_pi);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('?'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
*out = Ch(' '), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('?'), ++out;
*out = Ch('>'), ++out;
return out;
}
}
//! \endcond
///////////////////////////////////////////////////////////////////////////
// Printing
//! Prints XML to given output iterator.
//! \param out Output iterator to print to.
//! \param node Node to be printed. Pass xml_document to print entire document.
//! \param flags Flags controlling how XML is printed.
//! \return Output iterator pointing to position immediately after last character of printed text.
template<class OutIt, class Ch>
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
{
return internal::print_node(out, &node, flags, 0);
}
#ifndef RAPIDXML_NO_STREAMS
//! Prints XML to given output stream.
//! \param out Output stream to print to.
//! \param node Node to be printed. Pass xml_document to print entire document.
//! \param flags Flags controlling how XML is printed.
//! \return Output stream.
template<class Ch>
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
{
print(std::ostream_iterator<Ch>(out), node, flags);
return out;
}
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
//! \param out Output stream to print to.
//! \param node Node to be printed.
//! \return Output stream.
template<class Ch>
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
{
return print(out, node);
}
#endif
}
#endif

View File

@@ -1,122 +0,0 @@
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
#define RAPIDXML_UTILS_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
#include "rapidxml.hpp"
#include <vector>
#include <string>
#include <fstream>
#include <stdexcept>
namespace rapidxml
{
//! Represents data loaded from a file
template<class Ch = char>
class file
{
public:
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
//! \param filename Filename to load.
file(const char *filename)
{
using namespace std;
// Open stream
basic_ifstream<Ch> stream(filename, ios::binary);
if (!stream)
throw runtime_error(string("cannot open file ") + filename);
stream.unsetf(ios::skipws);
// Determine stream size
stream.seekg(0, ios::end);
size_t size = stream.tellg();
stream.seekg(0);
// Load data and add terminating 0
m_data.resize(size + 1);
stream.read(&m_data.front(), static_cast<streamsize>(size));
m_data[size] = 0;
}
//! Loads file into the memory. Data will be automatically destroyed by the destructor
//! \param stream Stream to load from
file(std::basic_istream<Ch> &stream)
{
using namespace std;
// Load data and add terminating 0
stream.unsetf(ios::skipws);
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
if (stream.fail() || stream.bad())
throw runtime_error("error reading stream");
m_data.push_back(0);
}
//! Gets file data.
//! \return Pointer to data of file.
Ch *data()
{
return &m_data.front();
}
//! Gets file data.
//! \return Pointer to data of file.
const Ch *data() const
{
return &m_data.front();
}
//! Gets file data size.
//! \return Size of file data, in characters.
std::size_t size() const
{
return m_data.size();
}
private:
std::vector<Ch> m_data; // File data
};
//! Counts children of node. Time complexity is O(n).
//! \return Number of children of node
template<class Ch>
inline std::size_t count_children(xml_node<Ch> *node)
{
xml_node<Ch> *child = node->first_node();
std::size_t count = 0;
while (child)
{
++count;
child = child->next_sibling();
}
return count;
}
//! Counts attributes of node. Time complexity is O(n).
//! \return Number of attributes of node
template<class Ch>
inline std::size_t count_attributes(xml_node<Ch> *node)
{
xml_attribute<Ch> *attr = node->first_attribute();
std::size_t count = 0;
while (attr)
{
++count;
attr = attr->next_attribute();
}
return count;
}
}
#endif

View File

@@ -1,9 +1,11 @@
add_executable(tmx2gba add_executable(tmx2gba
strtools.hpp strtools.cpp
argparse.hpp argparse.cpp argparse.hpp argparse.cpp
$<$<NOT:$<TARGET_EXISTS:ZLIB::ZLIB>>:gzip.hpp gzip.cpp> $<$<NOT:$<TARGET_EXISTS:ZLIB::ZLIB>>:gzip.hpp gzip.cpp>
tmxlayer.hpp tmxlayer.hpp
tmxobject.hpp tmxobject.hpp
tmxtileset.hpp tmxtileset.hpp
tmxmap.hpp tmxmap.cpp
tmxreader.hpp tmxreader.cpp tmxreader.hpp tmxreader.cpp
convert.hpp convert.cpp convert.hpp convert.cpp
headerwriter.hpp headerwriter.cpp headerwriter.hpp headerwriter.cpp
@@ -14,11 +16,12 @@ configure_file(config.h.in config.h @ONLY)
target_sources(tmx2gba PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/config.h) target_sources(tmx2gba PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/config.h)
target_include_directories(tmx2gba PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(tmx2gba PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(tmx2gba PROPERTIES CXX_STANDARD 20) set_target_properties(tmx2gba PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON)
target_compile_definitions(${PROJECT_NAME} PRIVATE target_compile_definitions(${PROJECT_NAME} PRIVATE
$<$<BOOL:${MSVC}>:_CRT_SECURE_NO_WARNINGS> # disable msvc warning $<$<BOOL:${MSVC}>:_CRT_SECURE_NO_WARNINGS>) # Disable msvc warning
$<$<TARGET_EXISTS:ZLIB::ZLIB>:USE_ZLIB>)
# Enable strong warnings # Enable strong warnings
target_compile_options(tmx2gba PRIVATE target_compile_options(tmx2gba PRIVATE
@@ -26,9 +29,8 @@ target_compile_options(tmx2gba PRIVATE
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wall -Wextra -pedantic> $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wall -Wextra -pedantic>
$<$<CXX_COMPILER_ID:Clang,AppleClang>:-Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded>) $<$<CXX_COMPILER_ID:Clang,AppleClang>:-Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded>)
target_link_libraries(tmx2gba External::rapidxml) target_link_libraries(tmx2gba
#pugixml) pugixml::pugixml base64::base64 Zstd::Zstd
target_link_libraries(tmx2gba base64::base64 Zstd::Zstd
$<$<TARGET_EXISTS:ZLIB::ZLIB>:ZLIB::ZLIB> $<$<TARGET_EXISTS:ZLIB::ZLIB>:ZLIB::ZLIB>
$<$<TARGET_EXISTS:miniz::miniz>:miniz::miniz>) $<$<TARGET_EXISTS:miniz::miniz>:miniz::miniz>)

View File

@@ -1,4 +1,5 @@
/* argparse.cpp - Copyright (C) 2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2024 a dinosaur
#include "argparse.hpp" #include "argparse.hpp"
#include <optional> #include <optional>
@@ -6,6 +7,7 @@
#include <filesystem> #include <filesystem>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <algorithm>
ArgParse::ArgParser::ArgParser( ArgParse::ArgParser::ArgParser(
@@ -98,19 +100,18 @@ ArgParse::ParseCtrl ArgParse::ParserState::Next(const std::string_view token)
{ {
flagChar = flag.value(); flagChar = flag.value();
const auto opt = getOption(flagChar); const auto opt = getOption(flagChar);
if (opt.has_value()) if (!opt.has_value())
return ParseCtrl::QUIT_ERR_UNKNOWN;
bool expect = !opt.value().get().argumentName.empty();
if (token.length() <= 2)
{ {
bool expect = !opt.value().get().argumentName.empty(); expectArg = expect;
if (token.length() <= 2) if (!expectArg)
{ return handler(flagChar, "");
expectArg = expect; }
if (!expectArg) else
return handler(flagChar, ""); {
} return handler(flagChar, expect ? token.substr(2) : "");
else
{
return handler(flagChar, expect ? token.substr(2) : "");
}
} }
} }
else if (!token.empty()) else if (!token.empty())

View File

@@ -1,4 +1,5 @@
/* argparse.hpp - Copyright (C) 2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2024 a dinosaur
#ifndef ARGPARSE_HPP #ifndef ARGPARSE_HPP
#define ARGPARSE_HPP #define ARGPARSE_HPP

View File

@@ -1,6 +1,10 @@
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H
#define TMX2GBA_VERSION "@PROJECT_VERSION@" #define TMX2GBA_VERSION "@PROJECT_VERSION@"
#define TMX2GBA_DESCRIPTION "@PROJECT_DESCRIPTION@"
#define TMX2GBA_HOMEPAGE "@PROJECT_HOMEPAGE_URL@"
#cmakedefine USE_ZLIB
#endif//CONFIG_H #endif//CONFIG_H

View File

@@ -1,4 +1,5 @@
/* converter.hpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#include "convert.hpp" #include "convert.hpp"
#include "tmxreader.hpp" #include "tmxreader.hpp"
@@ -12,8 +13,7 @@ bool convert::ConvertCharmap(std::vector<uint16_t>& out, int idxOffset, uint32_t
const size_t numTiles = tmx.TileCount(); const size_t numTiles = tmx.TileCount();
assert(gfxTiles.size() == numTiles); assert(gfxTiles.size() == numTiles);
if (palTiles.has_value()) assert(!palTiles.has_value() || palTiles.value().size() == numTiles);
assert(palTiles.value().size() == numTiles);
out.reserve(numTiles); out.reserve(numTiles);
for (size_t i = 0; i < numTiles; ++i) for (size_t i = 0; i < numTiles; ++i)

View File

@@ -1,4 +1,5 @@
/* converter.hpp - Copyright (C) 2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2024 a dinosaur
#ifndef CONVERT_HPP #ifndef CONVERT_HPP
#define CONVERT_HPP #define CONVERT_HPP

View File

@@ -2,7 +2,7 @@
// SPDX-License-Identifier: Zlib // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2024 a dinosaur // SPDX-FileCopyrightText: (c) 2024 a dinosaur
#include "tmxlite/detail/gzip.hpp" #include "gzip.hpp"
#include <string_view> #include <string_view>

View File

@@ -1,4 +1,5 @@
/* headerwriter.cpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#include "headerwriter.hpp" #include "headerwriter.hpp"
#include <algorithm> #include <algorithm>

View File

@@ -1,4 +1,5 @@
/* headerwriter.hpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#ifndef HEADERWRITER_HPP #ifndef HEADERWRITER_HPP
#define HEADERWRITER_HPP #define HEADERWRITER_HPP

37
src/strtools.cpp Normal file
View File

@@ -0,0 +1,37 @@
// SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#include "strtools.hpp"
#include <cctype>
#include <algorithm>
const std::string_view TrimWhitespace(const std::string_view str)
{
auto beg = std::find_if_not(str.begin(), str.end(), ::isspace);
if (beg == std::end(str))
{
return {};
}
auto end = std::find_if_not(str.rbegin(), str.rend(), ::isspace);
auto begOff = std::distance(str.begin(), beg);
auto endOff = std::distance(end, str.rend()) - begOff;
using size_type = std::string::size_type;
return str.substr(static_cast<size_type>(begOff), static_cast<size_type>(endOff));
}
std::string SanitiseLabel(const std::string_view ident)
{
std::string out;
out.reserve(ident.length());
int last = '_';
for (int i : ident)
{
if (out.empty() && std::isdigit(i)) { continue; }
if (!std::isalnum(i)) { i = '_'; }
if (i != '_' || last != '_') { out.push_back(i); }
last = i;
}
return out;
}

113
src/strtools.hpp Normal file
View File

@@ -0,0 +1,113 @@
// SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2024 a dinosaur
#ifndef STRTOOLS_HPP
#define STRTOOLS_HPP
#include <string>
#include <string_view>
#include <cstdint>
// Cut leading & trailing whitespace (including newlines)
[[nodiscard]] const std::string_view TrimWhitespace(const std::string_view str);
// Convert string to valid C identifier
[[nodiscard]] std::string SanitiseLabel(const std::string_view ident);
#include <ostream>
// Template functions for converting unsigned ints to C/GNU style hex
static inline constexpr char CHexU(uint8_t h) { return "0123456789ABCDEF"[h >> 4]; }
static inline constexpr char CHexL(uint8_t l) { return "0123456789ABCDEF"[l & 15]; }
template <typename T> static void CHex(std::ostream& s, T x);
template <> void CHex(std::ostream& s, uint8_t x)
{
if (x > 9) s << "0x";
if (x > 15) s << CHexU(x);
s << CHexL(x);
}
template <> void CHex(std::ostream& s, uint16_t x)
{
if (x > 9) s << "0x";
if (x > 4095) s << CHexU(static_cast<uint8_t>(x >> 8));
if (x > 255) s << CHexL(static_cast<uint8_t>(x >> 8));
if (x > 15) s << CHexU(static_cast<uint8_t>(x));
s << CHexL(static_cast<uint8_t>(x));
}
template <> void CHex(std::ostream& s, uint32_t x)
{
if (x > 9) s << "0x";
if (x > 0xFFFFFFF) s << CHexU(static_cast<uint8_t>(x >> 24));
if (x > 0xFFFFFF) s << CHexL(static_cast<uint8_t>(x >> 24));
if (x > 0xFFFFF) s << CHexU(static_cast<uint8_t>(x >> 16));
if (x > 65535) s << CHexL(static_cast<uint8_t>(x >> 16));
if (x > 4095) s << CHexU(static_cast<uint8_t>(x >> 8));
if (x > 255) s << CHexL(static_cast<uint8_t>(x >> 8));
if (x > 15) s << CHexU(static_cast<uint8_t>(x));
s << CHexL(static_cast<uint8_t>(x));
}
#include <limits>
#include <cstdlib>
#include <optional>
// Templated string to int/float w/ exception-less error handling
template <typename T>
[[nodiscard]] static std::optional<T> IntFromStr(const char* str, int base = 0) noexcept
{
using std::numeric_limits;
errno = 0;
char* end = nullptr;
long res = std::strtol(str, &end, base);
if (errno == ERANGE) { return std::nullopt; }
if (str == end) { return std::nullopt; }
if constexpr (sizeof(long) > sizeof(T))
{
if (res > numeric_limits<T>::max() || res < numeric_limits<T>::min())
return std::nullopt;
}
return static_cast<T>(res);
}
template <typename T>
[[nodiscard]] static std::optional<T> UintFromStr(const char* str, int base = 0) noexcept
{
using std::numeric_limits;
char* end = nullptr;
errno = 0;
unsigned long res = std::strtoul(str, &end, base);
if (errno == ERANGE) { return std::nullopt; }
if (str == end) { return std::nullopt; }
if constexpr (numeric_limits<unsigned long>::max() > numeric_limits<T>::max())
{
if (res > numeric_limits<T>::max()) { return std::nullopt; }
}
return static_cast<T>(res);
}
template <typename T>
[[nodiscard]] static std::optional<T> FloatFromStr(const char* str) noexcept
{
char* end = nullptr;
T res;
errno = 0;
if constexpr (std::is_same_v<T, float>)
res = std::strtof(str, &end);
else
res = static_cast<T>(std::strtod(str, &end));
if (errno == ERANGE) { return std::nullopt; }
if (str == end) { return std::nullopt; }
return res;
}
#endif//STRTOOLS_HPP

View File

@@ -1,82 +1,11 @@
/* swwriter.cpp - Copyright (C) 2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2024 a dinosaur
#include "swriter.hpp" #include "swriter.hpp"
#include "strtools.hpp"
#include <type_traits> #include <type_traits>
#include <limits>
#include <assert.h> #include <assert.h>
#define GNU_STYLE 0
#define MASM_STYLE 1
#define HEX_STYLE GNU_STYLE
static inline constexpr char HexU(uint8_t h) { return "0123456789ABCDEF"[h >> 4]; }
static inline constexpr char HexL(uint8_t l) { return "0123456789ABCDEF"[l & 15]; }
#if HEX_STYLE == GNU_STYLE
template <typename T> static void CHex(std::ostream& s, T x);
template <> void CHex(std::ostream& s, uint8_t x)
{
if (x > 9) s << "0x";
if (x > 15) s << HexU(x);
s << HexL(x);
}
template <> void CHex(std::ostream& s, uint16_t x)
{
if (x > 9) s << "0x";
if (x > 4095) s << HexU(static_cast<uint8_t>(x >> 8));
if (x > 255) s << HexL(static_cast<uint8_t>(x >> 8));
if (x > 15) s << HexU(static_cast<uint8_t>(x));
s << HexL(static_cast<uint8_t>(x));
}
template <> void CHex(std::ostream& s, uint32_t x)
{
if (x > 9) s << "0x";
if (x > 0xFFFFFFF) s << HexU(static_cast<uint8_t>(x >> 24));
if (x > 0xFFFFFF) s << HexL(static_cast<uint8_t>(x >> 24));
if (x > 0xFFFFF) s << HexU(static_cast<uint8_t>(x >> 16));
if (x > 65535) s << HexL(static_cast<uint8_t>(x >> 16));
if (x > 4095) s << HexU(static_cast<uint8_t>(x >> 8));
if (x > 255) s << HexL(static_cast<uint8_t>(x >> 8));
if (x > 15) s << HexU(static_cast<uint8_t>(x));
s << HexL(static_cast<uint8_t>(x));
}
#elif HEX_STYLE == MASM_STYLE
template <typename T> static void MHex(std::ostream& s, T x);
template <> void MHex(std::ostream& s, uint8_t x)
{
if (x > 159) s << "0";
if (x > 15) s << HexU(x); else if (x > 9) s << "0";
s << HexL(x);
if (x > 9) s << "h";
}
template <> void MHex(std::ostream& s, uint16_t x)
{
if (x > 40959) s << "0";
if (x > 4095) s << HexU(static_cast<uint8_t>(x >> 8)); else if (x > 2559) s << "0";
if (x > 255) s << HexL(static_cast<uint8_t>(x >> 8)); else if (x > 159) s << "0";
if (x > 15) s << HexU(static_cast<uint8_t>(x)); else if (x > 9) s << "0";
s << HexL(static_cast<uint8_t>(x));
if (x > 9) s << "h";
}
template <> void MHex(std::ostream& s, uint32_t x)
{
if (x > 0x9FFFFFFF) s << "0";
if (x > 0xFFFFFFF) s << HexU(static_cast<uint8_t>(x >> 24)); else if (x > 0x9FFFFFF) s << "0";
if (x > 0xFFFFFF) s << HexL(static_cast<uint8_t>(x >> 24)); else if (x > 0x9FFFFF) s << "0";
if (x > 0xFFFFF) s << HexU(static_cast<uint8_t>(x >> 16)); else if (x > 655359) s << "0";
if (x > 65535) s << HexL(static_cast<uint8_t>(x >> 16)); else if (x > 40959) s << "0";
if (x > 4095) s << HexU(static_cast<uint8_t>(x >> 8)); else if (x > 2559) s << "0";
if (x > 255) s << HexL(static_cast<uint8_t>(x >> 8)); else if (x > 159) s << "0";
if (x > 15) s << HexU(static_cast<uint8_t>(x)); else if (x > 9) s << "0";
s << HexL(static_cast<uint8_t>(x));
if (x > 9) s << "h";
}
#else
# error "Unknown hex style"
#endif
template <typename T> static constexpr const std::string_view DataType(); template <typename T> static constexpr const std::string_view DataType();
template <> constexpr const std::string_view DataType<uint8_t>() { return ".byte"; } template <> constexpr const std::string_view DataType<uint8_t>() { return ".byte"; }
@@ -95,11 +24,7 @@ static void WriteArrayDetail(std::ostream& s, const I beg, const I end, int perC
s << "\t" << DataType<Element>() << " "; s << "\t" << DataType<Element>() << " ";
const Element e = *it; const Element e = *it;
#if HEX_STYLE == MASM_STYLE
MHex(s, e);
#elif HEX_STYLE == GNU_STYLE
CHex(s, e); CHex(s, e);
#endif
if (++it == end) if (++it == end)
break; break;

View File

@@ -1,4 +1,5 @@
/* swwriter.hpp - Copyright (C) 2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2024 a dinosaur
#ifndef SWRITER_HPP #ifndef SWRITER_HPP
#define SWRITER_HPP #define SWRITER_HPP

View File

@@ -1,10 +1,16 @@
/* tmx2gba.cpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ // tmx2gba.cpp - main entry point
// SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#include <string_view>
constexpr std::string_view copyrightStr("(c) 2015-2024 a dinosaur");
#include "argparse.hpp" #include "argparse.hpp"
#include "tmxreader.hpp" #include "tmxreader.hpp"
#include "convert.hpp" #include "convert.hpp"
#include "headerwriter.hpp" #include "headerwriter.hpp"
#include "swriter.hpp" #include "swriter.hpp"
#include "strtools.hpp"
#include "config.h" #include "config.h"
#include <iostream> #include <iostream>
#include <map> #include <map>
@@ -19,15 +25,14 @@ struct Arguments
int offset = 0; int offset = 0;
int palette = 0; int palette = 0;
std::vector<std::string> objMappings; std::vector<std::string> objMappings;
bool help = false, showVersion = false; bool help = false;
}; };
using ArgParse::Option; using ArgParse::Option;
static const ArgParse::Options options = static const ArgParse::Options options =
{ {
Option::Optional('h', {}, "Display this help & command info"), Option::Optional('h', {}, "Display help & command info"),
Option::Optional('v', {}, "Display version & quit"),
Option::Optional('l', "name", "Name of layer to use (default first layer in TMX)"), Option::Optional('l', "name", "Name of layer to use (default first layer in TMX)"),
Option::Optional('y', "name", "Layer for palette mappings"), Option::Optional('y', "name", "Layer for palette mappings"),
Option::Optional('c', "name", "Output a separate 8bit collision map of the specified layer"), Option::Optional('c', "name", "Output a separate 8bit collision map of the specified layer"),
@@ -51,7 +56,6 @@ static bool ParseArgs(int argc, char** argv, Arguments& params)
switch (opt) switch (opt)
{ {
case 'h': params.help = true; return ParseCtrl::QUIT_EARLY; case 'h': params.help = true; return ParseCtrl::QUIT_EARLY;
case 'v': params.showVersion = true; return ParseCtrl::QUIT_EARLY;
case 'l': params.layer = arg; return ParseCtrl::CONTINUE; case 'l': params.layer = arg; return ParseCtrl::CONTINUE;
case 'c': params.collisionlay = arg; return ParseCtrl::CONTINUE; case 'c': params.collisionlay = arg; return ParseCtrl::CONTINUE;
case 'y': params.paletteLay = arg; return ParseCtrl::CONTINUE; case 'y': params.paletteLay = arg; return ParseCtrl::CONTINUE;
@@ -69,11 +73,8 @@ static bool ParseArgs(int argc, char** argv, Arguments& params)
catch (std::out_of_range const&) { return ParseCtrl::QUIT_ERR_RANGE; } catch (std::out_of_range const&) { return ParseCtrl::QUIT_ERR_RANGE; }
}); });
if (!parser.Parse(std::span(argv + 1, argc - 1))) if (!parser.Parse(std::span(argv + 1, argc - 1))) { return false; }
return false; if (params.help) { return true; }
if (params.help || params.showVersion)
return true;
if (!params.flagFile.empty()) if (!params.flagFile.empty())
{ {
@@ -115,41 +116,16 @@ static bool ParseArgs(int argc, char** argv, Arguments& params)
return true; return true;
} }
static std::string SanitiseLabel(const std::string_view ident)
{
std::string out;
out.reserve(ident.length());
int last = '_';
for (int i : ident)
{
if (out.empty() && std::isdigit(i))
continue;
if (!std::isalnum(i))
i = '_';
if (i != '_' || last != '_')
out.push_back(i);
last = i;
}
return out;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
Arguments p; Arguments p;
if (!ParseArgs(argc, argv, p)) if (!ParseArgs(argc, argv, p)) { return 1; }
return 1;
if (p.help) if (p.help)
{ {
std::cout << "tmx2gba v" << TMX2GBA_VERSION << ", " << copyrightStr << std::endl;
options.ShowHelpUsage(argv[0], std::cout); options.ShowHelpUsage(argv[0], std::cout);
return 0; return 0;
} }
if (p.showVersion)
{
std::cout << "tmx2gba version " << TMX2GBA_VERSION << ", (c) 2015-2024 a dinosaur" << std::endl;
return 0;
}
// Object mappings // Object mappings
std::map<std::string, uint32_t> objMapping; std::map<std::string, uint32_t> objMapping;
@@ -222,8 +198,7 @@ int main(int argc, char** argv)
// Convert to GBA-friendly charmap data // Convert to GBA-friendly charmap data
{ {
std::vector<uint16_t> charDat; std::vector<uint16_t> charDat;
if (!convert::ConvertCharmap(charDat, p.offset, p.palette, tmx)) if (!convert::ConvertCharmap(charDat, p.offset, p.palette, tmx)) { return 1; }
return 1;
// Write out charmap // Write out charmap
outH.WriteSize(tmx.GetSize().width, tmx.GetSize().height); outH.WriteSize(tmx.GetSize().width, tmx.GetSize().height);
@@ -235,8 +210,7 @@ int main(int argc, char** argv)
if (tmx.HasCollisionTiles()) if (tmx.HasCollisionTiles())
{ {
std::vector<uint8_t> collisionDat; std::vector<uint8_t> collisionDat;
if (!convert::ConvertCollision(collisionDat, tmx)) if (!convert::ConvertCollision(collisionDat, tmx)) { return 1; }
return 1;
outH.WriteCollision(collisionDat); outH.WriteCollision(collisionDat);
outS.WriteArray("Collision", collisionDat, 32); outS.WriteArray("Collision", collisionDat, 32);
@@ -245,8 +219,7 @@ int main(int argc, char** argv)
if (tmx.HasObjects()) if (tmx.HasObjects())
{ {
std::vector<uint32_t> objDat; std::vector<uint32_t> objDat;
if (!convert::ConvertObjects(objDat, tmx)) if (!convert::ConvertObjects(objDat, tmx)) { return 1; }
return 1;
outH.WriteObjects(objDat); outH.WriteObjects(objDat);
outS.WriteArray("Objdat", objDat); outS.WriteArray("Objdat", objDat);

View File

@@ -1,4 +1,5 @@
/* tmxlayer.hpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#ifndef TMXLAYER_HPP #ifndef TMXLAYER_HPP
#define TMXLAYER_HPP #define TMXLAYER_HPP
@@ -25,7 +26,7 @@ public:
TmxLayer(int width, int height, const std::string_view name, std::vector<uint32_t>&& tileDat) noexcept TmxLayer(int width, int height, const std::string_view name, std::vector<uint32_t>&& tileDat) noexcept
: mName(name), mWidth(width), mHeight(height), mTileDat(std::move(tileDat)) {} : mName(name), mWidth(width), mHeight(height), mTileDat(std::move(tileDat)) {}
[[nodiscard]] constexpr const std::string_view Name() const noexcept { return mName; } [[nodiscard]] const std::string_view Name() const noexcept { return mName; }
[[nodiscard]] constexpr std::pair<int, int> TileCount() const noexcept { return { mWidth, mHeight }; } [[nodiscard]] constexpr std::pair<int, int> TileCount() const noexcept { return { mWidth, mHeight }; }
[[nodiscard]] constexpr const std::span<const uint32_t> Tiles() const noexcept { return mTileDat; } [[nodiscard]] constexpr const std::span<const uint32_t> Tiles() const noexcept { return mTileDat; }
}; };

236
src/tmxmap.cpp Normal file
View File

@@ -0,0 +1,236 @@
// SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#include "tmxmap.hpp"
#include "strtools.hpp"
#include "config.h"
#include <pugixml.hpp>
#include <base64.h>
#ifdef USE_ZLIB
# include <zlib.h>
#else
# include "gzip.hpp"
#endif
#include <zstd.h>
#include <cerrno>
#include <algorithm>
enum class Encoding { XML, BASE64, CSV, INVALID };
enum class Compression { NONE, GZIP, ZLIB, ZSTD, INVALID };
[[nodiscard]] static Encoding EncodingFromStr(const std::string_view str)
{
if (str.empty()) { return Encoding::XML; }
if (str == "base64") { return Encoding::BASE64; }
if (str == "csv") { return Encoding::CSV; }
return Encoding::INVALID;
}
[[nodiscard]] static Compression CompressionFromStr(const std::string_view str)
{
if (str.empty()) { return Compression::NONE; }
if (str == "gzip") { return Compression::GZIP; }
if (str == "zlib") { return Compression::ZLIB; }
if (str == "zstd") { return Compression::ZSTD; }
return Compression::INVALID;
}
[[nodiscard]] static bool DecodeBase64(
std::vector<uint32_t>& out, size_t numTiles,
const std::string_view base64, Compression compression)
{
auto decoded = base64_decode(TrimWhitespace(base64));
if (decoded.empty()) { return false; }
const std::span source(reinterpret_cast<const uint8_t*>(decoded.data()), decoded.size());
//FIXME: lmao what is big endian
switch (compression)
{
case Compression::GZIP:
#ifndef USE_ZLIB
{
out.resize(numTiles);
GZipReader reader;
if (!reader.OpenMemory(source) ||
!reader.Read({ reinterpret_cast<uint8_t*>(out.data()), sizeof(uint32_t) * numTiles }) ||
!reader.Check())
return false;
return true;
}
#endif
case Compression::ZLIB:
{
out.resize(numTiles);
// Decompress gzip/zlib data with zlib/zlib data miniz
z_stream s =
{
.next_in = const_cast<Bytef*>(source.data()),
.avail_in = static_cast<unsigned int>(source.size()),
.next_out = reinterpret_cast<Bytef*>(out.data()),
.avail_out = static_cast<unsigned int>(sizeof(uint32_t) * numTiles),
.zalloc = nullptr, .zfree = nullptr, .opaque = nullptr
};
#ifdef USE_ZLIB
const int wbits = (compression == Compression::GZIP) ? MAX_WBITS | 16 : MAX_WBITS;
#else
const int wbits = MZ_DEFAULT_WINDOW_BITS;
#endif
if (inflateInit2(&s, wbits) != Z_OK)
return false;
int res = inflate(&s, Z_FINISH);
inflateEnd(&s);
return res == Z_STREAM_END;
}
case Compression::ZSTD:
{
out.resize(numTiles);
auto res = ZSTD_decompress(
reinterpret_cast<void*>(out.data()),
sizeof(uint32_t) * numTiles,
source.data(), source.size());
return !ZSTD_isError(res);
}
case Compression::NONE:
{
out.reserve(numTiles);
const auto end = source.end();
for (auto it = source.begin(); it < end - 3;)
{
uint32_t tile = *it++;
tile |= static_cast<uint32_t>(*it++) << 8u;
tile |= static_cast<uint32_t>(*it++) << 16u;
tile |= static_cast<uint32_t>(*it++) << 24u;
out.emplace_back(tile);
}
return true;
}
case Compression::INVALID:
default: return false;
}
}
void TmxMap::ReadTileset(const pugi::xml_node& xNode)
{
std::string_view name = xNode.attribute("name").value();
std::string_view source = xNode.attribute("source").value();
auto firstGid = UintFromStr<uint32_t>(xNode.attribute("firstgid").value()).value_or(0);
auto numTiles = UintFromStr<uint32_t>(xNode.attribute("tilecount").value()).value_or(0);
if (numTiles == 0)
return; // FIXME: warn about empty tilesets or something
mTilesets.emplace_back(TmxTileset(name, source, firstGid, numTiles));
}
void TmxMap::ReadLayer(const pugi::xml_node& xNode)
{
std::string_view name = xNode.attribute("name").value();
// Read layer size
int width = IntFromStr<int>(xNode.attribute("width").value()).value_or(0);
int height = IntFromStr<int>(xNode.attribute("height").value()).value_or(0);
if (width <= 0 || height <= 0) { return; }
const auto numTiles = static_cast<size_t>(width) * static_cast<size_t>(height);
auto xData = xNode.child("data");
if (xData.empty() || xData.first_child().empty())
return;
// Read data
std::vector<uint32_t> tileDat;
auto encoding = EncodingFromStr(xData.attribute("encoding").value());
if (encoding == Encoding::BASE64)
{
const std::string_view base64(xData.child_value());
if (base64.empty())
return;
const auto compression = CompressionFromStr(xData.attribute("compression").value());
if (compression == Compression::INVALID || !DecodeBase64(tileDat, numTiles, base64, compression))
return;
}
else if (encoding == Encoding::XML)
{
tileDat.reserve(numTiles);
std::ranges::transform(xData.children("tile"), std::back_inserter(tileDat), [](auto it)
-> uint32_t { return UintFromStr<uint32_t>(it.attribute("gid").value()).value_or(0); });
}
else if (encoding == Encoding::CSV)
{
tileDat.reserve(numTiles);
const std::string_view csv(xData.child_value());
std::string::size_type pos = 0;
while (true)
{
// TODO: check if this has a problem on other locales?
auto gid = UintFromStr<uint32_t>(csv.substr(pos).data());
if (gid.has_value())
tileDat.emplace_back(gid.value());
if ((pos = csv.find(',', pos)) == std::string::npos)
break;
++pos;
}
}
else { return; }
mLayers.emplace_back(TmxLayer(width, height, name, std::move(tileDat)));
}
void TmxMap::ReadObjectGroup(const pugi::xml_node& xNode)
{
std::string_view name(xNode.value());
std::vector<TmxObject> objects;
const auto xObjects = xNode.children("object");
//mObjects.reserve(xObjects.size())
for (const auto it : xObjects)
{
int id = IntFromStr<int>(it.attribute("id").value()).value_or(0);
std::string_view name = it.attribute("name").value();
// Read axis-aligned bounding box
auto x = FloatFromStr<float>(it.attribute("x").value()).value_or(0.0f);
auto y = FloatFromStr<float>(it.attribute("y").value()).value_or(0.0f);
auto width = FloatFromStr<float>(it.attribute("width").value()).value_or(0.0f);
auto height = FloatFromStr<float>(it.attribute("height").value()).value_or(0.0f);
objects.emplace_back(TmxObject(id, name, { x, y, width, height }));
}
if (objects.empty())
return; //FIXME: log this
mObjectGroups.emplace_back(TmxObjectGroup(name, std::move(objects)));
}
bool TmxMap::Load(const std::string& inPath)
{
// Parse document
pugi::xml_document xDoc;
auto res = xDoc.load_file(inPath.c_str());
if (res.status != pugi::xml_parse_status::status_ok)
return false;
// Get map node
auto xMap = xDoc.child("map");
if (xMap.empty())
return false;
// Read map attribs
mWidth = IntFromStr<int>(xMap.attribute("width").value()).value_or(0);
mHeight = IntFromStr<int>(xMap.attribute("height").value()).value_or(0);
// Read nodes
for (auto it : xMap.children())
{
std::string_view name(it.name());
if (!name.compare("layer")) { ReadLayer(it); }
else if (!name.compare("tileset")) { ReadTileset(it); }
else if (!name.compare("objectgroup")) { ReadObjectGroup(it); }
}
return true;
}

38
src/tmxmap.hpp Normal file
View File

@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#ifndef TMXMAP_HPP
#define TMXMAP_HPP
#include "tmxtileset.hpp"
#include "tmxobject.hpp"
#include "tmxlayer.hpp"
#include <vector>
#include <span>
#include <string>
#include <string_view>
namespace pugi { class xml_node; }
class TmxMap
{
int mWidth = 0, mHeight = 0;
std::vector<TmxLayer> mLayers;
std::vector<TmxTileset> mTilesets;
std::vector<TmxObjectGroup> mObjectGroups;
void ReadTileset(const pugi::xml_node& xNode);
void ReadLayer(const pugi::xml_node& xNode);
void ReadObjectGroup(const pugi::xml_node& xNode);
public:
[[nodiscard]] bool Load(const std::string& inPath);
[[nodiscard]] constexpr std::pair<int, int> TileCount() const noexcept { return { mWidth, mHeight }; }
[[nodiscard]] constexpr const std::vector<TmxTileset>& Tilesets() const noexcept { return mTilesets; }
[[nodiscard]] constexpr const std::vector<TmxLayer>& Layers() const noexcept { return mLayers; }
[[nodiscard]] constexpr const std::vector<TmxObjectGroup>& ObjectGroups() const noexcept { return mObjectGroups; }
};
#endif//TMXMAP_HPP

View File

@@ -1,25 +1,43 @@
/* tmxobject.hpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#ifndef TMXOBJECT_HPP #ifndef TMXOBJECT_HPP
#define TMXOBJECT_HPP #define TMXOBJECT_HPP
#include <string> #include <string>
#include <string_view>
#include <vector>
#include <utility> #include <utility>
class TmxObject class TmxObject
{ {
public: public:
TmxObject(std::string_view name, float x, float y) : mName(name), mPos{ x, y } {}
template <typename T> template <typename T>
struct Position { T x, y; }; struct AABB { T x, y, w, h; };
constexpr const std::string_view Name() const noexcept { return mName; } TmxObject(int id, std::string_view name, AABB<float>&& box) : mId(id), mName(name), mBox(std::move(box)) {}
constexpr Position<float> Pos() const noexcept { return mPos; }
constexpr int Id() const noexcept { return mId; }
const std::string_view Name() const noexcept { return mName; }
constexpr const AABB<float>& Box() const noexcept { return mBox; }
private: private:
int mId;
std::string mName; std::string mName;
Position<float> mPos; AABB<float> mBox;
};
class TmxObjectGroup
{
std::string mName;
std::vector<TmxObject> mObjects;
public:
TmxObjectGroup(std::string_view name, std::vector<TmxObject>&& objects)
: mName(name), mObjects(std::move(objects)) {}
const std::string_view Name() const noexcept { return mName; }
constexpr const std::vector<TmxObject>& Objects() const noexcept { return mObjects; }
}; };
#endif//TMXOBJECT_HPP #endif//TMXOBJECT_HPP

View File

@@ -1,201 +1,13 @@
/* tmxreader.cpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#include "tmxreader.hpp" #include "tmxreader.hpp"
#include "tmxtileset.hpp" #include "tmxmap.hpp"
#include "tmxobject.hpp"
#include "tmxlayer.hpp"
#include "base64.h"
#ifdef USE_ZLIB
# include <zlib.h>
#else
# include "gzip.hpp"
#endif
#include <rapidxml/rapidxml.hpp>
#include <optional> #include <optional>
#include <algorithm> #include <algorithm>
#include <ranges> #include <ranges>
#include <sstream>
#include <fstream>
class TmxMap
{
int mWidth = 0, mHeight = 0;
std::vector<TmxLayer> mLayers;
std::vector<TmxTileset> mTilesets;
std::vector<TmxObject> mObjects;
[[nodiscard]] bool Decode(std::span<uint32_t> out, const std::string_view base64);
void ReadTileset(rapidxml::xml_node<>* aXNode);
void ReadLayer(rapidxml::xml_node<>* aXNode);
void ReadObjects(rapidxml::xml_node<>* aXNode);
public:
[[nodiscard]] bool Load(const std::string_view inPath);
constexpr std::pair<int, int> TileCount() const noexcept { return { mWidth, mHeight }; }
constexpr const std::vector<TmxTileset>& Tilesets() const noexcept { return mTilesets; }
constexpr const std::vector<TmxLayer>& Layers() const noexcept { return mLayers; }
};
bool TmxMap::Decode(std::span<uint32_t> out, const std::string_view base64)
{
// Cut leading & trailing whitespace (including newlines)
auto beg = std::find_if_not(base64.begin(), base64.end(), ::isspace);
if (beg == std::end(base64))
return false;
auto end = std::find_if_not(base64.rbegin(), base64.rend(), ::isspace);
std::size_t begOff = std::distance(base64.begin(), beg);
std::size_t endOff = std::distance(end, base64.rend()) - begOff;
const auto trimmed = base64.substr(begOff, endOff);
// Decode base64 string
std::string decoded = base64_decode(trimmed);
// Decompress compressed data
auto dstSize = static_cast<uLongf>(sizeof(uint32_t) * out.size());
int res = uncompress(
reinterpret_cast<unsigned char*>(out.data()),
&dstSize,
reinterpret_cast<const unsigned char*>(decoded.data()),
static_cast<uLong>(decoded.size()));
return res >= 0;
}
void TmxMap::ReadTileset(rapidxml::xml_node<>* aXNode)
{
std::string_view name, source;
uint32_t firstGid = 0, lastGid = 0;
// Read name
auto xAttrib = aXNode->first_attribute("name");
if (xAttrib != nullptr)
name = xAttrib->value();
// Read source
xAttrib = aXNode->first_attribute("source");
if (xAttrib != nullptr)
source = xAttrib->value();
// Read first global ID
xAttrib = aXNode->first_attribute("firstgid");
if (xAttrib != nullptr)
firstGid = static_cast<uint32_t>(std::stoul(xAttrib->value()));
// Read last global ID
xAttrib = aXNode->first_attribute("lastgid");
if (xAttrib)
lastGid = static_cast<uint32_t>(std::stoul(xAttrib->value()));
mTilesets.emplace_back(TmxTileset(name, source, firstGid, lastGid));
}
void TmxMap::ReadLayer(rapidxml::xml_node<>* aXNode)
{
std::string_view name;
int width = 0, height = 0;
// Read name
auto xAttrib = aXNode->first_attribute("name");
if (xAttrib != nullptr)
name = xAttrib->value();
// Read width
xAttrib = aXNode->first_attribute("width");
if (xAttrib != nullptr)
width = std::stoi(xAttrib->value());
// Read height
xAttrib = aXNode->first_attribute("height");
if (xAttrib != nullptr)
height = std::stoi(xAttrib->value());
// Read tile data
auto xData = aXNode->first_node("data");
if (xData == nullptr)
return;
// TODO: don't assume base64
std::vector<uint32_t> tileDat(width * height);
if (!Decode(tileDat, xData->value()))
return;
mLayers.emplace_back(TmxLayer(width, height, name, std::move(tileDat)));
}
void TmxMap::ReadObjects(rapidxml::xml_node<>* aXNode)
{
for (auto xNode = aXNode->first_node(); xNode != nullptr; xNode = xNode->next_sibling())
{
if (strcmp(xNode->name(), "object") != 0)
continue;
std::string_view name;
float x = 0.0f, y = 0.0f;
// Read name
auto 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());
mObjects.emplace_back(TmxObject(name, x, y));
}
}
bool TmxMap::Load(const std::string_view inPath)
{
// Read file into a buffer
auto inFile = std::ifstream(inPath);
std::stringstream buf;
buf << inFile.rdbuf();
std::string strXml = buf.str();
buf.clear();
// Parse document
rapidxml::xml_document<> xDoc;
xDoc.parse<0>(const_cast<char*>(strXml.c_str()));
// Get map node
auto xMap = xDoc.first_node("map");
if (xMap == nullptr)
return false;
// Read map attribs
rapidxml::xml_attribute<>* xAttrib = nullptr;
if ((xAttrib = xMap->first_attribute("width")) != nullptr)
mWidth = std::stoi(xAttrib->value());
if ((xAttrib = xMap->first_attribute("height")) != nullptr)
mHeight = std::stoi(xAttrib->value());
// Read nodes
for (auto xNode = xMap->first_node(); xNode != nullptr; xNode = xNode->next_sibling())
{
// Read layer nodes
const auto xName = xNode->name();
if (std::strcmp(xName, "layer") == 0)
ReadLayer(xNode);
else if (std::strcmp(xName, "tileset") == 0)
ReadTileset(xNode);
else if (std::strcmp(xName, "objectgroup") == 0)
ReadObjects(xNode);
}
return true;
}
TmxReader::Error TmxReader::Open(const std::string& inPath, TmxReader::Error TmxReader::Open(const std::string& inPath,
const std::string_view graphicsName, const std::string_view graphicsName,
const std::string_view paletteName, const std::string_view paletteName,
@@ -209,10 +21,7 @@ TmxReader::Error TmxReader::Open(const std::string& inPath,
using std::optional; using std::optional;
using std::reference_wrapper; using std::reference_wrapper;
optional<reference_wrapper<const TmxLayer>> layerGfx; optional<reference_wrapper<const TmxLayer>> layerGfx, layerCls, layerPal;
optional<reference_wrapper<const TmxLayer>> layerCls;
optional<reference_wrapper<const TmxLayer>> layerPal;
optional<reference_wrapper<std::vector<const TmxObject>>> objGroups;
// Read layers // Read layers
for (const auto& layer : map.Layers()) for (const auto& layer : map.Layers())
@@ -225,12 +34,6 @@ TmxReader::Error TmxReader::Open(const std::string& inPath,
if (!layerGfx.has_value() && (graphicsName.empty() || name == graphicsName)) { layerGfx = layer; } if (!layerGfx.has_value() && (graphicsName.empty() || name == graphicsName)) { layerGfx = layer; }
if (!collisionName.empty() && !layerCls.has_value() && name == collisionName) { layerCls = layer; } if (!collisionName.empty() && !layerCls.has_value() && name == collisionName) { layerCls = layer; }
if (!paletteName.empty() && !layerPal.has_value() && name == paletteName) { layerPal = layer; } if (!paletteName.empty() && !layerPal.has_value() && name == paletteName) { layerPal = layer; }
/*
else if (!objMapping.empty() && layer->getType() == tmx::Layer::Type::Object)
{
objGroups.emplace_back(layer->getLayerAs<ObjectGroup>());
}
*/
} }
// Check layers // Check layers
@@ -250,7 +53,7 @@ TmxReader::Error TmxReader::Open(const std::string& inPath,
// Read graphics layer // Read graphics layer
mGraphics.reserve(numTiles); mGraphics.reserve(numTiles);
for (auto tmxTile : layerGfx.value().get().Tiles()) for (auto tmxTile : layerGfx.value().get().Tiles())
mGraphics.emplace_back(Tile{ tmxTile & ~FLIP_MASK, static_cast<uint8_t>((tmxTile & FLIP_MASK) >> 28) }); mGraphics.emplace_back(Tile{ tmxTile & ~TmxLayer::FLIP_MASK, static_cast<uint8_t>((tmxTile & TmxLayer::FLIP_MASK) >> 28) });
// Read optional layers // Read optional layers
if (layerPal.has_value()) if (layerPal.has_value())
@@ -258,7 +61,7 @@ TmxReader::Error TmxReader::Open(const std::string& inPath,
std::vector<uint32_t> v; std::vector<uint32_t> v;
v.reserve(numTiles); v.reserve(numTiles);
for (auto tmxTile : layerPal.value().get().Tiles()) for (auto tmxTile : layerPal.value().get().Tiles())
v.emplace_back(tmxTile & ~FLIP_MASK); v.emplace_back(tmxTile & ~TmxLayer::FLIP_MASK);
mPalette.emplace(v); mPalette.emplace(v);
} }
if (layerCls.has_value()) if (layerCls.has_value())
@@ -266,56 +69,41 @@ TmxReader::Error TmxReader::Open(const std::string& inPath,
std::vector<uint32_t> v; std::vector<uint32_t> v;
v.reserve(numTiles); v.reserve(numTiles);
for (auto tmxTile : layerCls.value().get().Tiles()) for (auto tmxTile : layerCls.value().get().Tiles())
v.emplace_back(tmxTile & ~FLIP_MASK); v.emplace_back(tmxTile & ~TmxLayer::FLIP_MASK);
mCollision.emplace(v); mCollision.emplace(v);
} }
// Read tilesets // Read tilesets
const auto& tilesets = map.Tilesets(); const auto& tilesets = map.Tilesets();
mGidTable.reserve(tilesets.size()); mGidTable.reserve(tilesets.size());
for (const auto& set : tilesets) std::ranges::transform(tilesets, std::back_inserter(mGidTable),
mGidTable.emplace_back(set.GidRange()); [](const auto& it) { return it.GidRange(); });
// Read objects // Read objects
if (!objMapping.empty()) if (!map.ObjectGroups().empty())
{ {
std::vector<Object> v; std::vector<Object> objs;
for (const auto& tmxObj : objGroups.value().get()) for (const auto& group : map.ObjectGroups())
{ {
auto it = objMapping.find(std::string(tmxObj.Name())); const auto& tmxObjects = group.Objects();
if (it == objMapping.end()) objs.reserve(objs.size() + tmxObjects.size());
continue;
const auto& pos = tmxObj.Pos();
Object obj;
obj.id = it->second;
obj.x = pos.x;
obj.y = pos.y;
v.emplace_back(obj);
}
/*
for (const auto& group : objGroups)
{
const auto& tmxObjects = group.get().Objects();
v.reserve(v.size() + tmxObjects.size());
for (const auto& tmxObj : tmxObjects) for (const auto& tmxObj : tmxObjects)
{ {
auto it = objMapping.find(tmxObj.getName()); auto it = objMapping.find(std::string(tmxObj.Name()));
if (it == objMapping.end()) if (it == objMapping.end())
continue; continue;
const auto& aabb = tmxObj.getAABB(); const auto& aabb = tmxObj.Box();
Object obj; objs.emplace_back(Object
obj.id = it->second; {
obj.x = aabb.left; .id = it->second,
obj.y = aabb.top; .x = aabb.x,
.y = aabb.y
v.emplace_back(obj); });
} }
} }
*/ if (!objs.empty())
mObjects.emplace(v); mObjects.emplace(objs);
} }
return Error::OK; return Error::OK;

View File

@@ -1,4 +1,5 @@
/* tmxreader.hpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#ifndef TMXREADER_HPP #ifndef TMXREADER_HPP
#define TMXREADER_HPP #define TMXREADER_HPP

View File

@@ -1,4 +1,5 @@
/* tmxtileset.hpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ // SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
#ifndef TMXTILESET_HPP #ifndef TMXTILESET_HPP
#define TMXTILESET_HPP #define TMXTILESET_HPP
@@ -10,15 +11,16 @@
class TmxTileset class TmxTileset
{ {
std::string mName, mSource; std::string mName, mSource;
uint32_t mFirstGid = 0, mLastGid = 0; uint32_t mFirstGid = 0, mTileCount = 0;
public: public:
TmxTileset(const std::string_view name, const std::string_view source, uint32_t firstGid, uint32_t lastGid) TmxTileset(const std::string_view name, const std::string_view source, uint32_t firstGid, uint32_t tileCount)
: mName(name), mSource(source), mFirstGid(firstGid), mLastGid(lastGid) {} : mName(name), mSource(source), mFirstGid(firstGid), mTileCount(tileCount) {}
[[nodiscard]] constexpr const std::string_view Name() const noexcept { return mName; } [[nodiscard]] const std::string_view Name() const noexcept { return mName; }
[[nodiscard]] constexpr const std::string_view Source() const noexcept { return mSource; } [[nodiscard]] const std::string_view Source() const noexcept { return mSource; }
[[nodiscard]] constexpr const std::pair<uint32_t, uint32_t> GidRange() const noexcept { return { mFirstGid, mLastGid }; } [[nodiscard]] constexpr const std::pair<uint32_t, uint32_t> GidRange() const noexcept
{ return { mFirstGid, mFirstGid + mTileCount - 1 }; }
}; };
#endif//TMXTILESET_HPP #endif//TMXTILESET_HPP