mirror of
https://github.com/ScrelliCopter/tmx2gba.git
synced 2025-02-21 03:29:25 +11:00
@@ -41,8 +41,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(ext/base64)
|
add_subdirectory(ext/base64)
|
||||||
|
add_subdirectory(ext/rapidxml)
|
||||||
add_subdirectory(ext/tmxlite)
|
|
||||||
|
|
||||||
# Main tmx2gba sources
|
# Main tmx2gba sources
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|||||||
4
ext/rapidxml/CMakeLists.txt
Normal file
4
ext/rapidxml/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
add_library(rapidxml INTERFACE)
|
||||||
|
add_library(External::rapidxml ALIAS rapidxml)
|
||||||
|
target_include_directories(rapidxml
|
||||||
|
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
52
ext/rapidxml/license.txt
Normal file
52
ext/rapidxml/license.txt
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
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.
|
||||||
2596
ext/rapidxml/rapidxml/rapidxml.hpp
Normal file
2596
ext/rapidxml/rapidxml/rapidxml.hpp
Normal file
File diff suppressed because it is too large
Load Diff
174
ext/rapidxml/rapidxml/rapidxml_iterators.hpp
Normal file
174
ext/rapidxml/rapidxml/rapidxml_iterators.hpp
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
#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
|
||||||
421
ext/rapidxml/rapidxml/rapidxml_print.hpp
Normal file
421
ext/rapidxml/rapidxml/rapidxml_print.hpp
Normal file
@@ -0,0 +1,421 @@
|
|||||||
|
#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 (< > ' " &)
|
||||||
|
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
|
||||||
122
ext/rapidxml/rapidxml/rapidxml_utils.hpp
Normal file
122
ext/rapidxml/rapidxml/rapidxml_utils.hpp
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
#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
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
project(tmxlite VERSION 1.3.1)
|
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} STATIC
|
|
||||||
include/tmxlite/Config.hpp
|
|
||||||
include/tmxlite/FreeFuncs.hpp
|
|
||||||
include/tmxlite/ImageLayer.hpp
|
|
||||||
include/tmxlite/Layer.hpp
|
|
||||||
include/tmxlite/LayerGroup.hpp
|
|
||||||
include/tmxlite/Map.hpp
|
|
||||||
include/tmxlite/Object.hpp
|
|
||||||
include/tmxlite/ObjectGroup.hpp
|
|
||||||
include/tmxlite/ObjectTypes.hpp
|
|
||||||
include/tmxlite/Property.hpp
|
|
||||||
include/tmxlite/TileLayer.hpp
|
|
||||||
include/tmxlite/Tileset.hpp
|
|
||||||
include/tmxlite/Types.hpp
|
|
||||||
include/tmxlite/Types.inl
|
|
||||||
include/tmxlite/detail/Log.hpp
|
|
||||||
|
|
||||||
src/FreeFuncs.cpp
|
|
||||||
src/ImageLayer.cpp
|
|
||||||
src/Map.cpp
|
|
||||||
src/Object.cpp
|
|
||||||
src/ObjectGroup.cpp
|
|
||||||
src/Property.cpp
|
|
||||||
src/TileLayer.cpp
|
|
||||||
src/LayerGroup.cpp
|
|
||||||
src/Tileset.cpp
|
|
||||||
src/ObjectTypes.cpp)
|
|
||||||
|
|
||||||
if (NOT USE_ZLIB)
|
|
||||||
target_sources(${PROJECT_NAME} PRIVATE
|
|
||||||
include/tmxlite/detail/gzip.hpp
|
|
||||||
src/detail/gzip.cpp)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
|
||||||
CXX_STANDARD 20
|
|
||||||
CXX_STANDARD_REQUIRED ON)
|
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include)
|
|
||||||
|
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall)
|
|
||||||
|
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE
|
|
||||||
$<$<BOOL:${MSVC}>:_CRT_SECURE_NO_WARNINGS> # disable msvc warning
|
|
||||||
$<$<TARGET_EXISTS:ZLIB::ZLIB>:USE_ZLIB>)
|
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} base64::base64 pugixml Zstd::Zstd
|
|
||||||
$<$<TARGET_EXISTS:ZLIB::ZLIB>:ZLIB::ZLIB>
|
|
||||||
$<$<TARGET_EXISTS:miniz::miniz>:miniz::miniz>)
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
(c)Matt Marchant & contributors 2016 - 2021 http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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:
|
|
||||||
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.
|
|
||||||
Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
|
||||||
|
|
||||||
This notice may not be removed or altered from any source distribution.
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
(c) Matt Marchant 2016 - 2021
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
//static build doesn't need import/export macros
|
|
||||||
#define TMXLITE_EXPORT_API
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2021
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
#include "tmxlite/Types.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <vector>
|
|
||||||
#include <functional>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
//using inline here just to supress unused warnings on gcc
|
|
||||||
bool decompress(const char* source, std::vector<unsigned char>& dest, std::size_t inSize, std::size_t expectedSize);
|
|
||||||
|
|
||||||
static inline Colour colourFromString(std::string str)
|
|
||||||
{
|
|
||||||
//removes preceding #
|
|
||||||
auto result = str.find_last_of('#');
|
|
||||||
if (result != std::string::npos)
|
|
||||||
{
|
|
||||||
str = str.substr(result + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (str.size() == 6 || str.size() == 8)
|
|
||||||
{
|
|
||||||
unsigned int value, r, g, b;
|
|
||||||
unsigned int a = 255;
|
|
||||||
std::stringstream input(str);
|
|
||||||
input >> std::hex >> value;
|
|
||||||
|
|
||||||
r = (value >> 16) & 0xff;
|
|
||||||
g = (value >> 8) & 0xff;
|
|
||||||
b = value & 0xff;
|
|
||||||
|
|
||||||
if (str.size() == 8)
|
|
||||||
{
|
|
||||||
a = (value >> 24) & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
return{ std::uint8_t(r), std::uint8_t(g), std::uint8_t(b), std::uint8_t(a) };
|
|
||||||
}
|
|
||||||
Logger::log(str + ": not a valid colour string", Logger::Type::Error);
|
|
||||||
return{};
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::string resolveFilePath(std::string path, const std::string& workingDir)
|
|
||||||
{
|
|
||||||
static const std::string match("../");
|
|
||||||
std::size_t result = path.find(match);
|
|
||||||
std::size_t count = 0;
|
|
||||||
while (result != std::string::npos)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
path = path.substr(result + match.size());
|
|
||||||
result = path.find(match);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workingDir.empty()) return path;
|
|
||||||
|
|
||||||
std::string outPath = workingDir;
|
|
||||||
for (auto i = 0u; i < count; ++i)
|
|
||||||
{
|
|
||||||
result = outPath.find_last_of('/');
|
|
||||||
if (result != std::string::npos)
|
|
||||||
{
|
|
||||||
outPath = outPath.substr(0, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return outPath + '/' + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::string getFilePath(const std::string& path)
|
|
||||||
{
|
|
||||||
//TODO this doesn't actually check that there is a file at the
|
|
||||||
//end of the path, or that it's even a valid path...
|
|
||||||
|
|
||||||
static auto searchFunc = [](const char separator, const std::string& path)->std::string
|
|
||||||
{
|
|
||||||
std::size_t i = path.rfind(separator, path.length());
|
|
||||||
if (i != std::string::npos)
|
|
||||||
{
|
|
||||||
return(path.substr(0, i + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32 //try windows formatted paths first
|
|
||||||
std::string retVal = searchFunc('\\', path);
|
|
||||||
if (!retVal.empty()) return retVal;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return searchFunc('/', path);
|
|
||||||
}
|
|
||||||
} //namespacec tmx
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2022
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Config.hpp"
|
|
||||||
#include "tmxlite/Layer.hpp"
|
|
||||||
#include "tmxlite/Types.hpp"
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
\brief Image layers contain a single image which make up that
|
|
||||||
layer. The parser contains the fully resolved path to the image
|
|
||||||
relative to the working directory.
|
|
||||||
*/
|
|
||||||
class TMXLITE_EXPORT_API ImageLayer final : public Layer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit ImageLayer(const std::string&);
|
|
||||||
|
|
||||||
Type getType() const override { return Layer::Type::Image; }
|
|
||||||
void parse(const pugi::xml_node&, Map*) override;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the path, relative to the working directory,
|
|
||||||
of the image used by the image layer.
|
|
||||||
*/
|
|
||||||
const std::string& getImagePath() const { return m_filePath; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the colour used by the image to represent transparent
|
|
||||||
pixels. By default this is (0, 0, 0, 0)
|
|
||||||
*/
|
|
||||||
const Colour& getTransparencyColour() const { return m_transparencyColour; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns true if the image used by this layer specifically states a
|
|
||||||
colour to use as transparency
|
|
||||||
*/
|
|
||||||
bool hasTransparency() const { return m_hasTransparency; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the size of the image of the image layer in pixels.
|
|
||||||
*/
|
|
||||||
const Vector2u& getImageSize() const { return m_imageSize; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns true if the image drawn by this layer is repeated along
|
|
||||||
the X axis.
|
|
||||||
*/
|
|
||||||
bool hasRepeatX() const { return m_hasRepeatX; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns true if the image drawn by this layer is repeated along
|
|
||||||
the Y axis.
|
|
||||||
*/
|
|
||||||
bool hasRepeatY() const { return m_hasRepeatY; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_workingDir;
|
|
||||||
std::string m_filePath;
|
|
||||||
Colour m_transparencyColour;
|
|
||||||
bool m_hasTransparency;
|
|
||||||
Vector2u m_imageSize;
|
|
||||||
bool m_hasRepeatX;
|
|
||||||
bool m_hasRepeatY;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline ImageLayer& Layer::getLayerAs<ImageLayer>()
|
|
||||||
{
|
|
||||||
assert(getType() == Type::Image);
|
|
||||||
return *static_cast<ImageLayer*>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline const ImageLayer& Layer::getLayerAs<ImageLayer>() const
|
|
||||||
{
|
|
||||||
assert(getType() == Type::Image);
|
|
||||||
return *static_cast<const ImageLayer*>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2023
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Config.hpp"
|
|
||||||
#include "tmxlite/Property.hpp"
|
|
||||||
#include "tmxlite/Types.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace pugi
|
|
||||||
{
|
|
||||||
class xml_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
class Map;
|
|
||||||
class TileLayer;
|
|
||||||
class ObjectGroup;
|
|
||||||
class ImageLayer;
|
|
||||||
class LayerGroup;
|
|
||||||
/*!
|
|
||||||
\brief Represents a layer of a tmx format tile map.
|
|
||||||
This is an abstract base class from which all layer
|
|
||||||
types are derived.
|
|
||||||
*/
|
|
||||||
class TMXLITE_EXPORT_API Layer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Ptr = std::unique_ptr<Layer>;
|
|
||||||
|
|
||||||
Layer() : m_opacity(1.f), m_visible(true) {};
|
|
||||||
virtual ~Layer() = default;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Layer type as returned by getType()
|
|
||||||
Tile: this layer is a TileLayer type
|
|
||||||
Object: This layer is an ObjectGroup type
|
|
||||||
Image: This layer is an ImageLayer type
|
|
||||||
Group: This layer is a LayerGroup type
|
|
||||||
*/
|
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
Tile,
|
|
||||||
Object,
|
|
||||||
Image,
|
|
||||||
Group
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a Type value representing the concrete type.
|
|
||||||
Use this when deciding which conrete layer type to use when
|
|
||||||
calling the templated function getLayerAs<T>()
|
|
||||||
*/
|
|
||||||
virtual Type getType() const = 0;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the class of the Layer, as defined in the editor Tiled 1.9+
|
|
||||||
*/
|
|
||||||
const std::string& getClass() const { return m_class; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Use this to get a reference to the concrete layer type
|
|
||||||
which this layer points to.
|
|
||||||
Use getType() to return the type value of this layer and determine
|
|
||||||
if the concrete type is TileLayer, ObjectGroup, ImageLayer, or LayerGroup
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
T& getLayerAs();
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const T& getLayerAs() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Attempts to parse the specific node layer type
|
|
||||||
*/
|
|
||||||
virtual void parse(const pugi::xml_node&, Map* = nullptr) = 0;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the name of the layer
|
|
||||||
*/
|
|
||||||
const std::string& getName() const { return m_name; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the opacity value for the layer
|
|
||||||
*/
|
|
||||||
float getOpacity() const { return m_opacity; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns whether this layer is visible or not
|
|
||||||
*/
|
|
||||||
bool getVisible() const { return m_visible; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the offset from the top left corner
|
|
||||||
of the layer, in pixels
|
|
||||||
*/
|
|
||||||
const Vector2i& getOffset() const { return m_offset; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the parallax factor
|
|
||||||
*/
|
|
||||||
const Vector2f& getParallaxFactor() const { return m_parallaxFactor; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the tint colour of the layer.
|
|
||||||
Defaults to 0xFFFFFFFF - pure white
|
|
||||||
*/
|
|
||||||
Colour getTintColour() const { return m_tintColour; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the size of the layer, in pixels.
|
|
||||||
This will be the same as the map size for fixed size maps.
|
|
||||||
*/
|
|
||||||
const Vector2u& getSize() const { return m_size; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the list of properties of this layer
|
|
||||||
*/
|
|
||||||
const std::vector<Property>& getProperties() const { return m_properties; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void setName(const std::string& name) { m_name = name; }
|
|
||||||
void setClass(const std::string& cls) { m_class = cls; }
|
|
||||||
void setOpacity(float opacity) { m_opacity = opacity; }
|
|
||||||
void setVisible(bool visible) { m_visible = visible; }
|
|
||||||
void setOffset(std::int32_t x, std::int32_t y) { m_offset = Vector2i(x, y); }
|
|
||||||
void setParallaxFactor(float x, float y) { m_parallaxFactor.x = x; m_parallaxFactor.y = y; }
|
|
||||||
void setTintColour(Colour c) { m_tintColour = c; }
|
|
||||||
void setSize(std::uint32_t width, std::uint32_t height) { m_size = Vector2u(width, height); }
|
|
||||||
void addProperty(const pugi::xml_node& node) { m_properties.emplace_back(); m_properties.back().parse(node); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_name;
|
|
||||||
std::string m_class;
|
|
||||||
float m_opacity;
|
|
||||||
bool m_visible;
|
|
||||||
Vector2i m_offset;
|
|
||||||
Vector2f m_parallaxFactor;
|
|
||||||
Colour m_tintColour = { 255,255,255,255 };
|
|
||||||
Vector2u m_size;
|
|
||||||
|
|
||||||
std::vector<Property> m_properties;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Grant Gangi 2019 - 2022
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Config.hpp"
|
|
||||||
#include "tmxlite/Layer.hpp"
|
|
||||||
#include "tmxlite/Types.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
\brief Layer groups are used to organize the layers of
|
|
||||||
the map in a hierarchy. They can contain all other layer
|
|
||||||
types including more layer groups to further nest layers.
|
|
||||||
*/
|
|
||||||
class TMXLITE_EXPORT_API LayerGroup final : public Layer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
LayerGroup(const std::string& workDir, const Vector2u& tileCount);
|
|
||||||
~LayerGroup() = default;
|
|
||||||
LayerGroup(const LayerGroup&) = delete;
|
|
||||||
const LayerGroup& operator = (const LayerGroup&) = delete;
|
|
||||||
LayerGroup(LayerGroup&&) = default;
|
|
||||||
LayerGroup& operator = (LayerGroup&&) = default;
|
|
||||||
|
|
||||||
|
|
||||||
Type getType() const override { return Layer::Type::Group; }
|
|
||||||
void parse(const pugi::xml_node&, Map*) override;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a reference to the vector containing the layer data.
|
|
||||||
Layers are pointer-to-baseclass, the concrete type of which can be
|
|
||||||
found via Layer::getType()
|
|
||||||
\see Layer
|
|
||||||
*/
|
|
||||||
const std::vector<Layer::Ptr>& getLayers() const { return m_layers; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::vector<Layer::Ptr> m_layers;
|
|
||||||
|
|
||||||
std::string m_workingDir;
|
|
||||||
Vector2u m_tileCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline LayerGroup& Layer::getLayerAs<LayerGroup>()
|
|
||||||
{
|
|
||||||
assert(getType() == Type::Group);
|
|
||||||
return *static_cast<LayerGroup*>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline const LayerGroup& Layer::getLayerAs<LayerGroup>() const
|
|
||||||
{
|
|
||||||
assert(getType() == Type::Group);
|
|
||||||
return *static_cast<const LayerGroup*>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 -2021
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Tileset.hpp"
|
|
||||||
#include "tmxlite/Layer.hpp"
|
|
||||||
#include "tmxlite/Property.hpp"
|
|
||||||
#include "tmxlite/Types.hpp"
|
|
||||||
#include "tmxlite/Object.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
\brief Holds the xml version of the loaded map
|
|
||||||
*/
|
|
||||||
struct TMXLITE_EXPORT_API Version
|
|
||||||
{
|
|
||||||
//major/minor are apparently reserved by gcc
|
|
||||||
std::uint16_t upper;
|
|
||||||
std::uint16_t lower;
|
|
||||||
Version(std::uint16_t maj = 0, std::uint16_t min = 0)
|
|
||||||
: upper(maj), lower(min) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Orientation
|
|
||||||
{
|
|
||||||
Orthogonal,
|
|
||||||
Isometric,
|
|
||||||
Staggered,
|
|
||||||
Hexagonal,
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class RenderOrder
|
|
||||||
{
|
|
||||||
RightDown,
|
|
||||||
RightUp,
|
|
||||||
LeftDown,
|
|
||||||
LeftUp,
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class StaggerAxis
|
|
||||||
{
|
|
||||||
X, Y, None
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class StaggerIndex
|
|
||||||
{
|
|
||||||
Even, Odd, None
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Parser for TMX format tile maps.
|
|
||||||
This class can be used to parse the XML format tile maps created
|
|
||||||
with the Tiled map editor, providing an interface to create drawable and
|
|
||||||
physics objects. Typical usage would be to create an instance of this
|
|
||||||
class before calling load() providing a path to the *.tmx file to be
|
|
||||||
loaded. Then layers or objects can be requested from the Map class
|
|
||||||
to be interpreted as needed.
|
|
||||||
\see https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#map
|
|
||||||
*/
|
|
||||||
class TMXLITE_EXPORT_API Map final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
Map();
|
|
||||||
~Map() = default;
|
|
||||||
Map(const Map&) = delete;
|
|
||||||
Map& operator = (const Map&) = delete;
|
|
||||||
Map(Map&&) = default;
|
|
||||||
Map& operator = (Map&&) = default;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Attempts to parse the tilemap at the given location.
|
|
||||||
\param std::string Path to map file to try to parse
|
|
||||||
\returns true if map was parsed successfully else returns false.
|
|
||||||
In debug mode this will attempt to log any errors to the console.
|
|
||||||
*/
|
|
||||||
bool load(const std::string&);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Loads a map from a document stored in a string
|
|
||||||
\param data A std::string containing the map data to load
|
|
||||||
\param workingDir A std::string containing the working directory
|
|
||||||
in which to find assets such as tile sets or images
|
|
||||||
\returns true if successful, else false
|
|
||||||
*/
|
|
||||||
bool loadFromString(const std::string& data, const std::string& workingDir);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the version of the tile map last parsed.
|
|
||||||
If no tile map has yet been parsed the version will read 0, 0
|
|
||||||
*/
|
|
||||||
const Version& getVersion() const { return m_version; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the orientation of the map if one is loaded,
|
|
||||||
else returns None
|
|
||||||
*/
|
|
||||||
Orientation getOrientation() const { return m_orientation; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the RenderOrder of the map if one is loaded,
|
|
||||||
else returns None
|
|
||||||
*/
|
|
||||||
RenderOrder getRenderOrder() const { return m_renderOrder; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the tile count of the map in the X and Y directions
|
|
||||||
*/
|
|
||||||
const Vector2u& getTileCount() const { return m_tileCount; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the size of the tile grid in this map.
|
|
||||||
Actual tile sizes may vary and will be extended / shrunk about
|
|
||||||
the bottom left corner of the tile.
|
|
||||||
*/
|
|
||||||
const Vector2u& getTileSize() const { return m_tileSize; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the bounds of the map
|
|
||||||
*/
|
|
||||||
FloatRect getBounds() const { return FloatRect(0.f, 0.f, static_cast<float>(m_tileCount.x * m_tileSize.x), static_cast<float>(m_tileCount.y * m_tileSize.y)); }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the length of an edge of a tile if a Hexagonal
|
|
||||||
map is loaded.
|
|
||||||
The length returned is in pixels of the straight edge running
|
|
||||||
along the axis returned by getStaggerAxis(). If no map is loaded
|
|
||||||
or the loaded map is not of Hexagonal orientation this function
|
|
||||||
returns 0.f
|
|
||||||
*/
|
|
||||||
float getHexSideLength() const { return m_hexSideLength; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Stagger axis of the map.
|
|
||||||
If either a Staggered or Hexagonal tile map is loaded this returns
|
|
||||||
which axis the map is staggered along, else returns None.
|
|
||||||
*/
|
|
||||||
StaggerAxis getStaggerAxis() const { return m_staggerAxis; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Stagger Index of the loaded map.
|
|
||||||
If a Staggered or Hexagonal map is loaded this returns whether
|
|
||||||
the even or odd rows of tiles are staggered, otherwise it returns None.
|
|
||||||
*/
|
|
||||||
StaggerIndex getStaggerIndex() const { return m_staggerIndex; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the background colour of the map.
|
|
||||||
*/
|
|
||||||
const Colour& getBackgroundColour() const { return m_backgroundColour; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a reference to the vector of tile sets used by the map
|
|
||||||
*/
|
|
||||||
const std::vector<Tileset>& getTilesets() const { return m_tilesets; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a reference to the vector containing the layer data.
|
|
||||||
Layers are pointer-to-baseclass, the concrete type of which can be
|
|
||||||
found via Layer::getType()
|
|
||||||
\see Layer
|
|
||||||
*/
|
|
||||||
const std::vector<Layer::Ptr>& getLayers() const { return m_layers; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the class of the Map, as defined in the editor Tiled 1.9+
|
|
||||||
*/
|
|
||||||
const std::string& getClass() const { return m_class; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a vector of Property objects loaded by the map
|
|
||||||
*/
|
|
||||||
const std::vector<Property>& getProperties() const { return m_properties; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a Hashmap of all animated tiles accessible by TileID
|
|
||||||
*/
|
|
||||||
const std::map<std::uint32_t, Tileset::Tile>& getAnimatedTiles() const { return m_animTiles; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the current working directory of the map. Images and
|
|
||||||
other resources are loaded relative to this.
|
|
||||||
*/
|
|
||||||
const std::string& getWorkingDirectory() const { return m_workingDirectory; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns an unordered_map of template objects indexed by file name
|
|
||||||
*/
|
|
||||||
std::unordered_map<std::string, Object>& getTemplateObjects() { return m_templateObjects; }
|
|
||||||
const std::unordered_map<std::string, Object>& getTemplateObjects() const { return m_templateObjects; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns an unordered_map of tilesets used by templated objects.
|
|
||||||
If Object::getTilesetName() is not empty it can be used to retreive a tileset
|
|
||||||
from this map. Otherwise the object's tileset can be found from in the map's
|
|
||||||
global tilesets returned by getTilesets().
|
|
||||||
*/
|
|
||||||
std::unordered_map<std::string, Tileset>& getTemplateTilesets() { return m_templateTilesets; }
|
|
||||||
const std::unordered_map<std::string, Tileset>& getTemplateTilesets() const { return m_templateTilesets; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns true if this is in infinite tile map.
|
|
||||||
Infinite maps store their tile data in for tile layers in chunks. If
|
|
||||||
this is an infinite map use TileLayer::getChunks() to get tile IDs
|
|
||||||
rather than TileLayer::getTiles().
|
|
||||||
\see TileLayer
|
|
||||||
*/
|
|
||||||
bool isInfinite() const { return m_infinite; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
\brief Returns the origin of each layer's parallax offset value
|
|
||||||
*/
|
|
||||||
Vector2f getParallaxOrigin() const { return m_parallaxOrigin; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Version m_version;
|
|
||||||
std::string m_class;
|
|
||||||
Orientation m_orientation;
|
|
||||||
RenderOrder m_renderOrder;
|
|
||||||
bool m_infinite;
|
|
||||||
|
|
||||||
Vector2u m_tileCount;
|
|
||||||
Vector2u m_tileSize;
|
|
||||||
|
|
||||||
float m_hexSideLength;
|
|
||||||
StaggerAxis m_staggerAxis;
|
|
||||||
StaggerIndex m_staggerIndex;
|
|
||||||
|
|
||||||
Vector2f m_parallaxOrigin;
|
|
||||||
|
|
||||||
Colour m_backgroundColour;
|
|
||||||
|
|
||||||
std::string m_workingDirectory;
|
|
||||||
|
|
||||||
std::vector<Tileset> m_tilesets;
|
|
||||||
std::vector<Layer::Ptr> m_layers;
|
|
||||||
std::vector<Property> m_properties;
|
|
||||||
std::map<std::uint32_t, Tileset::Tile> m_animTiles;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, Object> m_templateObjects;
|
|
||||||
std::unordered_map<std::string, Tileset> m_templateTilesets;
|
|
||||||
|
|
||||||
bool parseMapNode(const pugi::xml_node&);
|
|
||||||
|
|
||||||
//always returns false so we can return this
|
|
||||||
//on load failure
|
|
||||||
bool reset();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,221 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
(c) Matt Marchant 2016 - 2021
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Config.hpp"
|
|
||||||
#include "tmxlite/Property.hpp"
|
|
||||||
#include "tmxlite/Types.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace pugi
|
|
||||||
{
|
|
||||||
class xml_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
class Map;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Contains the text information stored in a Text object.
|
|
||||||
*/
|
|
||||||
struct TMXLITE_EXPORT_API Text final
|
|
||||||
{
|
|
||||||
std::string fontFamily;
|
|
||||||
std::uint32_t pixelSize = 16; //!< pixels, not points
|
|
||||||
bool wrap = false;
|
|
||||||
Colour colour;
|
|
||||||
bool bold = false;
|
|
||||||
bool italic = false;
|
|
||||||
bool underline = false;
|
|
||||||
bool strikethough = false;
|
|
||||||
bool kerning = true;
|
|
||||||
|
|
||||||
enum class HAlign
|
|
||||||
{
|
|
||||||
Left, Centre, Right
|
|
||||||
}hAlign = HAlign::Left;
|
|
||||||
|
|
||||||
enum class VAlign
|
|
||||||
{
|
|
||||||
Top, Centre, Bottom
|
|
||||||
}vAlign = VAlign::Top;
|
|
||||||
|
|
||||||
std::string content; //!< actual string content
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Objects are stored in ObjectGroup layers.
|
|
||||||
Objects may be rectangular, elliptical, polygonal or
|
|
||||||
a polyline. Rectangular and elliptical Objects have their
|
|
||||||
size determined via the AABB, whereas polygon and polyline
|
|
||||||
shapes are defined by a list of points. Objects are
|
|
||||||
rectangular by default. Since version 1.0 Objects also
|
|
||||||
support Text nodes.
|
|
||||||
*/
|
|
||||||
class TMXLITE_EXPORT_API Object final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class Shape
|
|
||||||
{
|
|
||||||
Rectangle,
|
|
||||||
Ellipse,
|
|
||||||
Point,
|
|
||||||
Polygon,
|
|
||||||
Polyline,
|
|
||||||
Text
|
|
||||||
};
|
|
||||||
|
|
||||||
Object();
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Attempts to parse the given xml node and
|
|
||||||
read the Object properties if it is valid.
|
|
||||||
*/
|
|
||||||
void parse(const pugi::xml_node&, Map*);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the unique ID of the Object
|
|
||||||
*/
|
|
||||||
std::uint32_t getUID() const { return m_UID; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the name of the Object
|
|
||||||
*/
|
|
||||||
const std::string& getName() const { return m_name; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the type (equal to class) of the Object, as defined in the editor Tiled < 1.9
|
|
||||||
*/
|
|
||||||
const std::string& getType() const { return m_class; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the class (equal to type) of the Object, as defined in the editor Tiled 1.9+
|
|
||||||
*/
|
|
||||||
const std::string& getClass() const { return m_class; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the position of the Object in pixels
|
|
||||||
*/
|
|
||||||
const Vector2f& getPosition() const { return m_position; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the global Axis Aligned Bounding Box.
|
|
||||||
The AABB is positioned via the left and top properties, and
|
|
||||||
define the Object's width and height. This can be used to derive
|
|
||||||
the shape of the Object if it is rectangular or elliptical.
|
|
||||||
*/
|
|
||||||
const FloatRect& getAABB() const { return m_AABB; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the rotation of the Object in degrees clockwise
|
|
||||||
*/
|
|
||||||
float getRotation() const { return m_rotation; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the global tile ID associated with the Object
|
|
||||||
if there is one. This is used to draw the Object (and therefore
|
|
||||||
the Object must be rectangular)
|
|
||||||
*/
|
|
||||||
std::uint32_t getTileID() const { return m_tileID; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the flip flags if the objects uses a TileID to
|
|
||||||
draw it.
|
|
||||||
Returns 0 otherwise.
|
|
||||||
*/
|
|
||||||
std::uint8_t getFlipFlags() const { return m_flipFlags; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns whether or not the Object is visible
|
|
||||||
*/
|
|
||||||
bool visible() const { return m_visible; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the Shape type of the Object
|
|
||||||
*/
|
|
||||||
Shape getShape() const { return m_shape; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a reference to the vector of points which
|
|
||||||
make up the Object. If the Object is rectangular or elliptical
|
|
||||||
then the vector will be empty. Point coordinates are in pixels,
|
|
||||||
relative to the object position.
|
|
||||||
*/
|
|
||||||
const std::vector<Vector2f>& getPoints() const { return m_points; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a reference to the vector of properties belonging to
|
|
||||||
the Object.
|
|
||||||
*/
|
|
||||||
const std::vector<Property>& getProperties() const { return m_properties; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a Text struct containing information about any text
|
|
||||||
this object may have, such as font data and formatting.
|
|
||||||
If an object does not contain any text information this struct will
|
|
||||||
be populated with default values. Use getShape() to determine
|
|
||||||
if this object is in fact a text object.
|
|
||||||
*/
|
|
||||||
const Text& getText() const { return m_textData; }
|
|
||||||
Text& getText() { return m_textData; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the tileset name used by this object if it is derived
|
|
||||||
from a template, else returns an empty string.
|
|
||||||
If the string is not empty use it to index the unordered_map returned
|
|
||||||
by Map::getTemplateTilesets()
|
|
||||||
*/
|
|
||||||
const std::string& getTilesetName() const { return m_tilesetName; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::uint32_t m_UID;
|
|
||||||
std::string m_name;
|
|
||||||
std::string m_class;
|
|
||||||
Vector2f m_position;
|
|
||||||
FloatRect m_AABB;
|
|
||||||
float m_rotation;
|
|
||||||
std::uint32_t m_tileID;
|
|
||||||
std::uint8_t m_flipFlags;
|
|
||||||
bool m_visible;
|
|
||||||
|
|
||||||
Shape m_shape;
|
|
||||||
std::vector<Vector2f> m_points;
|
|
||||||
std::vector<Property> m_properties;
|
|
||||||
|
|
||||||
Text m_textData;
|
|
||||||
|
|
||||||
std::string m_tilesetName;
|
|
||||||
|
|
||||||
void parsePoints(const pugi::xml_node&);
|
|
||||||
void parseText(const pugi::xml_node&);
|
|
||||||
void parseTemplate(const std::string&, Map*);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2022
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Config.hpp"
|
|
||||||
#include "tmxlite/Layer.hpp"
|
|
||||||
#include "tmxlite/Object.hpp"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
\brief ObjectGroup layers contain a series of Objects
|
|
||||||
which may be made up of shapes or images.
|
|
||||||
*/
|
|
||||||
class TMXLITE_EXPORT_API ObjectGroup final : public Layer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class DrawOrder
|
|
||||||
{
|
|
||||||
Index, //< objects should be drawn in the order in which they appear
|
|
||||||
TopDown //< objects should be drawn sorted by their Y position
|
|
||||||
};
|
|
||||||
|
|
||||||
ObjectGroup();
|
|
||||||
|
|
||||||
Type getType() const override { return Layer::Type::Object; }
|
|
||||||
void parse(const pugi::xml_node&, Map*) override;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the colour associated with this layer
|
|
||||||
*/
|
|
||||||
const Colour& getColour() const { return m_colour; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the DrawOrder for the objects in this group.
|
|
||||||
Defaults to TopDown, where Objects are drawn sorted by Y position
|
|
||||||
*/
|
|
||||||
DrawOrder getDrawOrder() const { return m_drawOrder; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a reference to the vector of properties for
|
|
||||||
the ObjectGroup
|
|
||||||
*/
|
|
||||||
const std::vector<Property>& getProperties() const { return m_properties; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a reference to the vector of Objects which belong to the group
|
|
||||||
*/
|
|
||||||
const std::vector<Object>& getObjects() const { return m_objects; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Colour m_colour;
|
|
||||||
DrawOrder m_drawOrder;
|
|
||||||
|
|
||||||
std::vector<Property> m_properties;
|
|
||||||
std::vector<Object> m_objects;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline ObjectGroup& Layer::getLayerAs<ObjectGroup>()
|
|
||||||
{
|
|
||||||
assert(getType() == Type::Object);
|
|
||||||
return *static_cast<ObjectGroup*>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline const ObjectGroup& Layer::getLayerAs<ObjectGroup>() const
|
|
||||||
{
|
|
||||||
assert(getType() == Type::Object);
|
|
||||||
return *static_cast<const ObjectGroup*>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Raphaël Frantz 2021
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Property.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
\brief Parser for Tiled object types export format.
|
|
||||||
Link to the specification: https://doc.mapeditor.org/fr/latest/manual/custom-properties/#predefining-properties.
|
|
||||||
*/
|
|
||||||
class TMXLITE_EXPORT_API ObjectTypes final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/*!
|
|
||||||
\brief Types that stores all predefined properties for all objects of this type.
|
|
||||||
To take less spaces, they are not exported by default into maps.
|
|
||||||
*/
|
|
||||||
struct Type
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
Colour colour;
|
|
||||||
std::vector<Property> properties;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Attempts to parse the object types at the given location.
|
|
||||||
\param std::string Path to object types file to try to parse
|
|
||||||
\returns true if object types was parsed successfully else returns false.
|
|
||||||
In debug mode this will attempt to log any errors to the console.
|
|
||||||
*/
|
|
||||||
bool load(const std::string&);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Loads an object types from a document stored in a string
|
|
||||||
\param data A std::string containing the object types to load
|
|
||||||
\param workingDir A std::string containing the working directory
|
|
||||||
in which to find files.
|
|
||||||
\returns true if successful, else false
|
|
||||||
*/
|
|
||||||
bool loadFromString(const std::string& data, const std::string& workingDir);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns all predefined types and their default values.
|
|
||||||
*/
|
|
||||||
const std::vector<Type>& getTypes() const { return m_types; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_workingDirectory;
|
|
||||||
std::vector<Type> m_types;
|
|
||||||
|
|
||||||
bool parseObjectTypesNode(const pugi::xml_node&);
|
|
||||||
|
|
||||||
//always returns false so we can return this
|
|
||||||
//on load failure
|
|
||||||
bool reset();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2021
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Config.hpp"
|
|
||||||
#include "tmxlite/Types.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace pugi
|
|
||||||
{
|
|
||||||
class xml_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
\brief Represents a custom property.
|
|
||||||
Tiles, objects and layers of a tmx map may have custom
|
|
||||||
properties assigned to them. This class represents a
|
|
||||||
single property and provides access to its value, the
|
|
||||||
type of which can be determined with getType()
|
|
||||||
*/
|
|
||||||
class TMXLITE_EXPORT_API Property final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
Boolean,
|
|
||||||
Float,
|
|
||||||
Int,
|
|
||||||
String,
|
|
||||||
Colour,
|
|
||||||
File,
|
|
||||||
Object,
|
|
||||||
Undef
|
|
||||||
};
|
|
||||||
|
|
||||||
Property();
|
|
||||||
|
|
||||||
static Property fromBoolean(bool value);
|
|
||||||
static Property fromFloat(float value);
|
|
||||||
static Property fromInt(int value);
|
|
||||||
static Property fromString(const std::string& value);
|
|
||||||
static Property fromColour(const Colour& value);
|
|
||||||
static Property fromFile(const std::string& value);
|
|
||||||
static Property fromObject(int value);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Attempts to parse the given node as a property
|
|
||||||
\param isObjectTypes Set to true if the parsing is done from an object types files.
|
|
||||||
*/
|
|
||||||
void parse(const pugi::xml_node&, bool isObjectTypes = false);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the type of data stored in the property.
|
|
||||||
This should generally be called first before trying to
|
|
||||||
read the proprty value, as reading the incorrect type
|
|
||||||
will lead to undefined behaviour.
|
|
||||||
*/
|
|
||||||
Type getType() const { return m_type; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the name of this property
|
|
||||||
*/
|
|
||||||
const std::string& getName() const { return m_name; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the property's value as a boolean
|
|
||||||
*/
|
|
||||||
bool getBoolValue() const { assert(m_type == Type::Boolean); return m_boolValue; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the property's value as a float
|
|
||||||
*/
|
|
||||||
float getFloatValue() const { assert(m_type == Type::Float); return m_floatValue; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the property's value as an integer
|
|
||||||
*/
|
|
||||||
int getIntValue() const { assert(m_type == Type::Int || m_type == Type::Object); return m_intValue; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the property's value as a string
|
|
||||||
*/
|
|
||||||
const std::string& getStringValue() const { assert(m_type == Type::String); return m_stringValue; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the property's value as a Colour struct
|
|
||||||
*/
|
|
||||||
const Colour& getColourValue() const { assert(m_type == Type::Colour); return m_colourValue; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the file path property as a string, relative to the map file
|
|
||||||
*/
|
|
||||||
const std::string& getFileValue() const { assert(m_type == Type::File); return m_stringValue; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the property's value as an integer object handle
|
|
||||||
*/
|
|
||||||
int getObjectValue() const { assert(m_type == Type::Object); return m_intValue; }
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
union
|
|
||||||
{
|
|
||||||
bool m_boolValue;
|
|
||||||
float m_floatValue;
|
|
||||||
int m_intValue;
|
|
||||||
};
|
|
||||||
std::string m_stringValue;
|
|
||||||
std::string m_name;
|
|
||||||
Colour m_colourValue;
|
|
||||||
|
|
||||||
Type m_type;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2022
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Layer.hpp"
|
|
||||||
#include "tmxlite/Types.hpp"
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
\brief A layer made up from a series of tile sets
|
|
||||||
*/
|
|
||||||
class TMXLITE_EXPORT_API TileLayer final : public Layer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/*!
|
|
||||||
\brief Tile information for a layer
|
|
||||||
*/
|
|
||||||
struct Tile final
|
|
||||||
{
|
|
||||||
std::uint32_t ID = 0; //!< Global ID of the tile
|
|
||||||
std::uint8_t flipFlags = 0; //!< Flags marking if the tile should be flipped when drawn
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Represents a chunk of tile data, if this is an infinite map
|
|
||||||
*/
|
|
||||||
struct Chunk final
|
|
||||||
{
|
|
||||||
Vector2i position; //<! coordinate in tiles, not pixels
|
|
||||||
Vector2i size; //!< size in tiles, not pixels
|
|
||||||
std::vector<Tile> tiles;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Flags used to tell if a tile is flipped when drawn
|
|
||||||
*/
|
|
||||||
enum FlipFlag
|
|
||||||
{
|
|
||||||
Horizontal = 0x8,
|
|
||||||
Vertical = 0x4,
|
|
||||||
Diagonal = 0x2
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit TileLayer(std::size_t);
|
|
||||||
|
|
||||||
Type getType() const override { return Layer::Type::Tile; }
|
|
||||||
void parse(const pugi::xml_node&, Map*) override;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the list of tiles used to make up the layer
|
|
||||||
If this is empty then the map is most likely infinite, in
|
|
||||||
which case the tile data is stored in chunks.
|
|
||||||
\see getChunks()
|
|
||||||
*/
|
|
||||||
const std::vector<Tile>& getTiles() const { return m_tiles; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a vector of chunks which make up this layer
|
|
||||||
if the map is set to infinite. This will be empty if the map
|
|
||||||
is not infinite.
|
|
||||||
\see getTiles()
|
|
||||||
*/
|
|
||||||
const std::vector<Chunk>& getChunks() const { return m_chunks; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Tile> m_tiles;
|
|
||||||
std::vector<Chunk> m_chunks;
|
|
||||||
std::size_t m_tileCount;
|
|
||||||
|
|
||||||
void parseBase64(const pugi::xml_node&);
|
|
||||||
void parseCSV(const pugi::xml_node&);
|
|
||||||
void parseUnencoded(const pugi::xml_node&);
|
|
||||||
|
|
||||||
void createTiles(const std::vector<std::uint32_t>&, std::vector<Tile>& destination);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline TileLayer& Layer::getLayerAs<TileLayer>()
|
|
||||||
{
|
|
||||||
assert(getType() == Type::Tile);
|
|
||||||
return *static_cast<TileLayer*>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline const TileLayer& Layer::getLayerAs<TileLayer>() const
|
|
||||||
{
|
|
||||||
assert(getType() == Type::Tile);
|
|
||||||
return *static_cast<const TileLayer*>(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,296 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2023
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Config.hpp"
|
|
||||||
#include "tmxlite/Property.hpp"
|
|
||||||
#include "tmxlite/ObjectGroup.hpp"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
namespace pugi
|
|
||||||
{
|
|
||||||
class xml_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
class Map;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Represents a Tileset node as loaded
|
|
||||||
from a *.tmx format tile map via the tmx::Map
|
|
||||||
class.
|
|
||||||
*/
|
|
||||||
class TMXLITE_EXPORT_API Tileset final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Tileset(const std::string& workingDir);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Any tiles within a tile set which have special
|
|
||||||
data associated with them such as animation or terrain
|
|
||||||
information will have one of these stored in the tile set.
|
|
||||||
*/
|
|
||||||
struct Tile final
|
|
||||||
{
|
|
||||||
std::uint32_t ID = 0;
|
|
||||||
std::array<std::int32_t, 4u> terrainIndices{};
|
|
||||||
std::uint32_t probability = 100;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief a group of frames which make up an animation
|
|
||||||
*/
|
|
||||||
struct Animation final
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
\brief A frame within an animation
|
|
||||||
*/
|
|
||||||
struct Frame final
|
|
||||||
{
|
|
||||||
std::uint32_t tileID = 0;
|
|
||||||
std::uint32_t duration = 0;
|
|
||||||
|
|
||||||
bool operator == (const Frame& other) const
|
|
||||||
{
|
|
||||||
return (this == &other) ||
|
|
||||||
(tileID == other.tileID && duration == other.duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator != (const Frame& other) const
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
std::vector<Frame> frames;
|
|
||||||
}animation;
|
|
||||||
std::vector<Property> properties;
|
|
||||||
ObjectGroup objectGroup;
|
|
||||||
std::string imagePath;
|
|
||||||
Vector2u imageSize;
|
|
||||||
/*!
|
|
||||||
\brief The position of the tile within the image.
|
|
||||||
*/
|
|
||||||
Vector2u imagePosition;
|
|
||||||
std::string className;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Terrain information with which one
|
|
||||||
or more tiles may be associated.
|
|
||||||
*/
|
|
||||||
struct Terrain final
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::uint32_t tileID = -1;
|
|
||||||
std::vector<Property> properties;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Declares the alignment of tile Objects
|
|
||||||
*/
|
|
||||||
enum class ObjectAlignment
|
|
||||||
{
|
|
||||||
Unspecified,
|
|
||||||
TopLeft,
|
|
||||||
Top,
|
|
||||||
TopRight,
|
|
||||||
Left,
|
|
||||||
Center,
|
|
||||||
Right,
|
|
||||||
BottomLeft,
|
|
||||||
Bottom,
|
|
||||||
BottomRight
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Attempts to parse the given xml node.
|
|
||||||
If node parsing fails an error is printed in the console
|
|
||||||
and the Tileset remains in an uninitialised state.
|
|
||||||
*/
|
|
||||||
void parse(pugi::xml_node, Map*);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the first GID of this tile set.
|
|
||||||
This the ID of the first tile in the tile set, so that
|
|
||||||
each tile set guarantees a unique set of IDs
|
|
||||||
*/
|
|
||||||
std::uint32_t getFirstGID() const { return m_firstGID; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the last GID of this tile set.
|
|
||||||
This is the ID of the last tile in the tile set.
|
|
||||||
*/
|
|
||||||
std::uint32_t getLastGID() const;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the name of this tile set.
|
|
||||||
*/
|
|
||||||
const std::string& getName() const { return m_name; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the class of the Tileset, as defined in the editor Tiled 1.9+
|
|
||||||
*/
|
|
||||||
const std::string& getClass() const { return m_class; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the width and height of a tile in the
|
|
||||||
tile set, in pixels.
|
|
||||||
*/
|
|
||||||
const Vector2u& getTileSize() const { return m_tileSize; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the spacing, in pixels, between each tile in the set
|
|
||||||
*/
|
|
||||||
std::uint32_t getSpacing() const { return m_spacing; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the margin, in pixels, around each tile in the set
|
|
||||||
*/
|
|
||||||
std::uint32_t getMargin() const { return m_margin; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the number of tiles in the tile set
|
|
||||||
*/
|
|
||||||
std::uint32_t getTileCount() const { return m_tileCount; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the number of columns which make up the tile set.
|
|
||||||
This is used when rendering collection of images sets
|
|
||||||
*/
|
|
||||||
std::uint32_t getColumnCount() const { return m_columnCount; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the alignment of tile objects.
|
|
||||||
The default value is ObjectAlignment::Unspecified for compatibility.
|
|
||||||
When the alignment is Unspecified tile objects use BottomLeft in
|
|
||||||
orthogonal mode and Bottom in isometric mode.
|
|
||||||
\see ObjectAlignment
|
|
||||||
*/
|
|
||||||
ObjectAlignment getObjectAlignment() const { return m_objectAlignment; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the tile offset in pixels.
|
|
||||||
Tile will draw tiles offset from the top left using this value.
|
|
||||||
*/
|
|
||||||
const Vector2u& getTileOffset() const { return m_tileOffset; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a reference to the list of Property objects for this
|
|
||||||
tile set
|
|
||||||
*/
|
|
||||||
const std::vector<Property>& getProperties() const { return m_properties; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the file path to the tile set image, relative to the
|
|
||||||
working directory. Use this to load the texture required by whichever
|
|
||||||
method you choose to render the map.
|
|
||||||
*/
|
|
||||||
const std::string& getImagePath() const { return m_imagePath; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the size of the tile set image in pixels.
|
|
||||||
*/
|
|
||||||
const Vector2u& getImageSize() const { return m_imageSize; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns the colour used by the tile map image to represent transparency.
|
|
||||||
By default this is a transparent colour (0, 0, 0, 0)
|
|
||||||
*/
|
|
||||||
const Colour& getTransparencyColour() const { return m_transparencyColour; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns true if the image used by this tileset specifically requests
|
|
||||||
a colour to use as transparency.
|
|
||||||
*/
|
|
||||||
bool hasTransparency() const { return m_hasTransparency; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a vector of Terrain types associated with one
|
|
||||||
or more tiles within this tile set
|
|
||||||
*/
|
|
||||||
const std::vector<Terrain>& getTerrainTypes() const { return m_terrainTypes; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Returns a reference to the vector of tile data used by
|
|
||||||
tiles which make up this tile set.
|
|
||||||
*/
|
|
||||||
const std::vector<Tile>& getTiles() const { return m_tiles; }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Checks if a tiled ID is in the range of the first ID and the last ID
|
|
||||||
\param id Tile ID
|
|
||||||
\return
|
|
||||||
*/
|
|
||||||
bool hasTile(std::uint32_t id) const { return id >= m_firstGID && id <= getLastGID(); };
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief queries tiles and returns a tile with the given ID. Checks if the TileID is part of the Tileset with `hasTile(id)`
|
|
||||||
\param id Tile ID. The Tile ID will be corrected internally.
|
|
||||||
\return In case of a success it returns the correct tile. In terms of failure it will return a nullptr.
|
|
||||||
*/
|
|
||||||
const Tile* getTile(std::uint32_t id) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::string m_workingDir;
|
|
||||||
|
|
||||||
std::uint32_t m_firstGID;
|
|
||||||
std::string m_source;
|
|
||||||
std::string m_name;
|
|
||||||
std::string m_class;
|
|
||||||
Vector2u m_tileSize;
|
|
||||||
std::uint32_t m_spacing;
|
|
||||||
std::uint32_t m_margin;
|
|
||||||
std::uint32_t m_tileCount;
|
|
||||||
std::uint32_t m_columnCount;
|
|
||||||
ObjectAlignment m_objectAlignment;
|
|
||||||
Vector2u m_tileOffset;
|
|
||||||
|
|
||||||
std::vector<Property> m_properties;
|
|
||||||
std::string m_imagePath;
|
|
||||||
Vector2u m_imageSize;
|
|
||||||
Colour m_transparencyColour;
|
|
||||||
bool m_hasTransparency;
|
|
||||||
|
|
||||||
std::vector<Terrain> m_terrainTypes;
|
|
||||||
std::vector<std::uint32_t> m_tileIndex;
|
|
||||||
std::vector<Tile> m_tiles;
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
void parseOffsetNode(const pugi::xml_node&);
|
|
||||||
void parsePropertyNode(const pugi::xml_node&);
|
|
||||||
void parseTerrainNode(const pugi::xml_node&);
|
|
||||||
Tile& newTile(std::uint32_t ID);
|
|
||||||
void parseTileNode(const pugi::xml_node&, Map*);
|
|
||||||
void createMissingTile(std::uint32_t ID);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2023
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tmxlite/Config.hpp"
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
\brief Two dimensional vector used to store points and positions
|
|
||||||
*/
|
|
||||||
template <class T>
|
|
||||||
struct Vector2 final
|
|
||||||
{
|
|
||||||
Vector2() : x(0), y(0) {}
|
|
||||||
Vector2(T x, T y) :x(x), y(y) {}
|
|
||||||
T x, y;
|
|
||||||
};
|
|
||||||
|
|
||||||
using Vector2f = Vector2<float>;
|
|
||||||
using Vector2i = Vector2<int>;
|
|
||||||
using Vector2u = Vector2<unsigned>;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator + (const Vector2<T>& l, const Vector2<T>& r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator += (Vector2<T>& l, const Vector2<T>& r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator - (const Vector2<T>& l, const Vector2<T>& r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator -= (Vector2<T>& l, const Vector2<T>& r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator * (const Vector2<T>& l, const Vector2<T>& r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator *= (Vector2<T>& l, const Vector2<T>& r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator * (const Vector2<T>& l, T r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator *= (Vector2<T>& l, T r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator / (const Vector2<T>& l, const Vector2<T>& r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator /= (Vector2<T>& l, const Vector2<T>& r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator / (const Vector2<T>& l, T r);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator /= (Vector2<T>& l, T r);
|
|
||||||
|
|
||||||
#include "Types.inl"
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Describes a rectangular area, such as an AABB (axis aligned bounding box)
|
|
||||||
*/
|
|
||||||
template <class T>
|
|
||||||
struct Rectangle final
|
|
||||||
{
|
|
||||||
Rectangle() : left(0), top(0), width(0), height(0) {}
|
|
||||||
Rectangle(T l, T t, T w, T h) : left(l), top(t), width(w), height(h) {}
|
|
||||||
Rectangle(Vector2<T> position, Vector2<T> size) : left(position.x), top(position.y), width(size.x), height(size.y) {}
|
|
||||||
T left, top, width, height;
|
|
||||||
};
|
|
||||||
|
|
||||||
using FloatRect = Rectangle<float>;
|
|
||||||
using IntRect = Rectangle<int>;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief Contains the red, green, blue and alpha values of a colour
|
|
||||||
in the range 0 - 255.
|
|
||||||
*/
|
|
||||||
struct TMXLITE_EXPORT_API Colour final
|
|
||||||
{
|
|
||||||
Colour(std::uint8_t red = 0, std::uint8_t green = 0, std::uint8_t blue = 0, std::uint8_t alpha = 255)
|
|
||||||
: r(red), g(green), b(blue), a(alpha) {}
|
|
||||||
std::uint8_t r, g, b, a;
|
|
||||||
|
|
||||||
bool operator == (const Colour& other)
|
|
||||||
{
|
|
||||||
return other.r == r
|
|
||||||
&& other.g == g
|
|
||||||
&& other.b == b
|
|
||||||
&& other.a == a;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator != (const Colour& other)
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit operator std::uint32_t() const
|
|
||||||
{
|
|
||||||
return (r << 24) | (g << 16) | (b << 8) | a;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
std::ostream& operator << (std::ostream& os, const tmx::Vector2<T>& t)
|
|
||||||
{
|
|
||||||
os << "{" << t.x << ", " << t.y << "}";
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
std::ostream& operator << (std::ostream& os, const tmx::Rectangle<T>& t)
|
|
||||||
{
|
|
||||||
os << "{" << t.left << ", " << t.top << ", " << t.width << ", " << t.height << "}";
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator << (std::ostream& os, const tmx::Colour& c);
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2023
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator + (const Vector2<T>& l, const Vector2<T>& r)
|
|
||||||
{
|
|
||||||
return { l.x + r.x, l.y + r.y };
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator += (Vector2<T>& l, const Vector2<T>& r)
|
|
||||||
{
|
|
||||||
l.x += r.x;
|
|
||||||
l.y += r.y;
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator - (const Vector2<T>& l, const Vector2<T>& r)
|
|
||||||
{
|
|
||||||
return { l.x - r.x, l.y - r.y };
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator -= (Vector2<T>& l, const Vector2<T>& r)
|
|
||||||
{
|
|
||||||
l.x -= r.x;
|
|
||||||
l.y -= r.y;
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator * (const Vector2<T>& l, const Vector2<T>& r)
|
|
||||||
{
|
|
||||||
return { l.x * r.x, l.y * r.y };
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator *= (Vector2<T>& l, const Vector2<T>& r)
|
|
||||||
{
|
|
||||||
l.x *= r.x;
|
|
||||||
l.y *= r.y;
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator * (const Vector2<T>& l, T r)
|
|
||||||
{
|
|
||||||
return { l.x * r, l.y * r };
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator *= (Vector2<T>& l, T r)
|
|
||||||
{
|
|
||||||
l.x *= r;
|
|
||||||
l.y *= r;
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator / (const Vector2<T>& l, const Vector2<T>& r)
|
|
||||||
{
|
|
||||||
return { l.x / r.x, l.y / r.y };
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator /= (Vector2<T>& l, const Vector2<T>& r)
|
|
||||||
{
|
|
||||||
l.x /= r.x;
|
|
||||||
l.y /= r.y;
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T> operator / (const Vector2<T>& l, T r)
|
|
||||||
{
|
|
||||||
return { l.x / r, l.y / r };
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Vector2<T>& operator /= (Vector2<T>& l, T r)
|
|
||||||
{
|
|
||||||
l.x /= r;
|
|
||||||
l.y /= r;
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2021
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
//flexible logging class, based on code at https://github.com/fallahn/xygine
|
|
||||||
|
|
||||||
#ifndef TMXLITE_LOGGER_HPP_
|
|
||||||
#define TMXLITE_LOGGER_HPP_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <list>
|
|
||||||
#include <ctime>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define NOMINMAX
|
|
||||||
#include <windows.h>
|
|
||||||
#endif //_MSC_VER
|
|
||||||
|
|
||||||
namespace tmx
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
\brief Class allowing messages to be logged to a combination
|
|
||||||
of one or more destinations such as the console, log file or
|
|
||||||
output window in Visual Studio
|
|
||||||
*/
|
|
||||||
class Logger final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class Output
|
|
||||||
{
|
|
||||||
Console,
|
|
||||||
File,
|
|
||||||
All
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
Info,
|
|
||||||
Warning,
|
|
||||||
Error
|
|
||||||
};
|
|
||||||
/*!
|
|
||||||
\brief Logs a message to a given destination.
|
|
||||||
\param message Message to log
|
|
||||||
\param type Whether this message gets tagged as information, a warning or an error
|
|
||||||
\param output Destination for the message. Can be the console via cout, a log file on disk, or both
|
|
||||||
*/
|
|
||||||
static void log(const std::string& message, Type type = Type::Info, Output output = Output::Console)
|
|
||||||
{
|
|
||||||
std::string outstring;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case Type::Info:
|
|
||||||
default:
|
|
||||||
outstring = "INFO: " + message;
|
|
||||||
break;
|
|
||||||
case Type::Error:
|
|
||||||
outstring = "ERROR: " + message;
|
|
||||||
break;
|
|
||||||
case Type::Warning:
|
|
||||||
outstring = "WARNING: " + message;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output == Output::Console || output == Output::All)
|
|
||||||
{
|
|
||||||
if (type == Type::Error)
|
|
||||||
{
|
|
||||||
std::cerr << outstring << std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cout << outstring << std::endl;
|
|
||||||
}
|
|
||||||
const std::size_t maxBuffer = 30;
|
|
||||||
buffer().push_back(outstring);
|
|
||||||
if (buffer().size() > maxBuffer)buffer().pop_front(); //no majick here pl0x
|
|
||||||
updateOutString(maxBuffer);
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
outstring += "\n";
|
|
||||||
OutputDebugStringA(outstring.c_str());
|
|
||||||
#endif //_MSC_VER
|
|
||||||
}
|
|
||||||
if (output == Output::File || output == Output::All)
|
|
||||||
{
|
|
||||||
//output to a log file
|
|
||||||
std::ofstream file("output.log", std::ios::app);
|
|
||||||
if (file.good())
|
|
||||||
{
|
|
||||||
std::time_t time = std::time(nullptr);
|
|
||||||
auto tm = *std::localtime(&time);
|
|
||||||
//put_time isn't implemented by the ndk versions of the stl
|
|
||||||
file.imbue(std::locale());
|
|
||||||
file << std::put_time(&tm, "%d/%m/%y-%H:%M:%S: ");
|
|
||||||
file << outstring << std::endl;
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log(message, type, Output::Console);
|
|
||||||
log("Above message was intended for log file. Opening file probably failed.", Type::Warning, Output::Console);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::string& bufferString(){ return stringOutput(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::list<std::string>& buffer(){ static std::list<std::string> buffer; return buffer; }
|
|
||||||
static std::string& stringOutput() { static std::string output; return output; }
|
|
||||||
static void updateOutString(std::size_t maxBuffer)
|
|
||||||
{
|
|
||||||
static size_t count = 0;
|
|
||||||
stringOutput().append(buffer().back());
|
|
||||||
stringOutput().append("\n");
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (count > maxBuffer)
|
|
||||||
{
|
|
||||||
stringOutput() = stringOutput().substr(stringOutput().find_first_of('\n') + 1, stringOutput().size());
|
|
||||||
count--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define LOG(message, type)
|
|
||||||
#else
|
|
||||||
#define LOG(message, type) {\
|
|
||||||
std::stringstream ss; \
|
|
||||||
ss << message << " (" << __FILE__ << ", " << __LINE__ << ")"; \
|
|
||||||
tmx::Logger::log(ss.str(), type);}
|
|
||||||
#endif //NDEBUG
|
|
||||||
|
|
||||||
#endif //TMXLITE_LOGGER_HPP_
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2023
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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 "tmxlite/FreeFuncs.hpp"
|
|
||||||
#include "tmxlite/Types.hpp"
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
#ifndef USE_ZLIB
|
|
||||||
# include "miniz.h"
|
|
||||||
#else
|
|
||||||
# include <zlib.h>
|
|
||||||
#endif
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
bool tmx::decompress(const char* source, std::vector<unsigned char>& dest, std::size_t inSize, std::size_t expectedSize)
|
|
||||||
{
|
|
||||||
if (!source)
|
|
||||||
{
|
|
||||||
LOG("Input string is empty, decompression failed.", Logger::Type::Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//#ifdef USE_EXTLIBS
|
|
||||||
|
|
||||||
|
|
||||||
//#else
|
|
||||||
int currentSize = static_cast<int>(expectedSize);
|
|
||||||
std::vector<unsigned char> byteArray(expectedSize / sizeof(unsigned char));
|
|
||||||
z_stream stream;
|
|
||||||
stream.zalloc = Z_NULL;
|
|
||||||
stream.zfree = Z_NULL;
|
|
||||||
stream.opaque = Z_NULL;
|
|
||||||
stream.next_in = (Bytef*)source;
|
|
||||||
stream.avail_in = static_cast<unsigned int>(inSize);
|
|
||||||
stream.next_out = (Bytef*)byteArray.data();
|
|
||||||
stream.avail_out = static_cast<unsigned int>(expectedSize);
|
|
||||||
|
|
||||||
//we'd prefer to use inflateInit2 but it appears
|
|
||||||
//to be incorrect in miniz. This is fine for zlib
|
|
||||||
//compressed data, but gzip compressed streams
|
|
||||||
//will fail to inflate.
|
|
||||||
#ifdef USE_ZLIB
|
|
||||||
if (inflateInit2(&stream, 15 + 32) != Z_OK)
|
|
||||||
#else
|
|
||||||
if (inflateInit(&stream) != Z_OK)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
LOG("inflate init failed", Logger::Type::Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
result = inflate(&stream, Z_SYNC_FLUSH);
|
|
||||||
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default: break;
|
|
||||||
case Z_NEED_DICT:
|
|
||||||
case Z_STREAM_ERROR:
|
|
||||||
result = Z_DATA_ERROR;
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
Logger::log("If using gzip or zstd compression try using zlib instead", Logger::Type::Info);
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
inflateEnd(&stream);
|
|
||||||
Logger::log("inflate() returned " + std::to_string(result), Logger::Type::Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != Z_STREAM_END)
|
|
||||||
{
|
|
||||||
int oldSize = currentSize;
|
|
||||||
currentSize *= 2;
|
|
||||||
std::vector<unsigned char> newArray(currentSize / sizeof(unsigned char));
|
|
||||||
std::memcpy(newArray.data(), byteArray.data(), currentSize / 2);
|
|
||||||
byteArray = std::move(newArray);
|
|
||||||
|
|
||||||
stream.next_out = (Bytef*)(byteArray.data() + oldSize);
|
|
||||||
stream.avail_out = oldSize;
|
|
||||||
|
|
||||||
}
|
|
||||||
} while (result != Z_STREAM_END);
|
|
||||||
|
|
||||||
if (stream.avail_in != 0)
|
|
||||||
{
|
|
||||||
LOG("stream.avail_in is 0", Logger::Type::Error);
|
|
||||||
LOG("zlib decompression failed.", Logger::Type::Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int outSize = currentSize - stream.avail_out;
|
|
||||||
inflateEnd(&stream);
|
|
||||||
|
|
||||||
std::vector<unsigned char> newArray(outSize / sizeof(unsigned char));
|
|
||||||
std::memcpy(newArray.data(), byteArray.data(), outSize);
|
|
||||||
byteArray = std::move(newArray);
|
|
||||||
|
|
||||||
//copy bytes to vector
|
|
||||||
dest.insert(dest.begin(), byteArray.begin(), byteArray.end());
|
|
||||||
//#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator << (std::ostream& os, const tmx::Colour& c)
|
|
||||||
{
|
|
||||||
os << "RGBA: " << (int)c.r << ", " << (int)c.g << ", " << (int)c.b << ", " << (int)c.a;
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2023
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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 "tmxlite/ImageLayer.hpp"
|
|
||||||
#include "tmxlite/FreeFuncs.hpp"
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
|
||||||
|
|
||||||
using namespace tmx;
|
|
||||||
|
|
||||||
ImageLayer::ImageLayer(const std::string& workingDir)
|
|
||||||
: m_workingDir (workingDir),
|
|
||||||
m_hasTransparency (false),
|
|
||||||
m_hasRepeatX (false),
|
|
||||||
m_hasRepeatY (false)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//public
|
|
||||||
void ImageLayer::parse(const pugi::xml_node& node, Map*)
|
|
||||||
{
|
|
||||||
std::string attribName = node.name();
|
|
||||||
if (attribName != "imagelayer")
|
|
||||||
{
|
|
||||||
Logger::log("Node not an image layer, node skipped", Logger::Type::Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO this gets repeated foreach layer type and could all be moved to base class...
|
|
||||||
setName(node.attribute("name").as_string());
|
|
||||||
setClass(node.attribute("class").as_string());
|
|
||||||
setOpacity(node.attribute("opacity").as_float(1.f));
|
|
||||||
setVisible(node.attribute("visible").as_bool(true));
|
|
||||||
setOffset(node.attribute("offsetx").as_int(0), node.attribute("offsety").as_int(0));
|
|
||||||
setSize(node.attribute("width").as_uint(0), node.attribute("height").as_uint(0));
|
|
||||||
setParallaxFactor(node.attribute("parallaxx").as_float(1.f), node.attribute("parallaxy").as_float(1.f));
|
|
||||||
|
|
||||||
std::string tintColour = node.attribute("tintcolor").as_string();
|
|
||||||
if (!tintColour.empty())
|
|
||||||
{
|
|
||||||
setTintColour(colourFromString(tintColour));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_hasRepeatX = node.attribute("repeatx").as_bool(false);
|
|
||||||
m_hasRepeatY = node.attribute("repeaty").as_bool(false);
|
|
||||||
|
|
||||||
for (const auto& child : node.children())
|
|
||||||
{
|
|
||||||
attribName = child.name();
|
|
||||||
if (attribName == "image")
|
|
||||||
{
|
|
||||||
attribName = child.attribute("source").as_string();
|
|
||||||
if (attribName.empty())
|
|
||||||
{
|
|
||||||
Logger::log("Image Layer has missing source property", Logger::Type::Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (child.attribute("width") && child.attribute("height"))
|
|
||||||
{
|
|
||||||
m_imageSize.x = child.attribute("width").as_uint();
|
|
||||||
m_imageSize.y = child.attribute("height").as_uint();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_filePath = resolveFilePath(attribName, m_workingDir);
|
|
||||||
if (child.attribute("trans"))
|
|
||||||
{
|
|
||||||
attribName = child.attribute("trans").as_string();
|
|
||||||
m_transparencyColour = colourFromString(attribName);
|
|
||||||
m_hasTransparency = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (attribName == "properties")
|
|
||||||
{
|
|
||||||
for (const auto& p : child.children())
|
|
||||||
{
|
|
||||||
addProperty(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Grant Gangi 2019
|
|
||||||
Matt Marchant 2023
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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 "tmxlite/LayerGroup.hpp"
|
|
||||||
#include "tmxlite/FreeFuncs.hpp"
|
|
||||||
#include "tmxlite/ObjectGroup.hpp"
|
|
||||||
#include "tmxlite/ImageLayer.hpp"
|
|
||||||
#include "tmxlite/TileLayer.hpp"
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
|
||||||
|
|
||||||
using namespace tmx;
|
|
||||||
|
|
||||||
LayerGroup::LayerGroup(const std::string& workingDir, const Vector2u& tileCount)
|
|
||||||
: m_workingDir(workingDir),
|
|
||||||
m_tileCount(tileCount)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//public
|
|
||||||
void LayerGroup::parse(const pugi::xml_node& node, Map* map)
|
|
||||||
{
|
|
||||||
assert(map);
|
|
||||||
std::string attribString = node.name();
|
|
||||||
if (attribString != "group")
|
|
||||||
{
|
|
||||||
Logger::log("Node was not a group layer, node will be skipped.", Logger::Type::Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setName(node.attribute("name").as_string());
|
|
||||||
setClass(node.attribute("class").as_string());
|
|
||||||
setOpacity(node.attribute("opacity").as_float(1.f));
|
|
||||||
setVisible(node.attribute("visible").as_bool(true));
|
|
||||||
setOffset(node.attribute("offsetx").as_int(0), node.attribute("offsety").as_int(0));
|
|
||||||
setSize(node.attribute("width").as_uint(0), node.attribute("height").as_uint(0));
|
|
||||||
setParallaxFactor(node.attribute("parallaxx").as_float(1.f), node.attribute("parallaxy").as_float(1.f));
|
|
||||||
|
|
||||||
std::string tintColour = node.attribute("tintcolor").as_string();
|
|
||||||
if (!tintColour.empty())
|
|
||||||
{
|
|
||||||
setTintColour(colourFromString(tintColour));
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse children
|
|
||||||
for (const auto& child : node.children())
|
|
||||||
{
|
|
||||||
attribString = child.name();
|
|
||||||
if (attribString == "properties")
|
|
||||||
{
|
|
||||||
for (const auto& p : child.children())
|
|
||||||
{
|
|
||||||
addProperty(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (attribString == "layer")
|
|
||||||
{
|
|
||||||
m_layers.emplace_back(std::make_unique<TileLayer>(m_tileCount.x * m_tileCount.y));
|
|
||||||
m_layers.back()->parse(child, map);
|
|
||||||
}
|
|
||||||
else if (attribString == "objectgroup")
|
|
||||||
{
|
|
||||||
m_layers.emplace_back(std::make_unique<ObjectGroup>());
|
|
||||||
m_layers.back()->parse(child, map);
|
|
||||||
}
|
|
||||||
else if (attribString == "imagelayer")
|
|
||||||
{
|
|
||||||
m_layers.emplace_back(std::make_unique<ImageLayer>(m_workingDir));
|
|
||||||
m_layers.back()->parse(child, map);
|
|
||||||
}
|
|
||||||
else if (attribString == "group")
|
|
||||||
{
|
|
||||||
m_layers.emplace_back(std::make_unique<LayerGroup>(m_workingDir, m_tileCount));
|
|
||||||
m_layers.back()->parse(child, map);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG("Unidentified name " + attribString + ": node skipped", Logger::Type::Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,362 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2023
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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 "tmxlite/Map.hpp"
|
|
||||||
#include "tmxlite/FreeFuncs.hpp"
|
|
||||||
#include "tmxlite/ObjectGroup.hpp"
|
|
||||||
#include "tmxlite/ImageLayer.hpp"
|
|
||||||
#include "tmxlite/TileLayer.hpp"
|
|
||||||
#include "tmxlite/LayerGroup.hpp"
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
using namespace tmx;
|
|
||||||
|
|
||||||
Map::Map()
|
|
||||||
: m_orientation (Orientation::None),
|
|
||||||
m_renderOrder (RenderOrder::None),
|
|
||||||
m_infinite (false),
|
|
||||||
m_hexSideLength (0.f),
|
|
||||||
m_staggerAxis (StaggerAxis::None),
|
|
||||||
m_staggerIndex (StaggerIndex::None)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//public
|
|
||||||
bool Map::load(const std::string& path)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
|
|
||||||
//open the doc
|
|
||||||
pugi::xml_document doc;
|
|
||||||
auto result = doc.load_file(path.c_str());
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
Logger::log("Failed opening " + path, Logger::Type::Error);
|
|
||||||
Logger::log("Reason: " + std::string(result.description()), Logger::Type::Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//make sure we have consistent path separators
|
|
||||||
m_workingDirectory = path;
|
|
||||||
std::replace(m_workingDirectory.begin(), m_workingDirectory.end(), '\\', '/');
|
|
||||||
m_workingDirectory = getFilePath(m_workingDirectory);
|
|
||||||
|
|
||||||
if (!m_workingDirectory.empty() &&
|
|
||||||
m_workingDirectory.back() == '/')
|
|
||||||
{
|
|
||||||
m_workingDirectory.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//find the map node and bail if it doesn't exist
|
|
||||||
auto mapNode = doc.child("map");
|
|
||||||
if (!mapNode)
|
|
||||||
{
|
|
||||||
Logger::log("Failed opening map: " + path + ", no map node found", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseMapNode(mapNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Map::loadFromString(const std::string& data, const std::string& workingDir)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
|
|
||||||
//open the doc
|
|
||||||
pugi::xml_document doc;
|
|
||||||
auto result = doc.load_string(data.c_str());
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
Logger::log("Failed opening map", Logger::Type::Error);
|
|
||||||
Logger::log("Reason: " + std::string(result.description()), Logger::Type::Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//make sure we have consistent path separators
|
|
||||||
m_workingDirectory = workingDir;
|
|
||||||
std::replace(m_workingDirectory.begin(), m_workingDirectory.end(), '\\', '/');
|
|
||||||
m_workingDirectory = getFilePath(m_workingDirectory);
|
|
||||||
|
|
||||||
if (!m_workingDirectory.empty() &&
|
|
||||||
m_workingDirectory.back() == '/')
|
|
||||||
{
|
|
||||||
m_workingDirectory.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
//find the map node and bail if it doesn't exist
|
|
||||||
auto mapNode = doc.child("map");
|
|
||||||
if (!mapNode)
|
|
||||||
{
|
|
||||||
Logger::log("Failed opening map: no map node found", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseMapNode(mapNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
//private
|
|
||||||
bool Map::parseMapNode(const pugi::xml_node& mapNode)
|
|
||||||
{
|
|
||||||
//parse map attributes
|
|
||||||
std::size_t pointPos = 0;
|
|
||||||
std::string attribString = mapNode.attribute("version").as_string();
|
|
||||||
if (attribString.empty() || (pointPos = attribString.find('.')) == std::string::npos)
|
|
||||||
{
|
|
||||||
Logger::log("Invalid map version value, map not loaded.", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_version.upper = std::stoi(attribString.substr(0, pointPos));
|
|
||||||
m_version.lower = std::stoi(attribString.substr(pointPos + 1));
|
|
||||||
|
|
||||||
m_class = mapNode.attribute("class").as_string();
|
|
||||||
|
|
||||||
attribString = mapNode.attribute("orientation").as_string();
|
|
||||||
if (attribString.empty())
|
|
||||||
{
|
|
||||||
Logger::log("Missing map orientation attribute, map not loaded.", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attribString == "orthogonal")
|
|
||||||
{
|
|
||||||
m_orientation = Orientation::Orthogonal;
|
|
||||||
}
|
|
||||||
else if (attribString == "isometric")
|
|
||||||
{
|
|
||||||
m_orientation = Orientation::Isometric;
|
|
||||||
}
|
|
||||||
else if (attribString == "staggered")
|
|
||||||
{
|
|
||||||
m_orientation = Orientation::Staggered;
|
|
||||||
}
|
|
||||||
else if (attribString == "hexagonal")
|
|
||||||
{
|
|
||||||
m_orientation = Orientation::Hexagonal;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger::log(attribString + " format maps aren't supported yet, sorry! Map not loaded", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
attribString = mapNode.attribute("renderorder").as_string();
|
|
||||||
//this property is optional for older version of map files
|
|
||||||
if (!attribString.empty())
|
|
||||||
{
|
|
||||||
if (attribString == "right-down")
|
|
||||||
{
|
|
||||||
m_renderOrder = RenderOrder::RightDown;
|
|
||||||
}
|
|
||||||
else if (attribString == "right-up")
|
|
||||||
{
|
|
||||||
m_renderOrder = RenderOrder::RightUp;
|
|
||||||
}
|
|
||||||
else if (attribString == "left-down")
|
|
||||||
{
|
|
||||||
m_renderOrder = RenderOrder::LeftDown;
|
|
||||||
}
|
|
||||||
else if (attribString == "left-up")
|
|
||||||
{
|
|
||||||
m_renderOrder = RenderOrder::LeftUp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger::log(attribString + ": invalid render order. Map not loaded.", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapNode.attribute("infinite"))
|
|
||||||
{
|
|
||||||
m_infinite = mapNode.attribute("infinite").as_int() != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned width = mapNode.attribute("width").as_int();
|
|
||||||
unsigned height = mapNode.attribute("height").as_int();
|
|
||||||
if (width && height)
|
|
||||||
{
|
|
||||||
m_tileCount = { width, height };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger::log("Invalid map tile count, map not loaded", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
width = mapNode.attribute("tilewidth").as_int();
|
|
||||||
height = mapNode.attribute("tileheight").as_int();
|
|
||||||
if (width && height)
|
|
||||||
{
|
|
||||||
m_tileSize = { width, height };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger::log("Invalid tile size, map not loaded", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_hexSideLength = mapNode.attribute("hexsidelength").as_float();
|
|
||||||
if (m_orientation == Orientation::Hexagonal && m_hexSideLength <= 0)
|
|
||||||
{
|
|
||||||
Logger::log("Invalid he side length found, map not loaded", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
attribString = mapNode.attribute("staggeraxis").as_string();
|
|
||||||
if (attribString == "x")
|
|
||||||
{
|
|
||||||
m_staggerAxis = StaggerAxis::X;
|
|
||||||
}
|
|
||||||
else if (attribString == "y")
|
|
||||||
{
|
|
||||||
m_staggerAxis = StaggerAxis::Y;
|
|
||||||
}
|
|
||||||
if ((m_orientation == Orientation::Staggered || m_orientation == Orientation::Hexagonal)
|
|
||||||
&& m_staggerAxis == StaggerAxis::None)
|
|
||||||
{
|
|
||||||
Logger::log("Map missing stagger axis property. Map not loaded.", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
attribString = mapNode.attribute("staggerindex").as_string();
|
|
||||||
if (attribString == "odd")
|
|
||||||
{
|
|
||||||
m_staggerIndex = StaggerIndex::Odd;
|
|
||||||
}
|
|
||||||
else if (attribString == "even")
|
|
||||||
{
|
|
||||||
m_staggerIndex = StaggerIndex::Even;
|
|
||||||
}
|
|
||||||
if ((m_orientation == Orientation::Staggered || m_orientation == Orientation::Hexagonal)
|
|
||||||
&& m_staggerIndex == StaggerIndex::None)
|
|
||||||
{
|
|
||||||
Logger::log("Map missing stagger index property. Map not loaded.", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_parallaxOrigin =
|
|
||||||
{
|
|
||||||
mapNode.attribute("parallaxoriginx").as_float(0.f),
|
|
||||||
mapNode.attribute("parallaxoriginy").as_float(0.f)
|
|
||||||
};
|
|
||||||
|
|
||||||
//colour property is optional
|
|
||||||
attribString = mapNode.attribute("backgroundcolor").as_string();
|
|
||||||
if (!attribString.empty())
|
|
||||||
{
|
|
||||||
m_backgroundColour = colourFromString(attribString);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO do we need next object ID
|
|
||||||
|
|
||||||
//parse all child nodes
|
|
||||||
for (const auto& node : mapNode.children())
|
|
||||||
{
|
|
||||||
std::string name = node.name();
|
|
||||||
if (name == "tileset")
|
|
||||||
{
|
|
||||||
m_tilesets.emplace_back(m_workingDirectory);
|
|
||||||
m_tilesets.back().parse(node, this);
|
|
||||||
}
|
|
||||||
else if (name == "layer")
|
|
||||||
{
|
|
||||||
m_layers.emplace_back(std::make_unique<TileLayer>(m_tileCount.x * m_tileCount.y));
|
|
||||||
m_layers.back()->parse(node);
|
|
||||||
}
|
|
||||||
else if (name == "objectgroup")
|
|
||||||
{
|
|
||||||
m_layers.emplace_back(std::make_unique<ObjectGroup>());
|
|
||||||
m_layers.back()->parse(node, this);
|
|
||||||
}
|
|
||||||
else if (name == "imagelayer")
|
|
||||||
{
|
|
||||||
m_layers.emplace_back(std::make_unique<ImageLayer>(m_workingDirectory));
|
|
||||||
m_layers.back()->parse(node, this);
|
|
||||||
}
|
|
||||||
else if (name == "properties")
|
|
||||||
{
|
|
||||||
const auto& children = node.children();
|
|
||||||
for (const auto& child : children)
|
|
||||||
{
|
|
||||||
m_properties.emplace_back();
|
|
||||||
m_properties.back().parse(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (name == "group")
|
|
||||||
{
|
|
||||||
m_layers.emplace_back(std::make_unique<LayerGroup>(m_workingDirectory, m_tileCount));
|
|
||||||
m_layers.back()->parse(node, this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG("Unidentified name " + name + ": node skipped", Logger::Type::Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// fill animated tiles for easier lookup into map
|
|
||||||
for(const auto& ts : m_tilesets)
|
|
||||||
{
|
|
||||||
for(const auto& tile : ts.getTiles())
|
|
||||||
{
|
|
||||||
if (!tile.animation.frames.empty())
|
|
||||||
{
|
|
||||||
m_animTiles[tile.ID + ts.getFirstGID()] = tile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Map::reset()
|
|
||||||
{
|
|
||||||
m_orientation = Orientation::None;
|
|
||||||
m_renderOrder = RenderOrder::None;
|
|
||||||
m_tileCount = { 0u, 0u };
|
|
||||||
m_tileSize = { 0u, 0u };
|
|
||||||
m_hexSideLength = 0.f;
|
|
||||||
m_staggerAxis = StaggerAxis::None;
|
|
||||||
m_staggerIndex = StaggerIndex::None;
|
|
||||||
m_backgroundColour = {};
|
|
||||||
m_workingDirectory = "";
|
|
||||||
|
|
||||||
m_tilesets.clear();
|
|
||||||
m_layers.clear();
|
|
||||||
m_properties.clear();
|
|
||||||
|
|
||||||
m_templateObjects.clear();
|
|
||||||
m_templateTilesets.clear();
|
|
||||||
|
|
||||||
m_animTiles.clear();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,399 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2021
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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 "tmxlite/Object.hpp"
|
|
||||||
#include "tmxlite/FreeFuncs.hpp"
|
|
||||||
#include "tmxlite/Map.hpp"
|
|
||||||
#include "tmxlite/Tileset.hpp"
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
using namespace tmx;
|
|
||||||
|
|
||||||
Object::Object()
|
|
||||||
: m_UID (0),
|
|
||||||
m_rotation (0.f),
|
|
||||||
m_tileID (0),
|
|
||||||
m_flipFlags (0),
|
|
||||||
m_visible (true),
|
|
||||||
m_shape (Shape::Rectangle)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//public
|
|
||||||
void Object::parse(const pugi::xml_node& node, Map* map)
|
|
||||||
{
|
|
||||||
std::string attribString = node.name();
|
|
||||||
if (attribString != "object")
|
|
||||||
{
|
|
||||||
Logger::log("This not an Object node, parsing skipped.", Logger::Type::Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_UID = node.attribute("id").as_int();
|
|
||||||
m_name = node.attribute("name").as_string();
|
|
||||||
|
|
||||||
m_class = node.attribute("type").as_string();
|
|
||||||
if (m_class.empty())
|
|
||||||
{
|
|
||||||
m_class = node.attribute("class").as_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_position.x = node.attribute("x").as_float();
|
|
||||||
m_AABB.left = m_position.x;
|
|
||||||
m_position.y = node.attribute("y").as_float();
|
|
||||||
m_AABB.top = m_position.y;
|
|
||||||
m_AABB.width = node.attribute("width").as_float();
|
|
||||||
m_AABB.height = node.attribute("height").as_float();
|
|
||||||
m_rotation = node.attribute("rotation").as_float();
|
|
||||||
m_visible = node.attribute("visible").as_bool(true);
|
|
||||||
|
|
||||||
m_tileID = node.attribute("gid").as_uint();
|
|
||||||
|
|
||||||
static const std::uint32_t mask = 0xf0000000;
|
|
||||||
m_flipFlags = ((m_tileID & mask) >> 28);
|
|
||||||
m_tileID = m_tileID & ~mask;
|
|
||||||
|
|
||||||
for (const auto& child : node.children())
|
|
||||||
{
|
|
||||||
attribString = child.name();
|
|
||||||
if (attribString == "properties")
|
|
||||||
{
|
|
||||||
for (const auto& p : child.children())
|
|
||||||
{
|
|
||||||
m_properties.emplace_back();
|
|
||||||
m_properties.back().parse(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (attribString == "ellipse")
|
|
||||||
{
|
|
||||||
m_shape = Shape::Ellipse;
|
|
||||||
}
|
|
||||||
else if (attribString == "point")
|
|
||||||
{
|
|
||||||
m_shape = Shape::Point;
|
|
||||||
}
|
|
||||||
else if (attribString == "polygon")
|
|
||||||
{
|
|
||||||
m_shape = Shape::Polygon;
|
|
||||||
parsePoints(child);
|
|
||||||
}
|
|
||||||
else if (attribString == "polyline")
|
|
||||||
{
|
|
||||||
m_shape = Shape::Polyline;
|
|
||||||
parsePoints(child);
|
|
||||||
}
|
|
||||||
else if (attribString == "text")
|
|
||||||
{
|
|
||||||
m_shape = Shape::Text;
|
|
||||||
parseText(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//parse templates last so we know which properties
|
|
||||||
//ought to be overridden
|
|
||||||
std::string templateStr = node.attribute("template").as_string();
|
|
||||||
if (!templateStr.empty() && map)
|
|
||||||
{
|
|
||||||
parseTemplate(templateStr, map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//private
|
|
||||||
void Object::parsePoints(const pugi::xml_node& node)
|
|
||||||
{
|
|
||||||
if (node.attribute("points"))
|
|
||||||
{
|
|
||||||
std::string pointlist = node.attribute("points").as_string();
|
|
||||||
std::stringstream stream(pointlist);
|
|
||||||
std::vector<std::string> points;
|
|
||||||
std::string pointstring;
|
|
||||||
while (std::getline(stream, pointstring, ' '))
|
|
||||||
{
|
|
||||||
points.push_back(pointstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
//parse each pair into sf::vector2f
|
|
||||||
for (unsigned int i = 0; i < points.size(); i++)
|
|
||||||
{
|
|
||||||
std::vector<float> coords;
|
|
||||||
std::stringstream coordstream(points[i]);
|
|
||||||
|
|
||||||
float j;
|
|
||||||
while (coordstream >> j)
|
|
||||||
{
|
|
||||||
coords.push_back(j);
|
|
||||||
//TODO this should really ignore anything non-numeric
|
|
||||||
if (coordstream.peek() == ',')
|
|
||||||
{
|
|
||||||
coordstream.ignore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_points.emplace_back(coords[0], coords[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger::log("Points for polygon or polyline object are missing", Logger::Type::Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::parseText(const pugi::xml_node& node)
|
|
||||||
{
|
|
||||||
m_textData.bold = node.attribute("bold").as_bool(false);
|
|
||||||
m_textData.colour = colourFromString(node.attribute("color").as_string("#FFFFFFFF"));
|
|
||||||
m_textData.fontFamily = node.attribute("fontfamily").as_string();
|
|
||||||
m_textData.italic = node.attribute("italic").as_bool(false);
|
|
||||||
m_textData.kerning = node.attribute("kerning").as_bool(true);
|
|
||||||
m_textData.pixelSize = node.attribute("pixelsize").as_uint(16);
|
|
||||||
m_textData.strikethough = node.attribute("strikeout").as_bool(false);
|
|
||||||
m_textData.underline = node.attribute("underline").as_bool(false);
|
|
||||||
m_textData.wrap = node.attribute("wrap").as_bool(false);
|
|
||||||
|
|
||||||
std::string alignment = node.attribute("halign").as_string("left");
|
|
||||||
if (alignment == "left")
|
|
||||||
{
|
|
||||||
m_textData.hAlign = Text::HAlign::Left;
|
|
||||||
}
|
|
||||||
else if (alignment == "center")
|
|
||||||
{
|
|
||||||
m_textData.hAlign = Text::HAlign::Centre;
|
|
||||||
}
|
|
||||||
else if (alignment == "right")
|
|
||||||
{
|
|
||||||
m_textData.hAlign = Text::HAlign::Right;
|
|
||||||
}
|
|
||||||
|
|
||||||
alignment = node.attribute("valign").as_string("top");
|
|
||||||
if (alignment == "top")
|
|
||||||
{
|
|
||||||
m_textData.vAlign = Text::VAlign::Top;
|
|
||||||
}
|
|
||||||
else if (alignment == "center")
|
|
||||||
{
|
|
||||||
m_textData.vAlign = Text::VAlign::Centre;
|
|
||||||
}
|
|
||||||
else if (alignment == "bottom")
|
|
||||||
{
|
|
||||||
m_textData.vAlign = Text::VAlign::Bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_textData.content = node.text().as_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::parseTemplate(const std::string& path, Map* map)
|
|
||||||
{
|
|
||||||
assert(map);
|
|
||||||
|
|
||||||
auto& templateObjects = map->getTemplateObjects();
|
|
||||||
auto& templateTilesets = map->getTemplateTilesets();
|
|
||||||
|
|
||||||
//load the template if not already loaded
|
|
||||||
if (templateObjects.count(path) == 0)
|
|
||||||
{
|
|
||||||
auto templatePath = map->getWorkingDirectory() + "/" + path;
|
|
||||||
|
|
||||||
pugi::xml_document doc;
|
|
||||||
if (!doc.load_file(templatePath.c_str()))
|
|
||||||
{
|
|
||||||
Logger::log("Failed opening template file " + path, Logger::Type::Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto templateNode = doc.child("template");
|
|
||||||
if (!templateNode)
|
|
||||||
{
|
|
||||||
Logger::log("Template node missing from " + path, Logger::Type::Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if the template has a tileset load that (if not already loaded)
|
|
||||||
std::string tilesetName;
|
|
||||||
auto tileset = templateNode.child("tileset");
|
|
||||||
if (tileset)
|
|
||||||
{
|
|
||||||
tilesetName = tileset.attribute("source").as_string();
|
|
||||||
if (!tilesetName.empty() &&
|
|
||||||
templateTilesets.count(tilesetName) == 0)
|
|
||||||
{
|
|
||||||
templateTilesets.insert(std::make_pair(tilesetName, Tileset(map->getWorkingDirectory())));
|
|
||||||
templateTilesets.at(tilesetName).parse(tileset, map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//parse the object - don't pass the map pointer here so there's
|
|
||||||
//no recursion if someone tried to get clever and put a template in a template
|
|
||||||
auto obj = templateNode.child("object");
|
|
||||||
if (obj)
|
|
||||||
{
|
|
||||||
templateObjects.insert(std::make_pair(path, Object()));
|
|
||||||
templateObjects[path].parse(obj, nullptr);
|
|
||||||
templateObjects[path].m_tilesetName = tilesetName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//apply any non-overridden object properties from the template
|
|
||||||
if (templateObjects.count(path) != 0)
|
|
||||||
{
|
|
||||||
const auto& obj = templateObjects[path];
|
|
||||||
if (m_AABB.width == 0)
|
|
||||||
{
|
|
||||||
m_AABB.width = obj.m_AABB.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_AABB.height == 0)
|
|
||||||
{
|
|
||||||
m_AABB.height = obj.m_AABB.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_tilesetName = obj.m_tilesetName;
|
|
||||||
|
|
||||||
if (m_name.empty())
|
|
||||||
{
|
|
||||||
m_name = obj.m_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_class.empty())
|
|
||||||
{
|
|
||||||
m_class = obj.m_class;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_rotation == 0)
|
|
||||||
{
|
|
||||||
m_rotation = obj.m_rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_tileID == 0)
|
|
||||||
{
|
|
||||||
m_tileID = obj.m_tileID;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_flipFlags == 0)
|
|
||||||
{
|
|
||||||
m_flipFlags = obj.m_flipFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_shape == Shape::Rectangle)
|
|
||||||
{
|
|
||||||
m_shape = obj.m_shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_points.empty())
|
|
||||||
{
|
|
||||||
m_points = obj.m_points;
|
|
||||||
}
|
|
||||||
|
|
||||||
//compare properties and only copy ones that don't exist
|
|
||||||
for (const auto& p : obj.m_properties)
|
|
||||||
{
|
|
||||||
auto result = std::find_if(m_properties.begin(), m_properties.end(),
|
|
||||||
[&p](const Property& a)
|
|
||||||
{
|
|
||||||
return a.getName() == p.getName();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result == m_properties.end())
|
|
||||||
{
|
|
||||||
m_properties.push_back(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (m_shape == Shape::Text)
|
|
||||||
{
|
|
||||||
//check each text property and update as necessary
|
|
||||||
//TODO this makes he assumption we prefer the template
|
|
||||||
//properties over the default ones - this might not
|
|
||||||
//actually be the case....
|
|
||||||
const auto& otherText = obj.m_textData;
|
|
||||||
if (m_textData.fontFamily.empty())
|
|
||||||
{
|
|
||||||
m_textData.fontFamily = otherText.fontFamily;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_textData.pixelSize == 16)
|
|
||||||
{
|
|
||||||
m_textData.pixelSize = otherText.pixelSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO this isn't actually right if we *want* to be false
|
|
||||||
//and the template is set to true...
|
|
||||||
if (m_textData.wrap == false)
|
|
||||||
{
|
|
||||||
m_textData.wrap = otherText.wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_textData.colour == Colour())
|
|
||||||
{
|
|
||||||
m_textData.colour = otherText.colour;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_textData.bold == false)
|
|
||||||
{
|
|
||||||
m_textData.bold = otherText.bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_textData.italic == false)
|
|
||||||
{
|
|
||||||
m_textData.italic = otherText.italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_textData.underline == false)
|
|
||||||
{
|
|
||||||
m_textData.underline = otherText.underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_textData.strikethough == false)
|
|
||||||
{
|
|
||||||
m_textData.strikethough = otherText.strikethough;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_textData.kerning == true)
|
|
||||||
{
|
|
||||||
m_textData.kerning = otherText.kerning;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_textData.hAlign == Text::HAlign::Left)
|
|
||||||
{
|
|
||||||
m_textData.hAlign = otherText.hAlign;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_textData.vAlign == Text::VAlign::Top)
|
|
||||||
{
|
|
||||||
m_textData.vAlign = otherText.vAlign;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_textData.content.empty())
|
|
||||||
{
|
|
||||||
m_textData.content = otherText.content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2023
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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 "tmxlite/FreeFuncs.hpp"
|
|
||||||
#include "tmxlite/ObjectGroup.hpp"
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
|
||||||
|
|
||||||
using namespace tmx;
|
|
||||||
|
|
||||||
ObjectGroup::ObjectGroup()
|
|
||||||
: m_colour (127, 127, 127, 255),
|
|
||||||
m_drawOrder (DrawOrder::TopDown)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//public
|
|
||||||
void ObjectGroup::parse(const pugi::xml_node& node, Map* map)
|
|
||||||
{
|
|
||||||
assert(map);
|
|
||||||
|
|
||||||
std::string attribString = node.name();
|
|
||||||
if (attribString != "objectgroup")
|
|
||||||
{
|
|
||||||
Logger::log("Node was not an object group, node will be skipped.", Logger::Type::Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setName(node.attribute("name").as_string());
|
|
||||||
setClass(node.attribute("class").as_string());
|
|
||||||
|
|
||||||
attribString = node.attribute("color").as_string();
|
|
||||||
if (!attribString.empty())
|
|
||||||
{
|
|
||||||
m_colour = colourFromString(attribString);
|
|
||||||
}
|
|
||||||
|
|
||||||
setOpacity(node.attribute("opacity").as_float(1.f));
|
|
||||||
setVisible(node.attribute("visible").as_bool(true));
|
|
||||||
setOffset(node.attribute("offsetx").as_int(0), node.attribute("offsety").as_int(0));
|
|
||||||
setSize(node.attribute("width").as_uint(0), node.attribute("height").as_uint(0));
|
|
||||||
setParallaxFactor(node.attribute("parallaxx").as_float(1.f), node.attribute("parallaxy").as_float(1.f));
|
|
||||||
|
|
||||||
std::string tintColour = node.attribute("tintcolor").as_string();
|
|
||||||
if (!tintColour.empty())
|
|
||||||
{
|
|
||||||
setTintColour(colourFromString(tintColour));
|
|
||||||
}
|
|
||||||
|
|
||||||
attribString = node.attribute("draworder").as_string();
|
|
||||||
if (attribString == "index")
|
|
||||||
{
|
|
||||||
m_drawOrder = DrawOrder::Index;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& child : node.children())
|
|
||||||
{
|
|
||||||
attribString = child.name();
|
|
||||||
if (attribString == "properties")
|
|
||||||
{
|
|
||||||
for (const auto& p : child)
|
|
||||||
{
|
|
||||||
m_properties.emplace_back();
|
|
||||||
m_properties.back().parse(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (attribString == "object")
|
|
||||||
{
|
|
||||||
m_objects.emplace_back();
|
|
||||||
m_objects.back().parse(child, map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Raphaël Frantz 2021
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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 "tmxlite/FreeFuncs.hpp"
|
|
||||||
#include "tmxlite/ObjectTypes.hpp"
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
|
||||||
|
|
||||||
using namespace tmx;
|
|
||||||
|
|
||||||
bool ObjectTypes::load(const std::string &path)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
|
|
||||||
//open the doc
|
|
||||||
pugi::xml_document doc;
|
|
||||||
auto result = doc.load_file(path.c_str());
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
Logger::log("Failed opening " + path, Logger::Type::Error);
|
|
||||||
Logger::log("Reason: " + std::string(result.description()), Logger::Type::Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//make sure we have consistent path separators
|
|
||||||
m_workingDirectory = path;
|
|
||||||
std::replace(m_workingDirectory.begin(), m_workingDirectory.end(), '\\', '/');
|
|
||||||
m_workingDirectory = getFilePath(m_workingDirectory);
|
|
||||||
|
|
||||||
if (!m_workingDirectory.empty() &&
|
|
||||||
m_workingDirectory.back() == '/')
|
|
||||||
{
|
|
||||||
m_workingDirectory.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//find the node and bail if it doesn't exist
|
|
||||||
auto node = doc.child("objecttypes");
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
Logger::log("Failed opening object types: " + path + ", no objecttype node found", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseObjectTypesNode(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ObjectTypes::loadFromString(const std::string &data, const std::string &workingDir)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
|
|
||||||
//open the doc
|
|
||||||
pugi::xml_document doc;
|
|
||||||
auto result = doc.load_string(data.c_str());
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
Logger::log("Failed opening object types", Logger::Type::Error);
|
|
||||||
Logger::log("Reason: " + std::string(result.description()), Logger::Type::Error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//make sure we have consistent path separators
|
|
||||||
m_workingDirectory = workingDir;
|
|
||||||
std::replace(m_workingDirectory.begin(), m_workingDirectory.end(), '\\', '/');
|
|
||||||
m_workingDirectory = getFilePath(m_workingDirectory);
|
|
||||||
|
|
||||||
if (!m_workingDirectory.empty() &&
|
|
||||||
m_workingDirectory.back() == '/')
|
|
||||||
{
|
|
||||||
m_workingDirectory.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//find the node and bail if it doesn't exist
|
|
||||||
auto node = doc.child("objecttypes");
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
Logger::log("Failed object types: no objecttypes node found", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseObjectTypesNode(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ObjectTypes::parseObjectTypesNode(const pugi::xml_node &node)
|
|
||||||
{
|
|
||||||
//<objecttypes> <-- node
|
|
||||||
// <objecttype name="Character" color="#1e47ff">
|
|
||||||
// <property>...
|
|
||||||
|
|
||||||
//parse types
|
|
||||||
for(const auto& child : node.children())
|
|
||||||
{
|
|
||||||
std::string attribString = child.name();
|
|
||||||
if (attribString == "objecttype")
|
|
||||||
{
|
|
||||||
Type type;
|
|
||||||
|
|
||||||
//parse the metadata of the type
|
|
||||||
type.name = child.attribute("name").as_string();
|
|
||||||
type.colour = colourFromString(child.attribute("color").as_string("#FFFFFFFF"));;
|
|
||||||
|
|
||||||
//parse the default properties of the type
|
|
||||||
for (const auto& p : child.children())
|
|
||||||
{
|
|
||||||
Property prop;
|
|
||||||
prop.parse(p, true);
|
|
||||||
type.properties.push_back(prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_types.push_back(type);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG("Unidentified name " + attribString + ": node skipped", Logger::Type::Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ObjectTypes::reset()
|
|
||||||
{
|
|
||||||
m_workingDirectory.clear();
|
|
||||||
m_types.clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2021
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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 "tmxlite/Property.hpp"
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
#include "tmxlite/FreeFuncs.hpp"
|
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
|
||||||
|
|
||||||
using namespace tmx;
|
|
||||||
|
|
||||||
Property::Property()
|
|
||||||
: m_type(Type::Undef)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Property Property::fromBoolean(bool value)
|
|
||||||
{
|
|
||||||
Property p;
|
|
||||||
p.m_type = Type::Boolean;
|
|
||||||
p.m_boolValue = value;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Property Property::fromFloat(float value)
|
|
||||||
{
|
|
||||||
Property p;
|
|
||||||
p.m_type = Type::Float;
|
|
||||||
p.m_floatValue = value;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Property Property::fromInt(int value)
|
|
||||||
{
|
|
||||||
Property p;
|
|
||||||
p.m_type = Type::Int;
|
|
||||||
p.m_intValue = value;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Property Property::fromString(const std::string& value)
|
|
||||||
{
|
|
||||||
Property p;
|
|
||||||
p.m_type = Type::String;
|
|
||||||
p.m_stringValue = value;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Property Property::fromColour(const Colour& value)
|
|
||||||
{
|
|
||||||
Property p;
|
|
||||||
p.m_type = Type::Colour;
|
|
||||||
p.m_colourValue = value;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Property Property::fromFile(const std::string& value)
|
|
||||||
{
|
|
||||||
Property p;
|
|
||||||
p.m_type = Type::File;
|
|
||||||
p.m_stringValue = value;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Property Property::fromObject(int value)
|
|
||||||
{
|
|
||||||
Property p;
|
|
||||||
p.m_type = Type::Object;
|
|
||||||
p.m_intValue = value;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
//public
|
|
||||||
void Property::parse(const pugi::xml_node& node, bool isObjectTypes)
|
|
||||||
{
|
|
||||||
// The value attribute name is different in object types
|
|
||||||
const char *const valueAttribute = isObjectTypes ? "default" : "value";
|
|
||||||
|
|
||||||
std::string attribData = node.name();
|
|
||||||
if (attribData != "property")
|
|
||||||
{
|
|
||||||
Logger::log("Node was not a valid property, node will be skipped", Logger::Type::Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_name = node.attribute("name").as_string();
|
|
||||||
|
|
||||||
attribData = node.attribute("type").as_string("string");
|
|
||||||
if (attribData == "bool")
|
|
||||||
{
|
|
||||||
attribData = node.attribute(valueAttribute).as_string("false");
|
|
||||||
m_boolValue = (attribData == "true");
|
|
||||||
m_type = Type::Boolean;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (attribData == "int")
|
|
||||||
{
|
|
||||||
m_intValue = node.attribute(valueAttribute).as_int(0);
|
|
||||||
m_type = Type::Int;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (attribData == "float")
|
|
||||||
{
|
|
||||||
m_floatValue = node.attribute(valueAttribute).as_float(0.f);
|
|
||||||
m_type = Type::Float;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (attribData == "string")
|
|
||||||
{
|
|
||||||
m_stringValue = node.attribute(valueAttribute).as_string();
|
|
||||||
|
|
||||||
//if value is empty, try getting the child value instead
|
|
||||||
//as this is how multiline string properties are stored.
|
|
||||||
if(m_stringValue.empty())
|
|
||||||
{
|
|
||||||
m_stringValue = node.child_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_type = Type::String;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (attribData == "color")
|
|
||||||
{
|
|
||||||
m_colourValue = colourFromString(node.attribute(valueAttribute).as_string("#FFFFFFFF"));
|
|
||||||
m_type = Type::Colour;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (attribData == "file")
|
|
||||||
{
|
|
||||||
m_stringValue = node.attribute(valueAttribute).as_string();
|
|
||||||
m_type = Type::File;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (attribData == "object")
|
|
||||||
{
|
|
||||||
m_intValue = node.attribute(valueAttribute).as_int(0);
|
|
||||||
m_type = Type::Object;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,342 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2023
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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 "base64.h"
|
|
||||||
#include "tmxlite/FreeFuncs.hpp"
|
|
||||||
#include "tmxlite/TileLayer.hpp"
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
#ifndef USE_ZLIB
|
|
||||||
# include "tmxlite/detail/gzip.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
|
||||||
#include <zstd.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include <span>
|
|
||||||
|
|
||||||
using namespace tmx;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
struct CompressionType final
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
Zlib, GZip, Zstd, None
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
TileLayer::TileLayer(std::size_t tileCount)
|
|
||||||
: m_tileCount (tileCount)
|
|
||||||
{
|
|
||||||
m_tiles.reserve(tileCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
//public
|
|
||||||
void TileLayer::parse(const pugi::xml_node& node, Map*)
|
|
||||||
{
|
|
||||||
std::string attribName = node.name();
|
|
||||||
if (attribName != "layer")
|
|
||||||
{
|
|
||||||
Logger::log("node not a layer node, skipped parsing", Logger::Type::Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setName(node.attribute("name").as_string());
|
|
||||||
setClass(node.attribute("class").as_string());
|
|
||||||
setOpacity(node.attribute("opacity").as_float(1.f));
|
|
||||||
setVisible(node.attribute("visible").as_bool(true));
|
|
||||||
setOffset(node.attribute("offsetx").as_int(0), node.attribute("offsety").as_int(0));
|
|
||||||
setSize(node.attribute("width").as_uint(0), node.attribute("height").as_uint(0));
|
|
||||||
setParallaxFactor(node.attribute("parallaxx").as_float(1.f), node.attribute("parallaxy").as_float(1.f));
|
|
||||||
|
|
||||||
std::string tintColour = node.attribute("tintcolor").as_string();
|
|
||||||
if (!tintColour.empty())
|
|
||||||
{
|
|
||||||
setTintColour(colourFromString(tintColour));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& child : node.children())
|
|
||||||
{
|
|
||||||
attribName = child.name();
|
|
||||||
if (attribName == "data")
|
|
||||||
{
|
|
||||||
attribName = child.attribute("encoding").as_string();
|
|
||||||
if (attribName == "base64")
|
|
||||||
{
|
|
||||||
parseBase64(child);
|
|
||||||
}
|
|
||||||
else if (attribName == "csv")
|
|
||||||
{
|
|
||||||
parseCSV(child);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parseUnencoded(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (attribName == "properties")
|
|
||||||
{
|
|
||||||
for (const auto& p : child.children())
|
|
||||||
{
|
|
||||||
addProperty(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//private
|
|
||||||
void TileLayer::parseBase64(const pugi::xml_node& node)
|
|
||||||
{
|
|
||||||
auto processDataString = [](std::string dataString, std::size_t tileCount, std::int32_t compressionType)->std::vector<std::uint32_t>
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << dataString;
|
|
||||||
ss >> dataString;
|
|
||||||
dataString = base64_decode(dataString);
|
|
||||||
|
|
||||||
std::size_t expectedSize = tileCount * 4; //4 bytes per tile
|
|
||||||
std::vector<unsigned char> byteData;
|
|
||||||
byteData.reserve(expectedSize);
|
|
||||||
|
|
||||||
switch (compressionType)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
byteData.insert(byteData.end(), dataString.begin(), dataString.end());
|
|
||||||
break;
|
|
||||||
case CompressionType::Zstd:
|
|
||||||
{
|
|
||||||
std::size_t dataSize = dataString.length() * sizeof(unsigned char);
|
|
||||||
std::size_t result = ZSTD_decompress(byteData.data(), expectedSize, &dataString[0], dataSize);
|
|
||||||
|
|
||||||
if (ZSTD_isError(result))
|
|
||||||
{
|
|
||||||
std::string err = ZSTD_getErrorName(result);
|
|
||||||
LOG("Failed to decompress layer data, node skipped.\nError: " + err, Logger::Type::Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CompressionType::GZip:
|
|
||||||
#ifndef USE_ZLIB
|
|
||||||
{
|
|
||||||
byteData.resize(expectedSize);
|
|
||||||
const auto source = std::span(reinterpret_cast<const uint8_t*>(dataString.data()), dataString.size());
|
|
||||||
|
|
||||||
GZipReader reader;
|
|
||||||
if (!reader.OpenMemory(source) || !reader.Read(byteData) || !reader.Check())
|
|
||||||
{
|
|
||||||
LOG("Failed to decompress layer data, node skipped.", Logger::Type::Error);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
//[[fallthrough]];
|
|
||||||
case CompressionType::Zlib:
|
|
||||||
{
|
|
||||||
//unzip
|
|
||||||
std::size_t dataSize = dataString.length() * sizeof(unsigned char);
|
|
||||||
|
|
||||||
if (!decompress(dataString.c_str(), byteData, dataSize, expectedSize))
|
|
||||||
{
|
|
||||||
LOG("Failed to decompress layer data, node skipped.", Logger::Type::Error);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//data stream is in bytes so we need to OR into 32 bit values
|
|
||||||
std::vector<std::uint32_t> IDs;
|
|
||||||
IDs.reserve(tileCount);
|
|
||||||
for (auto i = 0u; i < expectedSize - 3u; i += 4u)
|
|
||||||
{
|
|
||||||
std::uint32_t id = byteData[i] | byteData[i + 1] << 8 | byteData[i + 2] << 16 | byteData[i + 3] << 24;
|
|
||||||
IDs.push_back(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return IDs;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::int32_t compressionType = CompressionType::None;
|
|
||||||
std::string compression = node.attribute("compression").as_string();
|
|
||||||
if (compression == "gzip")
|
|
||||||
{
|
|
||||||
compressionType = CompressionType::GZip;
|
|
||||||
}
|
|
||||||
else if (compression == "zlib")
|
|
||||||
{
|
|
||||||
compressionType = CompressionType::Zlib;
|
|
||||||
}
|
|
||||||
else if (compression == "zstd")
|
|
||||||
{
|
|
||||||
compressionType = CompressionType::Zstd;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string data = node.text().as_string();
|
|
||||||
if (data.empty())
|
|
||||||
{
|
|
||||||
//check for chunk nodes
|
|
||||||
auto dataCount = 0;
|
|
||||||
for (const auto& childNode : node.children())
|
|
||||||
{
|
|
||||||
std::string childName = childNode.name();
|
|
||||||
if (childName == "chunk")
|
|
||||||
{
|
|
||||||
std::string dataString = childNode.text().as_string();
|
|
||||||
if (!dataString.empty())
|
|
||||||
{
|
|
||||||
Chunk chunk;
|
|
||||||
chunk.position.x = childNode.attribute("x").as_int();
|
|
||||||
chunk.position.y = childNode.attribute("y").as_int();
|
|
||||||
|
|
||||||
chunk.size.x = childNode.attribute("width").as_int();
|
|
||||||
chunk.size.y = childNode.attribute("height").as_int();
|
|
||||||
|
|
||||||
auto IDs = processDataString(dataString, (chunk.size.x * chunk.size.y), compressionType);
|
|
||||||
|
|
||||||
if (!IDs.empty())
|
|
||||||
{
|
|
||||||
createTiles(IDs, chunk.tiles);
|
|
||||||
m_chunks.push_back(chunk);
|
|
||||||
dataCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dataCount == 0)
|
|
||||||
{
|
|
||||||
Logger::log("Layer " + getName() + " has no layer data. Layer skipped.", Logger::Type::Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto IDs = processDataString(data, m_tileCount, compressionType);
|
|
||||||
createTiles(IDs, m_tiles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileLayer::parseCSV(const pugi::xml_node& node)
|
|
||||||
{
|
|
||||||
auto processDataString = [](const std::string dataString, std::size_t tileCount)->std::vector<std::uint32_t>
|
|
||||||
{
|
|
||||||
std::vector<std::uint32_t> IDs;
|
|
||||||
IDs.reserve(tileCount);
|
|
||||||
|
|
||||||
const char* ptr = dataString.c_str();
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
char* end;
|
|
||||||
auto res = std::strtoul(ptr, &end, 10);
|
|
||||||
if (end == ptr) break;
|
|
||||||
ptr = end;
|
|
||||||
IDs.push_back(res);
|
|
||||||
if (*ptr == ',') ++ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IDs;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string data = node.text().as_string();
|
|
||||||
if (data.empty())
|
|
||||||
{
|
|
||||||
//check for chunk nodes
|
|
||||||
auto dataCount = 0;
|
|
||||||
for (const auto& childNode : node.children())
|
|
||||||
{
|
|
||||||
std::string childName = childNode.name();
|
|
||||||
if (childName == "chunk")
|
|
||||||
{
|
|
||||||
std::string dataString = childNode.text().as_string();
|
|
||||||
if (!dataString.empty())
|
|
||||||
{
|
|
||||||
Chunk chunk;
|
|
||||||
chunk.position.x = childNode.attribute("x").as_int();
|
|
||||||
chunk.position.y = childNode.attribute("y").as_int();
|
|
||||||
|
|
||||||
chunk.size.x = childNode.attribute("width").as_int();
|
|
||||||
chunk.size.y = childNode.attribute("height").as_int();
|
|
||||||
|
|
||||||
auto IDs = processDataString(dataString, chunk.size.x * chunk.size.y);
|
|
||||||
|
|
||||||
if (!IDs.empty())
|
|
||||||
{
|
|
||||||
createTiles(IDs, chunk.tiles);
|
|
||||||
m_chunks.push_back(chunk);
|
|
||||||
dataCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dataCount == 0)
|
|
||||||
{
|
|
||||||
Logger::log("Layer " + getName() + " has no layer data. Layer skipped.", Logger::Type::Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
createTiles(processDataString(data, m_tileCount), m_tiles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileLayer::parseUnencoded(const pugi::xml_node& node)
|
|
||||||
{
|
|
||||||
std::string attribName;
|
|
||||||
std::vector<std::uint32_t> IDs;
|
|
||||||
IDs.reserve(m_tileCount);
|
|
||||||
|
|
||||||
for (const auto& child : node.children())
|
|
||||||
{
|
|
||||||
attribName = child.name();
|
|
||||||
if (attribName == "tile")
|
|
||||||
{
|
|
||||||
IDs.push_back(child.attribute("gid").as_uint());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createTiles(IDs, m_tiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TileLayer::createTiles(const std::vector<std::uint32_t>& IDs, std::vector<Tile>& destination)
|
|
||||||
{
|
|
||||||
//LOG(IDs.size() != m_tileCount, "Layer tile count does not match expected size. Found: "
|
|
||||||
// + std::to_string(IDs.size()) + ", expected: " + std::to_string(m_tileCount));
|
|
||||||
|
|
||||||
static const std::uint32_t mask = 0xf0000000;
|
|
||||||
for (const auto& id : IDs)
|
|
||||||
{
|
|
||||||
destination.emplace_back();
|
|
||||||
destination.back().flipFlags = ((id & mask) >> 28);
|
|
||||||
destination.back().ID = id & ~mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,456 +0,0 @@
|
|||||||
/*********************************************************************
|
|
||||||
Matt Marchant 2016 - 2023
|
|
||||||
http://trederia.blogspot.com
|
|
||||||
|
|
||||||
tmxlite - Zlib license.
|
|
||||||
|
|
||||||
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 "tmxlite/Tileset.hpp"
|
|
||||||
#include "tmxlite/FreeFuncs.hpp"
|
|
||||||
#include "tmxlite/detail/Log.hpp"
|
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
using namespace tmx;
|
|
||||||
|
|
||||||
Tileset::Tileset(const std::string& workingDir)
|
|
||||||
: m_workingDir (workingDir),
|
|
||||||
m_firstGID (0),
|
|
||||||
m_spacing (0),
|
|
||||||
m_margin (0),
|
|
||||||
m_tileCount (0),
|
|
||||||
m_columnCount (0),
|
|
||||||
m_objectAlignment (ObjectAlignment::Unspecified),
|
|
||||||
m_transparencyColour (0, 0, 0, 0),
|
|
||||||
m_hasTransparency (false)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//public
|
|
||||||
void Tileset::parse(pugi::xml_node node, Map* map)
|
|
||||||
{
|
|
||||||
assert(map);
|
|
||||||
|
|
||||||
std::string attribString = node.name();
|
|
||||||
if (attribString != "tileset")
|
|
||||||
{
|
|
||||||
Logger::log(attribString + ": not a tileset node! Node will be skipped.", Logger::Type::Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_firstGID = node.attribute("firstgid").as_int();
|
|
||||||
if (m_firstGID == 0)
|
|
||||||
{
|
|
||||||
Logger::log("Invalid first GID in tileset. Tileset node skipped.", Logger::Type::Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pugi::xml_document tsxDoc; //need to keep this in scope
|
|
||||||
if (node.attribute("source"))
|
|
||||||
{
|
|
||||||
//parse TSX doc
|
|
||||||
std::string path = node.attribute("source").as_string();
|
|
||||||
path = resolveFilePath(path, m_workingDir);
|
|
||||||
|
|
||||||
//as the TSX file now dictates the image path, the working
|
|
||||||
//directory is now that of the tsx file
|
|
||||||
auto position = path.find_last_of('/');
|
|
||||||
if (position != std::string::npos)
|
|
||||||
{
|
|
||||||
m_workingDir = path.substr(0, position);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_workingDir = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
//see if doc can be opened
|
|
||||||
auto result = tsxDoc.load_file(path.c_str());
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
Logger::log(path + ": Failed opening tsx file for tile set, tile set will be skipped", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
//if it can then replace the current node with tsx node
|
|
||||||
node = tsxDoc.child("tileset");
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
Logger::log("tsx file does not contain a tile set node, tile set will be skipped", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_name = node.attribute("name").as_string();
|
|
||||||
LOG("found tile set " + m_name, Logger::Type::Info);
|
|
||||||
m_class = node.attribute("class").as_string();
|
|
||||||
|
|
||||||
m_tileSize.x = node.attribute("tilewidth").as_int();
|
|
||||||
m_tileSize.y = node.attribute("tileheight").as_int();
|
|
||||||
if (m_tileSize.x == 0 || m_tileSize.y == 0)
|
|
||||||
{
|
|
||||||
Logger::log("Invalid tile size found in tile set node. Node will be skipped.", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_spacing = node.attribute("spacing").as_int();
|
|
||||||
m_margin = node.attribute("margin").as_int();
|
|
||||||
m_tileCount = node.attribute("tilecount").as_int();
|
|
||||||
m_columnCount = node.attribute("columns").as_int();
|
|
||||||
|
|
||||||
m_tileIndex.reserve(m_tileCount);
|
|
||||||
m_tiles.reserve(m_tileCount);
|
|
||||||
|
|
||||||
std::string objectAlignment = node.attribute("objectalignment").as_string();
|
|
||||||
if (!objectAlignment.empty())
|
|
||||||
{
|
|
||||||
if (objectAlignment == "unspecified")
|
|
||||||
{
|
|
||||||
m_objectAlignment = ObjectAlignment::Unspecified;
|
|
||||||
}
|
|
||||||
else if (objectAlignment == "topleft")
|
|
||||||
{
|
|
||||||
m_objectAlignment = ObjectAlignment::TopLeft;
|
|
||||||
}
|
|
||||||
else if (objectAlignment == "top")
|
|
||||||
{
|
|
||||||
m_objectAlignment = ObjectAlignment::Top;
|
|
||||||
}
|
|
||||||
else if (objectAlignment == "topright")
|
|
||||||
{
|
|
||||||
m_objectAlignment = ObjectAlignment::TopRight;
|
|
||||||
}
|
|
||||||
else if (objectAlignment == "left")
|
|
||||||
{
|
|
||||||
m_objectAlignment = ObjectAlignment::Left;
|
|
||||||
}
|
|
||||||
else if (objectAlignment == "center")
|
|
||||||
{
|
|
||||||
m_objectAlignment = ObjectAlignment::Center;
|
|
||||||
}
|
|
||||||
else if (objectAlignment == "right")
|
|
||||||
{
|
|
||||||
m_objectAlignment = ObjectAlignment::Right;
|
|
||||||
}
|
|
||||||
else if (objectAlignment == "bottomleft")
|
|
||||||
{
|
|
||||||
m_objectAlignment = ObjectAlignment::BottomLeft;
|
|
||||||
}
|
|
||||||
else if (objectAlignment == "bottom")
|
|
||||||
{
|
|
||||||
m_objectAlignment = ObjectAlignment::Bottom;
|
|
||||||
}
|
|
||||||
else if (objectAlignment == "bottomright")
|
|
||||||
{
|
|
||||||
m_objectAlignment = ObjectAlignment::BottomRight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& children = node.children();
|
|
||||||
for (const auto& node : children)
|
|
||||||
{
|
|
||||||
std::string name = node.name();
|
|
||||||
if (name == "image")
|
|
||||||
{
|
|
||||||
//TODO this currently doesn't cover embedded images
|
|
||||||
//mostly because I can't figure out how to export them
|
|
||||||
//from the Tiled editor... but also resource handling
|
|
||||||
//should be handled by the renderer, not the parser.
|
|
||||||
attribString = node.attribute("source").as_string();
|
|
||||||
if (attribString.empty())
|
|
||||||
{
|
|
||||||
Logger::log("Tileset image node has missing source property, tile set not loaded", Logger::Type::Error);
|
|
||||||
return reset();
|
|
||||||
}
|
|
||||||
m_imagePath = resolveFilePath(attribString, m_workingDir);
|
|
||||||
if (node.attribute("trans"))
|
|
||||||
{
|
|
||||||
attribString = node.attribute("trans").as_string();
|
|
||||||
m_transparencyColour = colourFromString(attribString);
|
|
||||||
m_hasTransparency = true;
|
|
||||||
}
|
|
||||||
if (node.attribute("width") && node.attribute("height"))
|
|
||||||
{
|
|
||||||
m_imageSize.x = node.attribute("width").as_int();
|
|
||||||
m_imageSize.y = node.attribute("height").as_int();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (name == "tileoffset")
|
|
||||||
{
|
|
||||||
parseOffsetNode(node);
|
|
||||||
}
|
|
||||||
else if (name == "properties")
|
|
||||||
{
|
|
||||||
parsePropertyNode(node);
|
|
||||||
}
|
|
||||||
else if (name == "terraintypes")
|
|
||||||
{
|
|
||||||
parseTerrainNode(node);
|
|
||||||
}
|
|
||||||
else if (name == "tile")
|
|
||||||
{
|
|
||||||
parseTileNode(node, map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if the tsx file does not declare every tile, we create the missing ones
|
|
||||||
if (m_tiles.size() != getTileCount())
|
|
||||||
{
|
|
||||||
for (std::uint32_t ID = 0; ID < getTileCount(); ID++)
|
|
||||||
{
|
|
||||||
createMissingTile(ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint32_t Tileset::getLastGID() const
|
|
||||||
{
|
|
||||||
assert(!m_tileIndex.empty());
|
|
||||||
return m_firstGID + static_cast<std::uint32_t>(m_tileIndex.size()) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Tileset::Tile* Tileset::getTile(std::uint32_t id) const
|
|
||||||
{
|
|
||||||
if (!hasTile(id))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//corrects the ID. Indices and IDs are different.
|
|
||||||
id -= m_firstGID;
|
|
||||||
id = m_tileIndex[id];
|
|
||||||
return id ? &m_tiles[id - 1] : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
//private
|
|
||||||
void Tileset::reset()
|
|
||||||
{
|
|
||||||
m_firstGID = 0;
|
|
||||||
m_source = "";
|
|
||||||
m_name = "";
|
|
||||||
m_class = "";
|
|
||||||
m_tileSize = { 0,0 };
|
|
||||||
m_spacing = 0;
|
|
||||||
m_margin = 0;
|
|
||||||
m_tileCount = 0;
|
|
||||||
m_columnCount = 0;
|
|
||||||
m_objectAlignment = ObjectAlignment::Unspecified;
|
|
||||||
m_tileOffset = { 0,0 };
|
|
||||||
m_properties.clear();
|
|
||||||
m_imagePath = "";
|
|
||||||
m_transparencyColour = { 0, 0, 0, 0 };
|
|
||||||
m_hasTransparency = false;
|
|
||||||
m_terrainTypes.clear();
|
|
||||||
m_tileIndex.clear();
|
|
||||||
m_tiles.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tileset::parseOffsetNode(const pugi::xml_node& node)
|
|
||||||
{
|
|
||||||
m_tileOffset.x = node.attribute("x").as_int();
|
|
||||||
m_tileOffset.y = node.attribute("y").as_int();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tileset::parsePropertyNode(const pugi::xml_node& node)
|
|
||||||
{
|
|
||||||
const auto& children = node.children();
|
|
||||||
for (const auto& child : children)
|
|
||||||
{
|
|
||||||
m_properties.emplace_back();
|
|
||||||
m_properties.back().parse(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tileset::parseTerrainNode(const pugi::xml_node& node)
|
|
||||||
{
|
|
||||||
const auto& children = node.children();
|
|
||||||
for (const auto& child : children)
|
|
||||||
{
|
|
||||||
std::string name = child.name();
|
|
||||||
if (name == "terrain")
|
|
||||||
{
|
|
||||||
m_terrainTypes.emplace_back();
|
|
||||||
auto& terrain = m_terrainTypes.back();
|
|
||||||
terrain.name = child.attribute("name").as_string();
|
|
||||||
terrain.tileID = child.attribute("tile").as_int();
|
|
||||||
auto properties = child.child("properties");
|
|
||||||
if (properties)
|
|
||||||
{
|
|
||||||
for (const auto& p : properties)
|
|
||||||
{
|
|
||||||
name = p.name();
|
|
||||||
if (name == "property")
|
|
||||||
{
|
|
||||||
terrain.properties.emplace_back();
|
|
||||||
terrain.properties.back().parse(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Tileset::Tile& Tileset::newTile(std::uint32_t ID)
|
|
||||||
{
|
|
||||||
Tile& tile = (m_tiles.emplace_back(), m_tiles.back());
|
|
||||||
if (m_tileIndex.size() <= ID)
|
|
||||||
{
|
|
||||||
m_tileIndex.resize(ID + 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_tileIndex[ID] = static_cast<std::uint32_t>(m_tiles.size());
|
|
||||||
tile.ID = ID;
|
|
||||||
return tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tileset::parseTileNode(const pugi::xml_node& node, Map* map)
|
|
||||||
{
|
|
||||||
assert(map);
|
|
||||||
|
|
||||||
Tile& tile = newTile(node.attribute("id").as_int());
|
|
||||||
if (node.attribute("terrain"))
|
|
||||||
{
|
|
||||||
std::string data = node.attribute("terrain").as_string();
|
|
||||||
bool lastWasChar = true;
|
|
||||||
std::size_t idx = 0u;
|
|
||||||
for (auto i = 0u; i < data.size() && idx < tile.terrainIndices.size(); ++i)
|
|
||||||
{
|
|
||||||
if (isdigit(data[i]))
|
|
||||||
{
|
|
||||||
tile.terrainIndices[idx++] = std::atoi(&data[i]);
|
|
||||||
lastWasChar = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!lastWasChar)
|
|
||||||
{
|
|
||||||
lastWasChar = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tile.terrainIndices[idx++] = -1;
|
|
||||||
lastWasChar = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (lastWasChar)
|
|
||||||
{
|
|
||||||
tile.terrainIndices[idx] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tile.probability = node.attribute("probability").as_int(100);
|
|
||||||
|
|
||||||
tile.className = node.attribute("type").as_string();
|
|
||||||
if (tile.className.empty())
|
|
||||||
{
|
|
||||||
tile.className = node.attribute("class").as_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
//by default we set the tile's values as in an Image tileset
|
|
||||||
tile.imagePath = m_imagePath;
|
|
||||||
tile.imageSize = m_tileSize;
|
|
||||||
|
|
||||||
if (m_columnCount != 0)
|
|
||||||
{
|
|
||||||
std::uint32_t rowIndex = tile.ID % m_columnCount;
|
|
||||||
std::uint32_t columnIndex = tile.ID / m_columnCount;
|
|
||||||
tile.imagePosition.x = m_margin + rowIndex * (m_tileSize.x + m_spacing);
|
|
||||||
tile.imagePosition.y = m_margin + columnIndex * (m_tileSize.y + m_spacing);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& children = node.children();
|
|
||||||
for (const auto& child : children)
|
|
||||||
{
|
|
||||||
std::string name = child.name();
|
|
||||||
if (name == "properties")
|
|
||||||
{
|
|
||||||
for (const auto& prop : child.children())
|
|
||||||
{
|
|
||||||
tile.properties.emplace_back();
|
|
||||||
tile.properties.back().parse(prop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (name == "objectgroup")
|
|
||||||
{
|
|
||||||
tile.objectGroup.parse(child, map);
|
|
||||||
}
|
|
||||||
else if (name == "image")
|
|
||||||
{
|
|
||||||
std::string attribString = child.attribute("source").as_string();
|
|
||||||
if (attribString.empty())
|
|
||||||
{
|
|
||||||
Logger::log("Tile image path missing", Logger::Type::Warning);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
tile.imagePath = resolveFilePath(attribString, m_workingDir);
|
|
||||||
|
|
||||||
tile.imagePosition = tmx::Vector2u(0, 0);
|
|
||||||
|
|
||||||
if (child.attribute("trans"))
|
|
||||||
{
|
|
||||||
attribString = child.attribute("trans").as_string();
|
|
||||||
m_transparencyColour = colourFromString(attribString);
|
|
||||||
m_hasTransparency = true;
|
|
||||||
}
|
|
||||||
if (child.attribute("width"))
|
|
||||||
{
|
|
||||||
tile.imageSize.x = child.attribute("width").as_uint();
|
|
||||||
}
|
|
||||||
if (child.attribute("height"))
|
|
||||||
{
|
|
||||||
tile.imageSize.y = child.attribute("height").as_uint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (name == "animation")
|
|
||||||
{
|
|
||||||
for (const auto& frameNode : child.children())
|
|
||||||
{
|
|
||||||
Tile::Animation::Frame frame;
|
|
||||||
frame.duration = frameNode.attribute("duration").as_int();
|
|
||||||
frame.tileID = frameNode.attribute("tileid").as_int() + m_firstGID;
|
|
||||||
tile.animation.frames.push_back(frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Tileset::createMissingTile(std::uint32_t ID)
|
|
||||||
{
|
|
||||||
//first, we check if the tile does not yet exist
|
|
||||||
if (m_tileIndex.size() > ID && m_tileIndex[ID])
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tile& tile = newTile(ID);
|
|
||||||
tile.imagePath = m_imagePath;
|
|
||||||
tile.imageSize = m_tileSize;
|
|
||||||
|
|
||||||
std::uint32_t rowIndex = ID % m_columnCount;
|
|
||||||
std::uint32_t columnIndex = ID / m_columnCount;
|
|
||||||
tile.imagePosition.x = m_margin + rowIndex * (m_tileSize.x + m_spacing);
|
|
||||||
tile.imagePosition.y = m_margin + columnIndex * (m_tileSize.y + m_spacing);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
add_executable(tmx2gba
|
add_executable(tmx2gba
|
||||||
argparse.hpp argparse.cpp
|
argparse.hpp argparse.cpp
|
||||||
|
tmxlayer.hpp
|
||||||
|
tmxobject.hpp
|
||||||
|
tmxtileset.hpp
|
||||||
tmxreader.hpp tmxreader.cpp
|
tmxreader.hpp tmxreader.cpp
|
||||||
convert.hpp convert.cpp
|
convert.hpp convert.cpp
|
||||||
headerwriter.hpp headerwriter.cpp
|
headerwriter.hpp headerwriter.cpp
|
||||||
@@ -18,7 +21,10 @@ 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 tmxlite)
|
target_link_libraries(${PROJECT_NAME} base64::base64 pugixml Zstd::Zstd
|
||||||
|
$<$<TARGET_EXISTS:ZLIB::ZLIB>:ZLIB::ZLIB>
|
||||||
|
$<$<TARGET_EXISTS:miniz::miniz>:miniz::miniz>)
|
||||||
|
target_link_libraries(${PROJECT_NAME} External::rapidxml)
|
||||||
|
|
||||||
if (TMX2GBA_DKP_INSTALL)
|
if (TMX2GBA_DKP_INSTALL)
|
||||||
if (DEFINED ENV{DEVKITPRO})
|
if (DEFINED ENV{DEVKITPRO})
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ template <> constexpr std::string_view DatType<uint8_t>() { return "unsigned cha
|
|||||||
template <> constexpr std::string_view DatType<uint16_t>() { return "unsigned short"; }
|
template <> constexpr std::string_view DatType<uint16_t>() { return "unsigned short"; }
|
||||||
template <> constexpr std::string_view DatType<uint32_t>() { return "unsigned int"; }
|
template <> constexpr std::string_view DatType<uint32_t>() { return "unsigned int"; }
|
||||||
|
|
||||||
void HeaderWriter::WriteSize(unsigned width, unsigned height)
|
void HeaderWriter::WriteSize(int width, int height)
|
||||||
{
|
{
|
||||||
stream << std::endl;
|
stream << std::endl;
|
||||||
WriteDefine(mName + "Width", width);
|
WriteDefine(mName + "Width", width);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public:
|
|||||||
WriteDefine(name, std::to_string(value));
|
WriteDefine(name, std::to_string(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteSize(unsigned width, unsigned height);
|
void WriteSize(int width, int height);
|
||||||
void WriteCharacterMap(const std::span<uint16_t> charData);
|
void WriteCharacterMap(const std::span<uint16_t> charData);
|
||||||
void WriteCollision(const std::span<uint8_t> collisionData);
|
void WriteCollision(const std::span<uint8_t> collisionData);
|
||||||
void WriteObjects(const std::span<uint32_t> objData);
|
void WriteObjects(const std::span<uint32_t> objData);
|
||||||
|
|||||||
34
src/tmxlayer.hpp
Normal file
34
src/tmxlayer.hpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* tmxlayer.hpp - Copyright (C) 2015-2022 a dinosaur (zlib, see COPYING.txt) */
|
||||||
|
|
||||||
|
#ifndef TMXLAYER_HPP
|
||||||
|
#define TMXLAYER_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
class TmxLayer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr uint32_t FLIP_HORZ = 0x80000000;
|
||||||
|
static constexpr uint32_t FLIP_VERT = 0x40000000;
|
||||||
|
static constexpr uint32_t FLIP_DIAG = 0x20000000;
|
||||||
|
static constexpr uint32_t FLIP_MASK = 0xE0000000;
|
||||||
|
|
||||||
|
TmxLayer() : mWidth(0), mHeight(0), mTileDat(nullptr) {}
|
||||||
|
TmxLayer(int aWidth, int aHeight, std::string aName, uint32_t* aTileDat)
|
||||||
|
: mName(std::move(aName)), mWidth(aWidth), mHeight(aHeight), mTileDat(aTileDat) {}
|
||||||
|
inline ~TmxLayer() { delete[] mTileDat; }
|
||||||
|
|
||||||
|
constexpr const std::string& GetName() const { return mName; }
|
||||||
|
constexpr int GetWidth() const { return mWidth; }
|
||||||
|
constexpr int GetHeight() const { return mHeight; }
|
||||||
|
constexpr const uint32_t* GetData() const { return mTileDat; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mName;
|
||||||
|
int mWidth, mHeight;
|
||||||
|
uint32_t* mTileDat;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif//TMXLAYER_HPP
|
||||||
25
src/tmxobject.hpp
Normal file
25
src/tmxobject.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/* tmxobject.hpp - Copyright (C) 2015-2022 a dinosaur (zlib, see COPYING.txt) */
|
||||||
|
|
||||||
|
#ifndef TMXOBJECT_HPP
|
||||||
|
#define TMXOBJECT_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
class TmxObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TmxObject() : mX(0.0f), mY(0.0f) {}
|
||||||
|
TmxObject(std::string aName, float aX, float aY)
|
||||||
|
: mName(std::move(aName)), mX(aX), mY(aY) {}
|
||||||
|
~TmxObject() = default;
|
||||||
|
|
||||||
|
constexpr const std::string& GetName() const { return mName; }
|
||||||
|
inline void GetPos(float& aOutX, float& aOutY) const { aOutX = mX; aOutY = mY; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mName;
|
||||||
|
float mX, mY;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif//TMXOBJECT_HPP
|
||||||
@@ -1,12 +1,191 @@
|
|||||||
/* tmxreader.cpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */
|
/* tmxreader.cpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */
|
||||||
|
|
||||||
#include "tmxreader.hpp"
|
#include "tmxreader.hpp"
|
||||||
#include "tmxlite/Map.hpp"
|
#include "tmxtileset.hpp"
|
||||||
#include "tmxlite/TileLayer.hpp"
|
#include "tmxobject.hpp"
|
||||||
#include "tmxlite/ObjectGroup.hpp"
|
#include "tmxlayer.hpp"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
bool TmxReader::DecodeMap(uint32_t* aOut, size_t aOutSize, const std::string& aBase64Dat)
|
||||||
|
{
|
||||||
|
// Cut leading & trailing whitespace (including newlines)
|
||||||
|
auto beg = std::find_if_not(aBase64Dat.begin(), aBase64Dat.end(), ::isspace);
|
||||||
|
if (beg == std::end(aBase64Dat))
|
||||||
|
return false;
|
||||||
|
auto end = std::find_if_not(aBase64Dat.rbegin(), aBase64Dat.rend(), ::isspace);
|
||||||
|
std::size_t begOff = std::distance(aBase64Dat.begin(), beg);
|
||||||
|
std::size_t endOff = std::distance(end, aBase64Dat.rend()) - begOff;
|
||||||
|
auto trimmed = aBase64Dat.substr(begOff, endOff);
|
||||||
|
|
||||||
|
// Decode base64 string
|
||||||
|
std::string decoded = base64_decode(trimmed);
|
||||||
|
|
||||||
|
// Decompress compressed data
|
||||||
|
auto dstSize = static_cast<mz_ulong>(aOutSize);
|
||||||
|
int res = uncompress(
|
||||||
|
reinterpret_cast<unsigned char*>(aOut),
|
||||||
|
&dstSize,
|
||||||
|
reinterpret_cast<const unsigned char*>(decoded.data()),
|
||||||
|
static_cast<mz_ulong>(decoded.size()));
|
||||||
|
decoded.clear();
|
||||||
|
if (res < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TmxReader::ReadTileset(rapidxml::xml_node<>* aXNode)
|
||||||
|
{
|
||||||
|
rapidxml::xml_attribute<>* xAttrib;
|
||||||
|
|
||||||
|
const char* name = "";
|
||||||
|
const char* source = "";
|
||||||
|
uint32_t firstGid = 0;
|
||||||
|
|
||||||
|
// Read name
|
||||||
|
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()));
|
||||||
|
|
||||||
|
mTilesets.push_back(new TmxTileset(name, source, firstGid));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TmxReader::ReadLayer(rapidxml::xml_node<>* aXNode)
|
||||||
|
{
|
||||||
|
rapidxml::xml_attribute<>* xAttrib;
|
||||||
|
const char* name = "";
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
uint32_t* tileDat = nullptr;
|
||||||
|
|
||||||
|
// Read name
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// TODO: don't assume base64 & zlib
|
||||||
|
tileDat = new uint32_t[width * height];
|
||||||
|
if (!DecodeMap(tileDat, width * height * sizeof(uint32_t), std::string(xData->value())))
|
||||||
|
{
|
||||||
|
delete[] tileDat;
|
||||||
|
tileDat = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mLayers.push_back(new TmxLayer(width, height, name, tileDat));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TmxReader::ReadObjects(rapidxml::xml_node<>* aXNode)
|
||||||
|
{
|
||||||
|
for (auto xNode = aXNode->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());
|
||||||
|
|
||||||
|
mObjects.push_back(new TmxObject(name, x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TmxReader::Open(std::istream& aIn)
|
||||||
|
{
|
||||||
|
// Delete old tilesets
|
||||||
|
for (auto tileset : mTilesets)
|
||||||
|
delete tileset;
|
||||||
|
mTilesets.clear();
|
||||||
|
|
||||||
|
// Delete old layers
|
||||||
|
for (auto layer : mLayers)
|
||||||
|
delete layer;
|
||||||
|
mLayers.clear();
|
||||||
|
|
||||||
|
mGidTable.clear();
|
||||||
|
|
||||||
|
// Read string into a buffer
|
||||||
|
std::stringstream buf;
|
||||||
|
buf << aIn.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;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
if (strcmp(xNode->name(), "layer") == 0)
|
||||||
|
ReadLayer(xNode);
|
||||||
|
else
|
||||||
|
if (strcmp(xNode->name(), "tileset") == 0)
|
||||||
|
ReadTileset(xNode);
|
||||||
|
else
|
||||||
|
if (strcmp(xNode->name(), "objectgroup") == 0)
|
||||||
|
ReadObjects(xNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate global id table
|
||||||
|
for (auto tileset : mTilesets)
|
||||||
|
mGidTable.push_back(tileset->GetFirstGid());
|
||||||
|
std::sort(mGidTable.rbegin(), mGidTable.rend());
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* tmxreader.hpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */
|
/* tmxreader.hpp - Copyright (C) 2015-2022 a dinosaur (zlib, see COPYING.txt) */
|
||||||
|
|
||||||
#ifndef TMXREADER_HPP
|
#ifndef TMXREADER_HPP
|
||||||
#define TMXREADER_HPP
|
#define TMXREADER_HPP
|
||||||
@@ -10,6 +10,11 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <rapidxml/rapidxml.hpp>
|
||||||
|
|
||||||
|
class TmxTileset;
|
||||||
|
class TmxLayer;
|
||||||
|
class TmxObject;
|
||||||
|
|
||||||
class TmxReader
|
class TmxReader
|
||||||
{
|
{
|
||||||
@@ -34,7 +39,7 @@ public:
|
|||||||
const std::string_view paletteName,
|
const std::string_view paletteName,
|
||||||
const std::string_view collisionName,
|
const std::string_view collisionName,
|
||||||
const std::map<std::string, uint32_t>& objMapping);
|
const std::map<std::string, uint32_t>& objMapping);
|
||||||
struct Size { unsigned width, height; };
|
struct Size { int width, height; };
|
||||||
|
|
||||||
[[nodiscard]] constexpr Size GetSize() const { return mSize; }
|
[[nodiscard]] constexpr Size GetSize() const { return mSize; }
|
||||||
[[nodiscard]] constexpr size_t TileCount() const { return
|
[[nodiscard]] constexpr size_t TileCount() const { return
|
||||||
|
|||||||
28
src/tmxtileset.hpp
Normal file
28
src/tmxtileset.hpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/* tmxtileset.hpp - Copyright (C) 2015-2022 a dinosaur (zlib, see COPYING.txt) */
|
||||||
|
|
||||||
|
#ifndef TMXTILESET_HPP
|
||||||
|
#define TMXTILESET_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
class TmxTileset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TmxTileset() : mFirstGid(0) {}
|
||||||
|
TmxTileset(std::string aName, std::string aSource, uint32_t aFirstGid)
|
||||||
|
: mName(std::move(aName)), mSource(std::move(aSource)), mFirstGid(aFirstGid) {}
|
||||||
|
~TmxTileset() = default;
|
||||||
|
|
||||||
|
constexpr const std::string& GetName() const { return mName; }
|
||||||
|
constexpr const std::string& GetSource() const { return mSource; }
|
||||||
|
constexpr uint32_t GetFirstGid() const { return mFirstGid; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mName;
|
||||||
|
std::string mSource;
|
||||||
|
uint32_t mFirstGid;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif//TMXTILESET_HPP
|
||||||
Reference in New Issue
Block a user