mirror of
https://github.com/ScrelliCopter/tmx2gba.git
synced 2025-02-21 03:29:25 +11:00
port to tmxlite
This commit is contained in:
@@ -11,9 +11,8 @@ if (ASAN)
|
||||
endif()
|
||||
|
||||
# Libraries
|
||||
add_subdirectory(ext/base64)
|
||||
add_subdirectory(ext/miniz)
|
||||
add_subdirectory(ext/rapidxml)
|
||||
set(TMXLITE_STATIC_LIB ON)
|
||||
add_subdirectory(ext/tmxlite)
|
||||
|
||||
# Main tmx2gba sources
|
||||
add_subdirectory(src)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
add_library(base64
|
||||
base64.cpp base64.h)
|
||||
add_library(External::base64 ALIAS base64)
|
||||
target_include_directories(base64
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@@ -1,282 +0,0 @@
|
||||
/*
|
||||
base64.cpp and base64.h
|
||||
|
||||
base64 encoding and decoding with C++.
|
||||
More information at
|
||||
https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
|
||||
|
||||
Version: 2.rc.08 (release candidate)
|
||||
|
||||
Copyright (C) 2004-2017, 2020, 2021 René Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author 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 source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
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 source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
*/
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
//
|
||||
// Depending on the url parameter in base64_chars, one of
|
||||
// two sets of base64 characters needs to be chosen.
|
||||
// They differ in their last two characters.
|
||||
//
|
||||
static const char* base64_chars[2] = {
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789"
|
||||
"+/",
|
||||
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789"
|
||||
"-_"};
|
||||
|
||||
static unsigned int pos_of_char(const unsigned char chr) {
|
||||
//
|
||||
// Return the position of chr within base64_encode()
|
||||
//
|
||||
|
||||
if (chr >= 'A' && chr <= 'Z') return chr - 'A';
|
||||
else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1;
|
||||
else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
|
||||
else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
|
||||
else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_'
|
||||
else
|
||||
//
|
||||
// 2020-10-23: Throw std::exception rather than const char*
|
||||
//(Pablo Martin-Gomez, https://github.com/Bouska)
|
||||
//
|
||||
throw std::runtime_error("Input is not valid base64-encoded data.");
|
||||
}
|
||||
|
||||
static std::string insert_linebreaks(std::string str, size_t distance) {
|
||||
//
|
||||
// Provided by https://github.com/JomaCorpFX, adapted by me.
|
||||
//
|
||||
if (!str.length()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
size_t pos = distance;
|
||||
|
||||
while (pos < str.size()) {
|
||||
str.insert(pos, "\n");
|
||||
pos += distance + 1;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename String, unsigned int line_length>
|
||||
static std::string encode_with_line_breaks(String s) {
|
||||
return insert_linebreaks(base64_encode(s, false), line_length);
|
||||
}
|
||||
|
||||
template <typename String>
|
||||
static std::string encode_pem(String s) {
|
||||
return encode_with_line_breaks<String, 64>(s);
|
||||
}
|
||||
|
||||
template <typename String>
|
||||
static std::string encode_mime(String s) {
|
||||
return encode_with_line_breaks<String, 76>(s);
|
||||
}
|
||||
|
||||
template <typename String>
|
||||
static std::string encode(String s, bool url) {
|
||||
return base64_encode(reinterpret_cast<const unsigned char*>(s.data()), s.length(), url);
|
||||
}
|
||||
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) {
|
||||
|
||||
size_t len_encoded = (in_len +2) / 3 * 4;
|
||||
|
||||
unsigned char trailing_char = url ? '.' : '=';
|
||||
|
||||
//
|
||||
// Choose set of base64 characters. They differ
|
||||
// for the last two positions, depending on the url
|
||||
// parameter.
|
||||
// A bool (as is the parameter url) is guaranteed
|
||||
// to evaluate to either 0 or 1 in C++ therefore,
|
||||
// the correct character set is chosen by subscripting
|
||||
// base64_chars with url.
|
||||
//
|
||||
const char* base64_chars_ = base64_chars[url];
|
||||
|
||||
std::string ret;
|
||||
ret.reserve(len_encoded);
|
||||
|
||||
unsigned int pos = 0;
|
||||
|
||||
while (pos < in_len) {
|
||||
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
|
||||
|
||||
if (pos+1 < in_len) {
|
||||
ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
|
||||
|
||||
if (pos+2 < in_len) {
|
||||
ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
|
||||
ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]);
|
||||
}
|
||||
else {
|
||||
ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
|
||||
ret.push_back(trailing_char);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
|
||||
ret.push_back(trailing_char);
|
||||
ret.push_back(trailing_char);
|
||||
}
|
||||
|
||||
pos += 3;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename String>
|
||||
static std::string decode(String encoded_string, bool remove_linebreaks) {
|
||||
//
|
||||
// decode(…) is templated so that it can be used with String = const std::string&
|
||||
// or std::string_view (requires at least C++17)
|
||||
//
|
||||
|
||||
if (encoded_string.empty()) return std::string();
|
||||
|
||||
if (remove_linebreaks) {
|
||||
|
||||
std::string copy(encoded_string);
|
||||
|
||||
copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end());
|
||||
|
||||
return base64_decode(copy, false);
|
||||
}
|
||||
|
||||
size_t length_of_string = encoded_string.length();
|
||||
size_t pos = 0;
|
||||
|
||||
//
|
||||
// The approximate length (bytes) of the decoded string might be one or
|
||||
// two bytes smaller, depending on the amount of trailing equal signs
|
||||
// in the encoded string. This approximation is needed to reserve
|
||||
// enough space in the string to be returned.
|
||||
//
|
||||
size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
|
||||
std::string ret;
|
||||
ret.reserve(approx_length_of_decoded_string);
|
||||
|
||||
while (pos < length_of_string) {
|
||||
//
|
||||
// Iterate over encoded input string in chunks. The size of all
|
||||
// chunks except the last one is 4 bytes.
|
||||
//
|
||||
// The last chunk might be padded with equal signs or dots
|
||||
// in order to make it 4 bytes in size as well, but this
|
||||
// is not required as per RFC 2045.
|
||||
//
|
||||
// All chunks except the last one produce three output bytes.
|
||||
//
|
||||
// The last chunk produces at least one and up to three bytes.
|
||||
//
|
||||
|
||||
size_t pos_of_char_1 = pos_of_char(encoded_string[pos+1] );
|
||||
|
||||
//
|
||||
// Emit the first output byte that is produced in each chunk:
|
||||
//
|
||||
ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char(encoded_string[pos+0]) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4)));
|
||||
|
||||
if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045)
|
||||
encoded_string[pos+2] != '=' &&
|
||||
encoded_string[pos+2] != '.' // accept URL-safe base 64 strings, too, so check for '.' also.
|
||||
)
|
||||
{
|
||||
//
|
||||
// Emit a chunk's second byte (which might not be produced in the last chunk).
|
||||
//
|
||||
unsigned int pos_of_char_2 = pos_of_char(encoded_string[pos+2] );
|
||||
ret.push_back(static_cast<std::string::value_type>( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2)));
|
||||
|
||||
if ( ( pos + 3 < length_of_string ) &&
|
||||
encoded_string[pos+3] != '=' &&
|
||||
encoded_string[pos+3] != '.'
|
||||
)
|
||||
{
|
||||
//
|
||||
// Emit a chunk's third byte (which might not be produced in the last chunk).
|
||||
//
|
||||
ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string[pos+3]) ));
|
||||
}
|
||||
}
|
||||
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string base64_decode(std::string const& s, bool remove_linebreaks) {
|
||||
return decode(s, remove_linebreaks);
|
||||
}
|
||||
|
||||
std::string base64_encode(std::string const& s, bool url) {
|
||||
return encode(s, url);
|
||||
}
|
||||
|
||||
std::string base64_encode_pem (std::string const& s) {
|
||||
return encode_pem(s);
|
||||
}
|
||||
|
||||
std::string base64_encode_mime(std::string const& s) {
|
||||
return encode_mime(s);
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
//
|
||||
// Interface with std::string_view rather than const std::string&
|
||||
// Requires C++17
|
||||
// Provided by Yannic Bonenberger (https://github.com/Yannic)
|
||||
//
|
||||
|
||||
std::string base64_encode(std::string_view s, bool url) {
|
||||
return encode(s, url);
|
||||
}
|
||||
|
||||
std::string base64_encode_pem(std::string_view s) {
|
||||
return encode_pem(s);
|
||||
}
|
||||
|
||||
std::string base64_encode_mime(std::string_view s) {
|
||||
return encode_mime(s);
|
||||
}
|
||||
|
||||
std::string base64_decode(std::string_view s, bool remove_linebreaks) {
|
||||
return decode(s, remove_linebreaks);
|
||||
}
|
||||
|
||||
#endif // __cplusplus >= 201703L
|
||||
@@ -1,35 +0,0 @@
|
||||
//
|
||||
// base64 encoding and decoding with C++.
|
||||
// Version: 2.rc.08 (release candidate)
|
||||
//
|
||||
|
||||
#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
|
||||
#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
|
||||
|
||||
#include <string>
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#include <string_view>
|
||||
#endif // __cplusplus >= 201703L
|
||||
|
||||
std::string base64_encode (std::string const& s, bool url = false);
|
||||
std::string base64_encode_pem (std::string const& s);
|
||||
std::string base64_encode_mime(std::string const& s);
|
||||
|
||||
std::string base64_decode(std::string const& s, bool remove_linebreaks = false);
|
||||
std::string base64_encode(unsigned char const*, size_t len, bool url = false);
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
//
|
||||
// Interface with std::string_view rather than const std::string&
|
||||
// Requires C++17
|
||||
// Provided by Yannic Bonenberger (https://github.com/Yannic)
|
||||
//
|
||||
std::string base64_encode (std::string_view s, bool url = false);
|
||||
std::string base64_encode_pem (std::string_view s);
|
||||
std::string base64_encode_mime(std::string_view s);
|
||||
|
||||
std::string base64_decode(std::string_view s, bool remove_linebreaks = false);
|
||||
#endif // __cplusplus >= 201703L
|
||||
|
||||
#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */
|
||||
@@ -1,4 +0,0 @@
|
||||
add_library(rapidxml INTERFACE)
|
||||
add_library(External::rapidxml ALIAS rapidxml)
|
||||
target_include_directories(rapidxml
|
||||
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@@ -1,52 +0,0 @@
|
||||
Use of this software is granted under one of the following two licenses,
|
||||
to be chosen freely by the user.
|
||||
|
||||
1. Boost Software License - Version 1.0 - August 17th, 2003
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2006, 2007 Marcin Kalicinski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
2. The MIT License
|
||||
===============================================================================
|
||||
|
||||
Copyright (c) 2006, 2007 Marcin Kalicinski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,174 +0,0 @@
|
||||
#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
#define RAPIDXML_ITERATORS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_iterators.hpp This file contains rapidxml iterators
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Iterator of child nodes of xml_node
|
||||
template<class Ch>
|
||||
class node_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_node<Ch> value_type;
|
||||
typedef typename xml_node<Ch> &reference;
|
||||
typedef typename xml_node<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
node_iterator()
|
||||
: m_node(0)
|
||||
{
|
||||
}
|
||||
|
||||
node_iterator(xml_node<Ch> *node)
|
||||
: m_node(node->first_node())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_node);
|
||||
return *m_node;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_node);
|
||||
return m_node;
|
||||
}
|
||||
|
||||
node_iterator& operator++()
|
||||
{
|
||||
assert(m_node);
|
||||
m_node = m_node->next_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator++(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
node_iterator& operator--()
|
||||
{
|
||||
assert(m_node && m_node->previous_sibling());
|
||||
m_node = m_node->previous_sibling();
|
||||
return *this;
|
||||
}
|
||||
|
||||
node_iterator operator--(int)
|
||||
{
|
||||
node_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node == rhs.m_node;
|
||||
}
|
||||
|
||||
bool operator !=(const node_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_node != rhs.m_node;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_node<Ch> *m_node;
|
||||
|
||||
};
|
||||
|
||||
//! Iterator of child attributes of xml_node
|
||||
template<class Ch>
|
||||
class attribute_iterator
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename xml_attribute<Ch> value_type;
|
||||
typedef typename xml_attribute<Ch> &reference;
|
||||
typedef typename xml_attribute<Ch> *pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::bidirectional_iterator_tag iterator_category;
|
||||
|
||||
attribute_iterator()
|
||||
: m_attribute(0)
|
||||
{
|
||||
}
|
||||
|
||||
attribute_iterator(xml_node<Ch> *node)
|
||||
: m_attribute(node->first_attribute())
|
||||
{
|
||||
}
|
||||
|
||||
reference operator *() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return *m_attribute;
|
||||
}
|
||||
|
||||
pointer operator->() const
|
||||
{
|
||||
assert(m_attribute);
|
||||
return m_attribute;
|
||||
}
|
||||
|
||||
attribute_iterator& operator++()
|
||||
{
|
||||
assert(m_attribute);
|
||||
m_attribute = m_attribute->next_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator++(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
attribute_iterator& operator--()
|
||||
{
|
||||
assert(m_attribute && m_attribute->previous_attribute());
|
||||
m_attribute = m_attribute->previous_attribute();
|
||||
return *this;
|
||||
}
|
||||
|
||||
attribute_iterator operator--(int)
|
||||
{
|
||||
attribute_iterator tmp = *this;
|
||||
++this;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator ==(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute == rhs.m_attribute;
|
||||
}
|
||||
|
||||
bool operator !=(const attribute_iterator<Ch> &rhs)
|
||||
{
|
||||
return m_attribute != rhs.m_attribute;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
xml_attribute<Ch> *m_attribute;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,421 +0,0 @@
|
||||
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
// Only include streams if not disabled
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Printing flags
|
||||
|
||||
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Internal
|
||||
|
||||
//! \cond internal
|
||||
namespace internal
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal character operations
|
||||
|
||||
// Copy characters from given range to given output iterator
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
*out++ = *begin++;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Copy characters from given range to given output iterator and expand
|
||||
// characters into references (< > ' " &)
|
||||
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
|
||||
@@ -1,122 +0,0 @@
|
||||
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
|
||||
#define RAPIDXML_UTILS_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
|
||||
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
//! Represents data loaded from a file
|
||||
template<class Ch = char>
|
||||
class file
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
|
||||
//! \param filename Filename to load.
|
||||
file(const char *filename)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Open stream
|
||||
basic_ifstream<Ch> stream(filename, ios::binary);
|
||||
if (!stream)
|
||||
throw runtime_error(string("cannot open file ") + filename);
|
||||
stream.unsetf(ios::skipws);
|
||||
|
||||
// Determine stream size
|
||||
stream.seekg(0, ios::end);
|
||||
size_t size = stream.tellg();
|
||||
stream.seekg(0);
|
||||
|
||||
// Load data and add terminating 0
|
||||
m_data.resize(size + 1);
|
||||
stream.read(&m_data.front(), static_cast<streamsize>(size));
|
||||
m_data[size] = 0;
|
||||
}
|
||||
|
||||
//! Loads file into the memory. Data will be automatically destroyed by the destructor
|
||||
//! \param stream Stream to load from
|
||||
file(std::basic_istream<Ch> &stream)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// Load data and add terminating 0
|
||||
stream.unsetf(ios::skipws);
|
||||
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
|
||||
if (stream.fail() || stream.bad())
|
||||
throw runtime_error("error reading stream");
|
||||
m_data.push_back(0);
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
Ch *data()
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data.
|
||||
//! \return Pointer to data of file.
|
||||
const Ch *data() const
|
||||
{
|
||||
return &m_data.front();
|
||||
}
|
||||
|
||||
//! Gets file data size.
|
||||
//! \return Size of file data, in characters.
|
||||
std::size_t size() const
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Ch> m_data; // File data
|
||||
|
||||
};
|
||||
|
||||
//! Counts children of node. Time complexity is O(n).
|
||||
//! \return Number of children of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_children(xml_node<Ch> *node)
|
||||
{
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
std::size_t count = 0;
|
||||
while (child)
|
||||
{
|
||||
++count;
|
||||
child = child->next_sibling();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
//! Counts attributes of node. Time complexity is O(n).
|
||||
//! \return Number of attributes of node
|
||||
template<class Ch>
|
||||
inline std::size_t count_attributes(xml_node<Ch> *node)
|
||||
{
|
||||
xml_attribute<Ch> *attr = node->first_attribute();
|
||||
std::size_t count = 0;
|
||||
while (attr)
|
||||
{
|
||||
++count;
|
||||
attr = attr->next_attribute();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
131
ext/tmxlite/CMakeLists.txt
Normal file
131
ext/tmxlite/CMakeLists.txt
Normal file
@@ -0,0 +1,131 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(tmxlite VERSION 1.3.1)
|
||||
SET(PROJECT_NAME tmxlite)
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
|
||||
|
||||
if(NOT TMXLITE_STATIC_LIB)
|
||||
SET(TMXLITE_STATIC_LIB FALSE CACHE BOOL "Should tmxlite be built as a static or shared lib?")
|
||||
endif()
|
||||
|
||||
SET(PROJECT_STATIC_RUNTIME FALSE CACHE BOOL "Use statically linked standard/runtime libraries?")
|
||||
#option(BUILD_DOC "Build documentation" OFF)
|
||||
|
||||
SET(USE_RTTI TRUE CACHE BOOL "Use run time type information?")
|
||||
|
||||
SET(USE_EXTLIBS FALSE CACHE BOOL "Use external zlib, zstd and pugixml libraries instead of the included source?")
|
||||
SET(USE_ZSTD FALSE CACHE BOOL "Enable zstd compression? (Already set to true if USE_EXTLIBS is true)")
|
||||
|
||||
if(USE_RTTI)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR APPLE)
|
||||
if(PROJECT_STATIC_RUNTIME)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -static")
|
||||
else()
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR APPLE)
|
||||
if(PROJECT_STATIC_RUNTIME)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-rtti -static")
|
||||
else()
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-rtti")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(TMXLITE_STATIC_LIB)
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -D_DEBUG_ -DTMXLITE_STATIC")
|
||||
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG -DTMXLITE_STATIC")
|
||||
SET(CMAKE_DEBUG_POSTFIX -s-d)
|
||||
SET(CMAKE_RELEASE_POSTFIX -s)
|
||||
else()
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -D_DEBUG_")
|
||||
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG")
|
||||
SET(CMAKE_DEBUG_POSTFIX -d)
|
||||
endif()
|
||||
|
||||
#disable msvc warning
|
||||
if(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
|
||||
#includes the list of source files in the src directory
|
||||
SET(PROJECT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
include(${PROJECT_DIR}/CMakeLists.txt)
|
||||
|
||||
#if we want external zip and xml libs find them and tell the compiler
|
||||
if(USE_EXTLIBS)
|
||||
add_definitions(-DUSE_EXTLIBS)
|
||||
add_definitions(-DUSE_ZSTD)
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(PUGIXML REQUIRED)
|
||||
find_package(Zstd REQUIRED)
|
||||
|
||||
include_directories(${ZLIB_INCLUDE_DIRS} ${PUGIXML_INCLUDE_DIR} ${ZSTD_INCLUDE_DIR})
|
||||
|
||||
else()
|
||||
#add miniz and pugixml from source
|
||||
SET(PROJECT_SRC ${PROJECT_SRC} ${LIB_SRC})
|
||||
|
||||
if(USE_ZSTD)
|
||||
add_definitions(-DUSE_ZSTD)
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
|
||||
find_package(Zstd REQUIRED)
|
||||
include_directories(${ZSTD_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
if(TMXLITE_STATIC_LIB)
|
||||
add_library(${PROJECT_NAME} STATIC ${PROJECT_SRC})
|
||||
else()
|
||||
add_library(${PROJECT_NAME} SHARED ${PROJECT_SRC})
|
||||
endif()
|
||||
else()
|
||||
if(TMXLITE_STATIC_LIB)
|
||||
add_library(${PROJECT_NAME} STATIC ${PROJECT_SRC})
|
||||
else()
|
||||
add_library(${PROJECT_NAME} SHARED ${PROJECT_SRC})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_EXTLIBS)
|
||||
target_link_libraries(${PROJECT_NAME} ${ZLIB_LIBRARIES} ${PUGIXML_LIBRARY} ${ZSTD_LIBRARY})
|
||||
else()
|
||||
if(USE_ZSTD)
|
||||
target_link_libraries(${PROJECT_NAME} ${ZSTD_LIBRARY})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tmxlite.pc.in ${CMAKE_CURRENT_BINARY_DIR}/tmxlite.pc
|
||||
@ONLY)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/tmxlite DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
if(TMXLITE_STATIC_LIB)
|
||||
install(TARGETS ${PROJECT_NAME} EXPORT tmxlite-targets DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
else()
|
||||
install(TARGETS ${PROJECT_NAME} EXPORT tmxlite-targets
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/tmxlite.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
COMPONENT libraries)
|
||||
10
ext/tmxlite/cmake/modules/FindPUGIXML.cmake
Normal file
10
ext/tmxlite/cmake/modules/FindPUGIXML.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
find_path(PUGIXML_INCLUDE_DIR NAMES pugixml.hpp)
|
||||
find_library(PUGIXML_LIBRARY NAMES pugixml)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(PUGIXML DEFAULT_MSG
|
||||
PUGIXML_LIBRARY PUGIXML_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(PUGIXML_INCLUDE_DIR
|
||||
PUGIXML_LIBRARY)
|
||||
|
||||
10
ext/tmxlite/cmake/modules/FindTMXLITE.cmake
Normal file
10
ext/tmxlite/cmake/modules/FindTMXLITE.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
# Search for the header file
|
||||
find_path(TMXLITE_INCLUDE_DIR NAMES tmxlite/Config.hpp PATH_SUFFIXES include)
|
||||
|
||||
# Search for the library
|
||||
find_library(TMXLITE_LIBRARIES NAMES tmxlite PATH_SUFFIXES lib)
|
||||
|
||||
# Did we find everything we need?
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(tmxlite DEFAULT_MSG TMXLITE_LIBRARIES TMXLITE_INCLUDE_DIR)
|
||||
41
ext/tmxlite/cmake/modules/FindZstd.cmake
Normal file
41
ext/tmxlite/cmake/modules/FindZstd.cmake
Normal file
@@ -0,0 +1,41 @@
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#
|
||||
# - Try to find Facebook zstd library
|
||||
# This will define
|
||||
# ZSTD_FOUND
|
||||
# ZSTD_INCLUDE_DIR
|
||||
# ZSTD_LIBRARY
|
||||
#
|
||||
|
||||
find_path(ZSTD_INCLUDE_DIR NAMES zstd.h)
|
||||
|
||||
find_library(ZSTD_LIBRARY_DEBUG NAMES zstdd zstd_staticd)
|
||||
find_library(ZSTD_LIBRARY_RELEASE NAMES zstd zstd_static)
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
SELECT_LIBRARY_CONFIGURATIONS(ZSTD)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(
|
||||
ZSTD DEFAULT_MSG
|
||||
ZSTD_LIBRARY ZSTD_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if (ZSTD_FOUND)
|
||||
message(STATUS "Found Zstd: ${ZSTD_LIBRARY}")
|
||||
endif()
|
||||
|
||||
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
|
||||
188
ext/tmxlite/cmake/toolchains/ios.toolchain.cmake
Normal file
188
ext/tmxlite/cmake/toolchains/ios.toolchain.cmake
Normal file
@@ -0,0 +1,188 @@
|
||||
# Copyright (c) 2016, Bogdan Cristea <cristeab@gmail.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake
|
||||
# files which are included with CMake 2.8.4
|
||||
# It has been altered for iOS development
|
||||
|
||||
# Options:
|
||||
#
|
||||
# IOS_PLATFORM = OS (default) or SIMULATOR
|
||||
# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
|
||||
# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
|
||||
# SIMULATOR - used to build for the Simulator platforms, which have an x86_64 arch.
|
||||
#
|
||||
# IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
|
||||
# By default this location is automatcially chosen based on the IOS_PLATFORM value above.
|
||||
# If set manually, it will override the default location and force the user of a particular Developer Platform
|
||||
#
|
||||
# IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
|
||||
# By default this location is automatcially chosen based on the IOS_DEVELOPER_ROOT value.
|
||||
# In this case it will always be the most up-to-date SDK found in the IOS_DEVELOPER_ROOT path.
|
||||
# If set manually, this will force the use of a specific SDK version
|
||||
|
||||
# Macros:
|
||||
#
|
||||
# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE)
|
||||
# A convenience macro for setting xcode specific properties on targets
|
||||
# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1")
|
||||
#
|
||||
# find_host_package (PROGRAM ARGS)
|
||||
# A macro used to find executable programs on the host system, not within the iOS environment.
|
||||
# Thanks to the android-cmake project for providing the command
|
||||
|
||||
# Standard settings
|
||||
set (CMAKE_SYSTEM_NAME Darwin)
|
||||
set (CMAKE_SYSTEM_VERSION 1)
|
||||
set (UNIX True)
|
||||
set (APPLE True)
|
||||
set (IOS True)
|
||||
|
||||
# Required as of cmake 2.8.10
|
||||
set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
|
||||
|
||||
# Determine the cmake host system version so we know where to find the iOS SDKs
|
||||
find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
|
||||
if (CMAKE_UNAME)
|
||||
exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
|
||||
string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
|
||||
endif (CMAKE_UNAME)
|
||||
|
||||
set(CMAKE_C_COMPILER /usr/bin/clang CACHE FILEPATH "" FORCE)
|
||||
set(CMAKE_CXX_COMPILER /usr/bin/clang++ CACHE FILEPATH "" FORCE)
|
||||
set(CMAKE_AR ar CACHE FILEPATH "" FORCE)
|
||||
|
||||
# Skip the platform compiler checks for cross compiling
|
||||
set (CMAKE_CXX_COMPILER_WORKS TRUE)
|
||||
set (CMAKE_C_COMPILER_WORKS TRUE)
|
||||
|
||||
# All iOS/Darwin specific settings - some may be redundant
|
||||
set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
|
||||
set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
|
||||
set (CMAKE_SHARED_MODULE_PREFIX "lib")
|
||||
set (CMAKE_SHARED_MODULE_SUFFIX ".so")
|
||||
set (CMAKE_MODULE_EXISTS 1)
|
||||
set (CMAKE_DL_LIBS "")
|
||||
|
||||
set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
|
||||
set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
|
||||
set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
|
||||
set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
|
||||
|
||||
# Hidden visibilty is required for cxx on iOS
|
||||
set (CMAKE_C_FLAGS_INIT "")
|
||||
set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden")
|
||||
|
||||
set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
|
||||
set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
|
||||
|
||||
set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
|
||||
set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
|
||||
set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
|
||||
set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
|
||||
set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
|
||||
set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
|
||||
|
||||
# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
|
||||
# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
|
||||
# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
|
||||
# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
|
||||
if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
|
||||
find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
|
||||
endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
|
||||
|
||||
# Setup iOS platform unless specified manually with IOS_PLATFORM
|
||||
if (NOT DEFINED IOS_PLATFORM)
|
||||
set (IOS_PLATFORM "OS")
|
||||
endif (NOT DEFINED IOS_PLATFORM)
|
||||
set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform: OS or SIMULATOR")
|
||||
|
||||
# Check the platform selection and setup for developer root
|
||||
if (IOS_PLATFORM STREQUAL OS)
|
||||
set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
|
||||
elseif (IOS_PLATFORM STREQUAL SIMULATOR)
|
||||
set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
|
||||
else ()
|
||||
message (FATAL_ERROR "Unsupported IOS_PLATFORM value '${IOS_PLATFORM}' selected. Please choose OS or SIMULATOR")
|
||||
endif ()
|
||||
|
||||
# Setup iOS developer location unless specified manually with IOS_DEVELOPER_ROOT
|
||||
exec_program(/usr/bin/xcode-select ARGS -print-path OUTPUT_VARIABLE XCODE_DEVELOPER_DIR)
|
||||
set (IOS_DEVELOPER_ROOT "${XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer" CACHE PATH "Location of iOS Platform")
|
||||
|
||||
# Find and use the most recent iOS sdk unless specified manually with IOS_SDK_ROOT
|
||||
if (NOT DEFINED IOS_SDK_ROOT)
|
||||
file (GLOB _IOS_SDKS "${IOS_DEVELOPER_ROOT}/SDKs/*")
|
||||
if (_IOS_SDKS)
|
||||
list (SORT _IOS_SDKS)
|
||||
list (REVERSE _IOS_SDKS)
|
||||
list (GET _IOS_SDKS 0 IOS_SDK_ROOT)
|
||||
else (_IOS_SDKS)
|
||||
message (FATAL_ERROR "No iOS SDK's found in default search path ${IOS_DEVELOPER_ROOT}. Manually set IOS_SDK_ROOT or install the iOS SDK.")
|
||||
endif (_IOS_SDKS)
|
||||
message (STATUS "Toolchain using default iOS SDK: ${IOS_SDK_ROOT}")
|
||||
endif (NOT DEFINED IOS_SDK_ROOT)
|
||||
set (IOS_SDK_ROOT ${IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
|
||||
|
||||
# Set the sysroot default to the most recent SDK
|
||||
set (CMAKE_OSX_SYSROOT ${IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
|
||||
|
||||
# set the architecture for iOS
|
||||
if (${IOS_PLATFORM} STREQUAL OS)
|
||||
set (OSX_UNIVERSAL true)
|
||||
set (IOS_ARCH arm64)
|
||||
elseif (${IOS_PLATFORM} STREQUAL SIMULATOR)
|
||||
set (IOS_ARCH x86_64)
|
||||
endif (${IOS_PLATFORM} STREQUAL OS)
|
||||
|
||||
set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING "Build architecture for iOS" FORCE)
|
||||
|
||||
# Set the find root to the iOS developer roots and to user defined paths
|
||||
set (CMAKE_FIND_ROOT_PATH ${IOS_DEVELOPER_ROOT} ${IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE STRING "iOS find search path root")
|
||||
|
||||
# default to searching for frameworks first
|
||||
set (CMAKE_FIND_FRAMEWORK FIRST)
|
||||
|
||||
# set up the default search directories for frameworks
|
||||
set (CMAKE_SYSTEM_FRAMEWORK_PATH
|
||||
${IOS_SDK_ROOT}/System/Library/Frameworks
|
||||
${IOS_SDK_ROOT}/System/Library/PrivateFrameworks
|
||||
${IOS_SDK_ROOT}/Developer/Library/Frameworks
|
||||
)
|
||||
|
||||
# only search the iOS sdks, not the remainder of the host filesystem
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
|
||||
# This macro lets you find executable programs on the host system
|
||||
macro (find_host_package)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
|
||||
set (IOS FALSE)
|
||||
|
||||
find_package(${ARGN})
|
||||
|
||||
set (IOS TRUE)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
endmacro (find_host_package)
|
||||
64
ext/tmxlite/include/tmxlite/Config.hpp
Normal file
64
ext/tmxlite/include/tmxlite/Config.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*********************************************************************
|
||||
(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
|
||||
|
||||
//check which platform we're on and create export macros as necessary
|
||||
#if !defined(TMXLITE_STATIC)
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
//windows compilers need specific (and different) keywords for export
|
||||
#define TMXLITE_EXPORT_API __declspec(dllexport)
|
||||
|
||||
//for vc compilers we also need to turn off this annoying C4251 warning
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4251)
|
||||
#endif //_MSC_VER
|
||||
|
||||
#else //linux, FreeBSD, Mac OS X
|
||||
|
||||
#if __GNUC__ >= 4
|
||||
|
||||
//gcc 4 has special keywords for showing/hiding symbols,
|
||||
//the same keyword is used for both importing and exporting
|
||||
#define TMXLITE_EXPORT_API __attribute__ ((__visibility__ ("default")))
|
||||
|
||||
#else
|
||||
|
||||
//gcc < 4 has no mechanism to explicitly hide symbols, everything's exported
|
||||
#define TMXLITE_EXPORT_API
|
||||
#endif //__GNUC__
|
||||
|
||||
#endif //_WIN32
|
||||
|
||||
#else
|
||||
|
||||
//static build doesn't need import/export macros
|
||||
#define TMXLITE_EXPORT_API
|
||||
|
||||
#endif //TMXLITE_STATIC
|
||||
226
ext/tmxlite/include/tmxlite/FreeFuncs.hpp
Normal file
226
ext/tmxlite/include/tmxlite/FreeFuncs.hpp
Normal file
@@ -0,0 +1,226 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
/*********************************************************************
|
||||
base64_decode
|
||||
|
||||
Copyright (C) 2004-2008 René Nyffenegger
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author 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 source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
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 source code.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
*********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tmxlite/detail/Android.hpp>
|
||||
#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 std::string base64_decode(std::string const& encoded_string)
|
||||
{
|
||||
static const std::string base64_chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
std::function<bool(unsigned char)> is_base64 =
|
||||
[](unsigned char c)->bool
|
||||
{
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
};
|
||||
|
||||
auto in_len = encoded_string.size();
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
|
||||
{
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
if (i == 4)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
char_array_4[i] = static_cast<unsigned char>(base64_chars.find(char_array_4[i]));
|
||||
}
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
{
|
||||
ret += char_array_3[i];
|
||||
}
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
for (j = i; j < 4; j++)
|
||||
{
|
||||
char_array_4[j] = 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
char_array_4[j] = static_cast<unsigned char>(base64_chars.find(char_array_4[j]));
|
||||
}
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++)
|
||||
{
|
||||
ret += char_array_3[j];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
// this does only work on windows
|
||||
#ifndef __ANDROID__
|
||||
return outPath + '/' + path;
|
||||
#endif
|
||||
|
||||
// todo: make resolveFilePath work with subfolders on
|
||||
// android - currently only the root folder is working
|
||||
|
||||
#ifdef __ANDROID__
|
||||
return path;
|
||||
#endif
|
||||
}
|
||||
|
||||
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
|
||||
107
ext/tmxlite/include/tmxlite/ImageLayer.hpp
Normal file
107
ext/tmxlite/include/tmxlite/ImageLayer.hpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*********************************************************************
|
||||
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);
|
||||
}
|
||||
}
|
||||
175
ext/tmxlite/include/tmxlite/Layer.hpp
Normal file
175
ext/tmxlite/include/tmxlite/Layer.hpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/*********************************************************************
|
||||
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;
|
||||
};
|
||||
}
|
||||
86
ext/tmxlite/include/tmxlite/LayerGroup.hpp
Normal file
86
ext/tmxlite/include/tmxlite/LayerGroup.hpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*********************************************************************
|
||||
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);
|
||||
}
|
||||
}
|
||||
282
ext/tmxlite/include/tmxlite/Map.hpp
Normal file
282
ext/tmxlite/include/tmxlite/Map.hpp
Normal file
@@ -0,0 +1,282 @@
|
||||
/*********************************************************************
|
||||
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();
|
||||
};
|
||||
}
|
||||
221
ext/tmxlite/include/tmxlite/Object.hpp
Normal file
221
ext/tmxlite/include/tmxlite/Object.hpp
Normal file
@@ -0,0 +1,221 @@
|
||||
/*********************************************************************
|
||||
(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*);
|
||||
};
|
||||
}
|
||||
99
ext/tmxlite/include/tmxlite/ObjectGroup.hpp
Normal file
99
ext/tmxlite/include/tmxlite/ObjectGroup.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*********************************************************************
|
||||
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);
|
||||
}
|
||||
}
|
||||
86
ext/tmxlite/include/tmxlite/ObjectTypes.hpp
Normal file
86
ext/tmxlite/include/tmxlite/ObjectTypes.hpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*********************************************************************
|
||||
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();
|
||||
};
|
||||
}
|
||||
144
ext/tmxlite/include/tmxlite/Property.hpp
Normal file
144
ext/tmxlite/include/tmxlite/Property.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/*********************************************************************
|
||||
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;
|
||||
};
|
||||
}
|
||||
116
ext/tmxlite/include/tmxlite/TileLayer.hpp
Normal file
116
ext/tmxlite/include/tmxlite/TileLayer.hpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*********************************************************************
|
||||
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);
|
||||
}
|
||||
}
|
||||
296
ext/tmxlite/include/tmxlite/Tileset.hpp
Normal file
296
ext/tmxlite/include/tmxlite/Tileset.hpp
Normal file
@@ -0,0 +1,296 @@
|
||||
/*********************************************************************
|
||||
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);
|
||||
};
|
||||
}
|
||||
150
ext/tmxlite/include/tmxlite/Types.hpp
Normal file
150
ext/tmxlite/include/tmxlite/Types.hpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/*********************************************************************
|
||||
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);
|
||||
110
ext/tmxlite/include/tmxlite/Types.inl
Normal file
110
ext/tmxlite/include/tmxlite/Types.inl
Normal file
@@ -0,0 +1,110 @@
|
||||
/*********************************************************************
|
||||
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;
|
||||
}
|
||||
53
ext/tmxlite/include/tmxlite/detail/Android.hpp
Normal file
53
ext/tmxlite/include/tmxlite/detail/Android.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*********************************************************************
|
||||
Matt Marchant 2016
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef ANDROID_INC_HPP_
|
||||
#define ANDROID_INC_HPP_
|
||||
#ifdef __ANDROID__
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <typename T>
|
||||
std::string to_string(T value)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << value;
|
||||
return os.str();
|
||||
}
|
||||
}
|
||||
|
||||
#define STOI(str) std::strtol(str.c_str(), 0, 10)
|
||||
#else
|
||||
#define STOI(str) std::stoi(str)
|
||||
|
||||
#endif // __ANDROID__
|
||||
#endif // ANDROID_INC_HPP_
|
||||
190
ext/tmxlite/include/tmxlite/detail/Log.hpp
Normal file
190
ext/tmxlite/include/tmxlite/detail/Log.hpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/*********************************************************************
|
||||
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
|
||||
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#include <cstring>
|
||||
|
||||
#define LOG_TAG "TMXlite-Debug"
|
||||
//#define ALOG(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
|
||||
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
|
||||
#endif // __ANDROID__
|
||||
|
||||
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)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
|
||||
int outstringLength = outstring.length();
|
||||
char outstring_chararray[outstringLength+1];
|
||||
std::strcpy(outstring_chararray, outstring.c_str());
|
||||
LOGE("%s",outstring_chararray);
|
||||
#endif
|
||||
std::cerr << outstring << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
int outstringLength = outstring.length();
|
||||
char outstring_chararray[outstringLength+1];
|
||||
std::strcpy(outstring_chararray, outstring.c_str());
|
||||
LOGI("%s", outstring_chararray);
|
||||
#endif
|
||||
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())
|
||||
{
|
||||
#ifndef __ANDROID__
|
||||
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: ");
|
||||
#endif //__ANDROID__
|
||||
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--;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#ifndef _DEBUG_
|
||||
#define LOG(message, type)
|
||||
#else
|
||||
#define LOG(message, type) {\
|
||||
std::stringstream ss; \
|
||||
ss << message << " (" << __FILE__ << ", " << __LINE__ << ")"; \
|
||||
tmx::Logger::log(ss.str(), type);}
|
||||
#endif //_DEBUG_
|
||||
|
||||
#endif //TMXLITE_LOGGER_HPP_
|
||||
15
ext/tmxlite/src/CMakeLists.txt
Normal file
15
ext/tmxlite/src/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
set(PROJECT_SRC
|
||||
${PROJECT_DIR}/FreeFuncs.cpp
|
||||
${PROJECT_DIR}/ImageLayer.cpp
|
||||
${PROJECT_DIR}/Map.cpp
|
||||
${PROJECT_DIR}/Object.cpp
|
||||
${PROJECT_DIR}/ObjectGroup.cpp
|
||||
${PROJECT_DIR}/Property.cpp
|
||||
${PROJECT_DIR}/TileLayer.cpp
|
||||
${PROJECT_DIR}/LayerGroup.cpp
|
||||
${PROJECT_DIR}/Tileset.cpp
|
||||
${PROJECT_DIR}/ObjectTypes.cpp)
|
||||
|
||||
set(LIB_SRC
|
||||
${PROJECT_DIR}/miniz.c
|
||||
${PROJECT_DIR}/detail/pugixml.cpp)
|
||||
133
ext/tmxlite/src/FreeFuncs.cpp
Normal file
133
ext/tmxlite/src/FreeFuncs.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef USE_EXTLIBS
|
||||
#include "miniz.h"
|
||||
#else
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
#include <tmxlite/FreeFuncs.hpp>
|
||||
#include <tmxlite/Types.hpp>
|
||||
#include <tmxlite/detail/Log.hpp>
|
||||
|
||||
#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_EXTLIBS
|
||||
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;
|
||||
}
|
||||
110
ext/tmxlite/src/ImageLayer.cpp
Normal file
110
ext/tmxlite/src/ImageLayer.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef USE_EXTLIBS
|
||||
#include <pugixml.hpp>
|
||||
#else
|
||||
#include "detail/pugixml.hpp"
|
||||
#endif
|
||||
#include <tmxlite/ImageLayer.hpp>
|
||||
#include <tmxlite/FreeFuncs.hpp>
|
||||
#include <tmxlite/detail/Log.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
109
ext/tmxlite/src/LayerGroup.cpp
Normal file
109
ext/tmxlite/src/LayerGroup.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef USE_EXTLIBS
|
||||
#include <pugixml.hpp>
|
||||
#else
|
||||
#include "detail/pugixml.hpp"
|
||||
#endif
|
||||
#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>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
367
ext/tmxlite/src/Map.cpp
Normal file
367
ext/tmxlite/src/Map.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef USE_EXTLIBS
|
||||
#include <pugixml.hpp>
|
||||
#else
|
||||
#include "detail/pugixml.hpp"
|
||||
#endif
|
||||
#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 <tmxlite/detail/Android.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 = STOI(attribString.substr(0, pointPos));
|
||||
m_version.lower = 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;
|
||||
}
|
||||
403
ext/tmxlite/src/Object.cpp
Normal file
403
ext/tmxlite/src/Object.cpp
Normal file
@@ -0,0 +1,403 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef USE_EXTLIBS
|
||||
#include <pugixml.hpp>
|
||||
#else
|
||||
#include "detail/pugixml.hpp"
|
||||
#endif
|
||||
#include <tmxlite/Object.hpp>
|
||||
#include <tmxlite/FreeFuncs.hpp>
|
||||
#include <tmxlite/Map.hpp>
|
||||
#include <tmxlite/Tileset.hpp>
|
||||
#include <tmxlite/detail/Log.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
ext/tmxlite/src/ObjectGroup.cpp
Normal file
102
ext/tmxlite/src/ObjectGroup.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef USE_EXTLIBS
|
||||
#include <pugixml.hpp>
|
||||
#else
|
||||
#include "detail/pugixml.hpp"
|
||||
#endif
|
||||
#include <tmxlite/FreeFuncs.hpp>
|
||||
#include <tmxlite/ObjectGroup.hpp>
|
||||
#include <tmxlite/detail/Log.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
154
ext/tmxlite/src/ObjectTypes.cpp
Normal file
154
ext/tmxlite/src/ObjectTypes.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef USE_EXTLIBS
|
||||
#include <pugixml.hpp>
|
||||
#else
|
||||
#include "detail/pugixml.hpp"
|
||||
#endif
|
||||
#include <tmxlite/FreeFuncs.hpp>
|
||||
#include <tmxlite/ObjectTypes.hpp>
|
||||
#include <tmxlite/detail/Log.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;
|
||||
}
|
||||
167
ext/tmxlite/src/Property.cpp
Normal file
167
ext/tmxlite/src/Property.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef USE_EXTLIBS
|
||||
#include <pugixml.hpp>
|
||||
#else
|
||||
#include "detail/pugixml.hpp"
|
||||
#endif
|
||||
#include <tmxlite/Property.hpp>
|
||||
#include <tmxlite/detail/Log.hpp>
|
||||
#include <tmxlite/FreeFuncs.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;
|
||||
}
|
||||
}
|
||||
340
ext/tmxlite/src/TileLayer.cpp
Normal file
340
ext/tmxlite/src/TileLayer.cpp
Normal file
@@ -0,0 +1,340 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef USE_EXTLIBS
|
||||
#include <pugixml.hpp>
|
||||
#include <zstd.h>
|
||||
#else
|
||||
#include "detail/pugixml.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef USE_ZSTD
|
||||
#include <zstd.h>
|
||||
#endif
|
||||
|
||||
#include <tmxlite/FreeFuncs.hpp>
|
||||
#include <tmxlite/TileLayer.hpp>
|
||||
#include <tmxlite/detail/Log.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
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:
|
||||
#if defined USE_ZSTD || defined USE_EXTLIBS
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Logger::log("Library must be built with USE_EXTLIBS or USE_ZSTD for Zstd compression", Logger::Type::Error);
|
||||
return {};
|
||||
#endif
|
||||
case CompressionType::GZip:
|
||||
#ifndef USE_EXTLIBS
|
||||
Logger::log("Library must be built with USE_EXTLIBS for GZip compression", Logger::Type::Error);
|
||||
return {};
|
||||
#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;
|
||||
}
|
||||
}
|
||||
460
ext/tmxlite/src/Tileset.cpp
Normal file
460
ext/tmxlite/src/Tileset.cpp
Normal file
@@ -0,0 +1,460 @@
|
||||
/*********************************************************************
|
||||
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.
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef USE_EXTLIBS
|
||||
#include <pugixml.hpp>
|
||||
#else
|
||||
#include "detail/pugixml.hpp"
|
||||
#endif
|
||||
#include <tmxlite/Tileset.hpp>
|
||||
#include <tmxlite/FreeFuncs.hpp>
|
||||
#include <tmxlite/detail/Log.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);
|
||||
}
|
||||
75
ext/tmxlite/src/detail/pugiconfig.hpp
Normal file
75
ext/tmxlite/src/detail/pugiconfig.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* pugixml parser - version 1.7
|
||||
* --------------------------------------------------------
|
||||
* Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||
* Report bugs and download new versions at http://pugixml.org/
|
||||
*
|
||||
* This library is distributed under the MIT License. See notice at the end
|
||||
* of this file.
|
||||
*
|
||||
* This work is based on the pugxml parser, which is:
|
||||
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
*/
|
||||
|
||||
#ifndef HEADER_PUGICONFIG_HPP
|
||||
#define HEADER_PUGICONFIG_HPP
|
||||
|
||||
// Uncomment this to enable wchar_t mode
|
||||
// #define PUGIXML_WCHAR_MODE
|
||||
|
||||
// Uncomment this to enable compact mode
|
||||
// #define PUGIXML_COMPACT
|
||||
|
||||
// Uncomment this to disable XPath
|
||||
// #define PUGIXML_NO_XPATH
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// Uncomment this to disable STL
|
||||
#define PUGIXML_NO_STL
|
||||
|
||||
// Uncomment this to disable exceptions
|
||||
#define PUGIXML_NO_EXCEPTIONS
|
||||
#endif //__ANDROID__
|
||||
// Set this to control attributes for public classes/functions, i.e.:
|
||||
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||
|
||||
// Tune these constants to adjust memory-related behavior
|
||||
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||
|
||||
// Uncomment this to switch to header-only version
|
||||
//#define PUGIXML_HEADER_ONLY
|
||||
|
||||
// Uncomment this to enable long long support
|
||||
// #define PUGIXML_HAS_LONG_LONG
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copyright (c) 2006-2015 Arseny Kapoulkine
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
34
ext/tmxlite/src/detail/pugixml.LICENSE
Normal file
34
ext/tmxlite/src/detail/pugixml.LICENSE
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* pugixml parser - version 1.7
|
||||
* --------------------------------------------------------
|
||||
* Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||
* Report bugs and download new versions at http://pugixml.org/
|
||||
*
|
||||
* This library is distributed under the MIT License.
|
||||
*
|
||||
* This work is based on the pugxml parser, which is:
|
||||
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||
*
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
12426
ext/tmxlite/src/detail/pugixml.cpp
Normal file
12426
ext/tmxlite/src/detail/pugixml.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1400
ext/tmxlite/src/detail/pugixml.hpp
Normal file
1400
ext/tmxlite/src/detail/pugixml.hpp
Normal file
File diff suppressed because it is too large
Load Diff
59
ext/tmxlite/src/meson.build
Normal file
59
ext/tmxlite/src/meson.build
Normal file
@@ -0,0 +1,59 @@
|
||||
if get_option('use_extlibs')
|
||||
tmxlite_lib = library(meson.project_name() + binary_postfix,
|
||||
'FreeFuncs.cpp',
|
||||
'ImageLayer.cpp',
|
||||
'Map.cpp',
|
||||
'Object.cpp',
|
||||
'ObjectGroup.cpp',
|
||||
'Property.cpp',
|
||||
'TileLayer.cpp',
|
||||
'LayerGroup.cpp',
|
||||
'Tileset.cpp',
|
||||
install: true,
|
||||
include_directories: incdir,
|
||||
dependencies: [zdep, pugidep, zstddep]
|
||||
)
|
||||
else
|
||||
|
||||
if get_option('use_zstd')
|
||||
|
||||
tmxlite_lib = library(meson.project_name() + binary_postfix,
|
||||
'detail/pugixml.cpp',
|
||||
'FreeFuncs.cpp',
|
||||
'ImageLayer.cpp',
|
||||
'Map.cpp',
|
||||
'miniz.c',
|
||||
'Object.cpp',
|
||||
'ObjectGroup.cpp',
|
||||
'Property.cpp',
|
||||
'TileLayer.cpp',
|
||||
'LayerGroup.cpp',
|
||||
'Tileset.cpp',
|
||||
install: true,
|
||||
include_directories: incdir,
|
||||
dependencies: zstddep
|
||||
)
|
||||
else
|
||||
|
||||
tmxlite_lib = library(meson.project_name() + binary_postfix,
|
||||
'detail/pugixml.cpp',
|
||||
'FreeFuncs.cpp',
|
||||
'ImageLayer.cpp',
|
||||
'Map.cpp',
|
||||
'miniz.c',
|
||||
'Object.cpp',
|
||||
'ObjectGroup.cpp',
|
||||
'Property.cpp',
|
||||
'TileLayer.cpp',
|
||||
'LayerGroup.cpp',
|
||||
'Tileset.cpp',
|
||||
install: true,
|
||||
include_directories: incdir,
|
||||
)
|
||||
endif
|
||||
endif
|
||||
|
||||
tmxlite_dep = declare_dependency(
|
||||
link_with: tmxlite_lib,
|
||||
include_directories: incdir,
|
||||
)
|
||||
4916
ext/tmxlite/src/miniz.c
Normal file
4916
ext/tmxlite/src/miniz.c
Normal file
File diff suppressed because it is too large
Load Diff
8
ext/tmxlite/src/miniz.h
Normal file
8
ext/tmxlite/src/miniz.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
miniz public domain replacement for zlib. See miniz.c
|
||||
for more information.
|
||||
*/
|
||||
#ifndef MINIZ_HEADER_FILE_ONLY
|
||||
#define MINIZ_HEADER_FILE_ONLY
|
||||
#include "miniz.c"
|
||||
#endif //MINIZ_HEADER_FILE_ONLY
|
||||
14
ext/tmxlite/tmxlite.pc.in
Normal file
14
ext/tmxlite/tmxlite.pc.in
Normal file
@@ -0,0 +1,14 @@
|
||||
prefix="@CMAKE_INSTALL_PREFIX@"
|
||||
exec_prefix="${prefix}"
|
||||
libdir="${prefix}/lib"
|
||||
includedir="${prefix}/include"
|
||||
|
||||
Name: tmxlite
|
||||
Description: lightweight C++14 parser for Tiled tmx files
|
||||
URL: https://github.com/fallahn/tmxlite
|
||||
Version: @CMAKE_PROJECT_VERSION@
|
||||
Requires: @PKGCONF_REQ_PUB@
|
||||
Requires.private: @PKGCONF_REQ_PRIV@
|
||||
Cflags: -I"${includedir}"
|
||||
Libs: -L"${libdir}" -ltmxlite
|
||||
Libs.private: -L"${libdir}" -ltmxlite @PKGCONF_LIBS_PRIV@
|
||||
@@ -1,28 +1,20 @@
|
||||
add_executable(tmx2gba
|
||||
argparse.hpp argparse.cpp
|
||||
tmxlayer.hpp
|
||||
tmxobject.hpp
|
||||
tmxreader.hpp tmxreader.cpp
|
||||
tmxtileset.hpp
|
||||
swriter.hpp swriter.cpp
|
||||
convert.hpp convert.cpp
|
||||
headerwriter.hpp headerwriter.cpp
|
||||
swriter.hpp swriter.cpp
|
||||
tmx2gba.cpp)
|
||||
|
||||
set_target_properties(tmx2gba PROPERTIES
|
||||
# C++20 & C99
|
||||
CXX_STANDARD 20
|
||||
C_STANDARD 99)
|
||||
set_target_properties(tmx2gba PROPERTIES CXX_STANDARD 20)
|
||||
|
||||
# Enable strong warnings
|
||||
target_compile_options(tmx2gba PRIVATE
|
||||
$<$<CXX_COMPILER_ID:MSVC>:/Wall>
|
||||
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wall -Wextra -pedantic>
|
||||
$<$<CXX_COMPILER_ID:Clang,AppleClang>:-Weverything -Wno-c++98-compat>)
|
||||
$<$<CXX_COMPILER_ID:Clang,AppleClang>:-Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded>)
|
||||
|
||||
target_link_libraries(tmx2gba
|
||||
External::base64
|
||||
External::miniz
|
||||
External::rapidxml)
|
||||
target_link_libraries(tmx2gba tmxlite)
|
||||
|
||||
if (TMX2GBA_DKP_INSTALL)
|
||||
if (DEFINED ENV{DEVKITPRO})
|
||||
|
||||
67
src/convert.cpp
Normal file
67
src/convert.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/* converter.hpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */
|
||||
|
||||
#include "convert.hpp"
|
||||
#include "tmxreader.hpp"
|
||||
|
||||
|
||||
bool convert::ConvertCharmap(std::vector<uint16_t>& out, int idxOffset, uint32_t defaultPal, const TmxReader& tmx)
|
||||
{
|
||||
const auto gfxTiles = tmx.GetGraphicsTiles();
|
||||
const auto palTiles = tmx.GetPaletteTiles();
|
||||
|
||||
const size_t numTiles = tmx.TileCount();
|
||||
out.reserve(numTiles);
|
||||
for (size_t i = 0; i < numTiles; ++i)
|
||||
{
|
||||
const TmxReader::Tile tile = gfxTiles[i];
|
||||
|
||||
int tileIdx = std::max(0, static_cast<int>(tmx.LidFromGid(tile.id)) + idxOffset);
|
||||
uint8_t flags = 0x0;
|
||||
|
||||
// Get flipped!
|
||||
flags |= (tile.flags & TmxReader::FLIP_HORZ) ? 0x4 : 0x0;
|
||||
flags |= (tile.flags & TmxReader::FLIP_VERT) ? 0x8 : 0x0;
|
||||
|
||||
// Determine palette ID
|
||||
uint32_t idx = 0;
|
||||
if (palTiles.has_value())
|
||||
idx = tmx.LidFromGid(palTiles.value()[i]);
|
||||
if (idx == 0)
|
||||
idx = defaultPal + 1;
|
||||
flags |= static_cast<uint8_t>(idx - 1) << 4;
|
||||
|
||||
out.push_back(static_cast<uint16_t>(tileIdx) | static_cast<uint16_t>(flags << 8));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool convert::ConvertCollision(std::vector<uint8_t>& out, const TmxReader& tmx)
|
||||
{
|
||||
const auto clsTiles = tmx.GetCollisionTiles().value();
|
||||
|
||||
size_t numTiles = tmx.TileCount();
|
||||
out.reserve(numTiles);
|
||||
for (size_t i = 0; i < numTiles; ++i)
|
||||
{
|
||||
uint8_t id = static_cast<uint8_t>(tmx.LidFromGid(clsTiles[i]));
|
||||
out.emplace_back(id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool convert::ConvertObjects(std::vector<uint32_t>& out, const TmxReader& tmx)
|
||||
{
|
||||
const auto objects = tmx.GetObjects().value();
|
||||
|
||||
for (auto obj : objects)
|
||||
{
|
||||
out.push_back(obj.id);
|
||||
out.emplace_back(static_cast<int>(obj.x * 256.0f));
|
||||
out.emplace_back(static_cast<int>(obj.y * 256.0f));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
20
src/convert.hpp
Normal file
20
src/convert.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/* converter.hpp - Copyright (C) 2024 a dinosaur (zlib, see COPYING.txt) */
|
||||
|
||||
#ifndef CONVERT_HPP
|
||||
#define CONVERT_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
class TmxReader;
|
||||
|
||||
namespace convert
|
||||
{
|
||||
[[nodiscard]] bool ConvertCharmap(std::vector<uint16_t>& out,
|
||||
int idOffset, uint32_t defaultPalIdx,
|
||||
const TmxReader& tmx);
|
||||
[[nodiscard]] bool ConvertCollision(std::vector<uint8_t>& out, const TmxReader& tmx);
|
||||
[[nodiscard]] bool ConvertObjects(std::vector<uint32_t>& out, const TmxReader& tmx);
|
||||
};
|
||||
|
||||
#endif//CONVERT_HPP
|
||||
@@ -8,7 +8,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<uint32_t>() { return "unsigned int"; }
|
||||
|
||||
void HeaderWriter::WriteSize(int width, int height)
|
||||
void HeaderWriter::WriteSize(unsigned width, unsigned height)
|
||||
{
|
||||
stream << std::endl;
|
||||
WriteDefine(mName + "Width", width);
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
WriteDefine(name, std::to_string(value));
|
||||
}
|
||||
|
||||
void WriteSize(int width, int height);
|
||||
void WriteSize(unsigned width, unsigned height);
|
||||
void WriteCharacterMap(const std::span<uint16_t> charData);
|
||||
void WriteCollision(const std::span<uint8_t> collisionData);
|
||||
void WriteObjects(const std::span<uint32_t> objData);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "swriter.hpp"
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
#include <assert.h>
|
||||
|
||||
#define GNU_STYLE 0
|
||||
#define MASM_STYLE 1
|
||||
@@ -130,31 +131,26 @@ void SWriter::WriteSymbol(const std::string_view suffix)
|
||||
|
||||
void SWriter::WriteArray(const std::string_view suffix, std::span<uint8_t> data, int numCols)
|
||||
{
|
||||
assert(data.size());
|
||||
WriteSymbol(suffix);
|
||||
WriteArrayDetail(stream, data.begin(), data.end(), numCols);
|
||||
}
|
||||
|
||||
void SWriter::WriteArray(const std::string_view suffix, std::span<uint16_t> data, int numCols)
|
||||
{
|
||||
assert(data.size());
|
||||
WriteSymbol(suffix);
|
||||
WriteArrayDetail(stream, data.begin(), data.end(), numCols);
|
||||
}
|
||||
|
||||
void SWriter::WriteArray(const std::string_view suffix, std::span<uint32_t> data, int numCols)
|
||||
{
|
||||
assert(data.size());
|
||||
WriteSymbol(suffix);
|
||||
WriteArrayDetail(stream, data.begin(), data.end(), numCols);
|
||||
}
|
||||
|
||||
|
||||
SWriter::~SWriter()
|
||||
{
|
||||
if (stream.is_open())
|
||||
{
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
bool SWriter::Open(const std::filesystem::path& path, const std::string_view name)
|
||||
{
|
||||
mName = name;
|
||||
|
||||
@@ -20,9 +20,7 @@ class SWriter
|
||||
void WriteSymbol(const std::string_view suffix);
|
||||
|
||||
public:
|
||||
~SWriter();
|
||||
|
||||
bool Open(const std::filesystem::path& path, const std::string_view name);
|
||||
[[nodiscard]] bool Open(const std::filesystem::path& path, const std::string_view name);
|
||||
|
||||
void WriteArray(const std::string_view suffix, std::span<uint8_t> data, int numCols = 16);
|
||||
void WriteArray(const std::string_view suffix, std::span<uint16_t> data, int numCols = 16);
|
||||
|
||||
122
src/tmx2gba.cpp
122
src/tmx2gba.cpp
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "argparse.hpp"
|
||||
#include "tmxreader.hpp"
|
||||
#include "tmxlayer.hpp"
|
||||
#include "tmxobject.hpp"
|
||||
#include "convert.hpp"
|
||||
#include "headerwriter.hpp"
|
||||
#include "swriter.hpp"
|
||||
#include <iostream>
|
||||
@@ -15,13 +14,13 @@ static const char* versionStr = "tmx2gba version 0.3, (c) 2015-2022 a dinosaur";
|
||||
|
||||
struct Arguments
|
||||
{
|
||||
bool help = false, showVersion = false;
|
||||
std::string inPath, outPath;
|
||||
std::string layer, collisionlay, paletteLay;
|
||||
std::string flagFile;
|
||||
int offset = 0;
|
||||
int palette = 0;
|
||||
std::vector<std::string> objMappings;
|
||||
bool help = false, showVersion = false;
|
||||
};
|
||||
|
||||
using ArgParse::Option;
|
||||
@@ -163,34 +162,26 @@ int main(int argc, char** argv)
|
||||
|
||||
// Open & read input file
|
||||
TmxReader tmx;
|
||||
std::ifstream fin(p.inPath);
|
||||
if (!fin.is_open())
|
||||
switch (tmx.Open(p.inPath,
|
||||
p.layer, p.paletteLay, p.collisionlay, objMapping))
|
||||
{
|
||||
case TmxReader::Error::LOAD_FAILED:
|
||||
std::cerr << "Failed to open input file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
tmx.Open(fin);
|
||||
|
||||
// Get layers
|
||||
if (tmx.GetLayerCount() == 0)
|
||||
{
|
||||
std::cerr << "No layers found." << std::endl;
|
||||
case TmxReader::Error::NO_LAYERS:
|
||||
std::cerr << "No suitable tile layer found." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
const TmxLayer* layerGfx = p.layer.empty()
|
||||
? tmx.GetLayer(0)
|
||||
: tmx.GetLayer(p.layer);
|
||||
const TmxLayer* layerCls = p.collisionlay.empty()
|
||||
? nullptr
|
||||
: tmx.GetLayer(p.collisionlay);
|
||||
const TmxLayer* layerPal = p.paletteLay.empty()
|
||||
? nullptr
|
||||
: tmx.GetLayer(p.paletteLay);
|
||||
|
||||
if (layerGfx == nullptr)
|
||||
{
|
||||
std::cerr << "Input layer not found." << std::endl;
|
||||
case TmxReader::Error::GRAPHICS_NOTFOUND:
|
||||
std::cerr << "No graphics layer \"" << p.layer << "\" found." << std::endl;
|
||||
return 1;
|
||||
case TmxReader::Error::PALETTE_NOTFOUND:
|
||||
std::cerr << "No palette layer \"" << p.paletteLay << "\" found." << std::endl;
|
||||
return 1;
|
||||
case TmxReader::Error::COLLISION_NOTFOUND:
|
||||
std::cerr << "No collision layer \"" << p.collisionlay << "\" found." << std::endl;
|
||||
return 1;
|
||||
case TmxReader::Error::OK:
|
||||
break;
|
||||
}
|
||||
|
||||
// Get name from file
|
||||
@@ -203,12 +194,13 @@ int main(int argc, char** argv)
|
||||
name = name.substr(slashPos + 1);
|
||||
|
||||
// Open output files
|
||||
SWriter outS; HeaderWriter outH;
|
||||
SWriter outS;
|
||||
if (!outS.Open(p.outPath + ".s", name))
|
||||
{
|
||||
std::cerr << "Failed to create output file \"" << p.outPath << ".s\".";
|
||||
return 1;
|
||||
}
|
||||
HeaderWriter outH;
|
||||
if (!outH.Open(p.outPath + ".h", name))
|
||||
{
|
||||
std::cerr << "Failed to create output file \"" << p.outPath << ".h\".";
|
||||
@@ -216,82 +208,34 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
// Convert to GBA-friendly charmap data
|
||||
const uint32_t* gfxTiles = layerGfx->GetData();
|
||||
const uint32_t* palTiles = (layerPal == nullptr) ? nullptr : layerPal->GetData();
|
||||
std::vector<uint16_t> charDat;
|
||||
const size_t numTiles = static_cast<size_t>(layerGfx->GetWidth()) * static_cast<size_t>(layerGfx->GetHeight());
|
||||
charDat.reserve(numTiles);
|
||||
for (size_t i = 0; i < numTiles; ++i)
|
||||
{
|
||||
uint32_t read = (*gfxTiles++);
|
||||
std::vector<uint16_t> charDat;
|
||||
if (!convert::ConvertCharmap(charDat, p.offset, p.palette, tmx))
|
||||
return 1;
|
||||
|
||||
uint16_t tile = std::max(0, static_cast<int>(tmx.LidFromGid(read & ~TmxLayer::FLIP_MASK)) + p.offset);
|
||||
uint8_t flags = 0x0;
|
||||
|
||||
// Get flipped!
|
||||
flags |= (read & TmxLayer::FLIP_HORZ) ? 0x4 : 0x0;
|
||||
flags |= (read & TmxLayer::FLIP_VERT) ? 0x8 : 0x0;
|
||||
|
||||
// Determine palette ID
|
||||
uint32_t idx = 0;
|
||||
if (palTiles != nullptr)
|
||||
idx = tmx.LidFromGid((*palTiles++) & ~TmxLayer::FLIP_MASK);
|
||||
if (idx == 0)
|
||||
idx = p.palette + 1;
|
||||
flags |= static_cast<uint8_t>(idx - 1) << 4;
|
||||
|
||||
charDat.push_back(tile | (static_cast<uint16_t>(flags) << 8));
|
||||
// Write out charmap
|
||||
outH.WriteSize(tmx.GetSize().width, tmx.GetSize().height);
|
||||
outH.WriteCharacterMap(charDat);
|
||||
outS.WriteArray("Tiles", charDat);
|
||||
}
|
||||
|
||||
// Write out charmap
|
||||
outH.WriteSize(tmx.GetWidth(), tmx.GetHeight());
|
||||
outH.WriteCharacterMap(charDat);
|
||||
outS.WriteArray("Tiles", charDat);
|
||||
|
||||
// Convert collision map & write it out
|
||||
if (layerCls != nullptr)
|
||||
// Convert collision map & write out
|
||||
if (tmx.HasCollisionTiles())
|
||||
{
|
||||
std::vector<uint8_t> collisionDat;
|
||||
collisionDat.reserve(layerCls->GetWidth() * layerCls->GetHeight());
|
||||
if (!convert::ConvertCollision(collisionDat, tmx))
|
||||
return 1;
|
||||
|
||||
gfxTiles = layerCls->GetData();
|
||||
for (int i = 0; i < layerCls->GetWidth() * layerCls->GetHeight(); ++i)
|
||||
{
|
||||
uint8_t ucTile = static_cast<uint8_t>(tmx.LidFromGid((*gfxTiles++) & ~TmxLayer::FLIP_MASK));
|
||||
collisionDat.push_back(ucTile);
|
||||
}
|
||||
|
||||
// Try to nicely append "_collision" to the output name
|
||||
std::string path;
|
||||
size_t extPos = p.outPath.find_last_of('.');
|
||||
if (extPos != std::string::npos)
|
||||
path = p.outPath.insert(extPos, "_collision");
|
||||
else
|
||||
path = p.outPath + "_collision";
|
||||
|
||||
// Write collision
|
||||
outH.WriteCollision(collisionDat);
|
||||
outS.WriteArray("Collision", collisionDat, 32);
|
||||
}
|
||||
|
||||
if (!p.objMappings.empty())
|
||||
if (tmx.HasObjects())
|
||||
{
|
||||
std::vector<uint32_t> objDat;
|
||||
for (size_t i = 0; i < tmx.GetObjectCount(); ++i)
|
||||
{
|
||||
auto obj = tmx.GetObject(i);
|
||||
auto it = objMapping.find(obj->GetName());
|
||||
if (it == objMapping.end())
|
||||
continue;
|
||||
if (!convert::ConvertObjects(objDat, tmx))
|
||||
return 1;
|
||||
|
||||
float x, y;
|
||||
obj->GetPos(x, y);
|
||||
objDat.push_back(it->second);
|
||||
objDat.push_back(static_cast<int>(x * 256.0f));
|
||||
objDat.push_back(static_cast<int>(y * 256.0f));
|
||||
}
|
||||
|
||||
// Write objects
|
||||
outH.WriteObjects(objDat);
|
||||
outS.WriteArray("Objdat", objDat);
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/* 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
|
||||
@@ -1,25 +0,0 @@
|
||||
/* 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,227 +1,133 @@
|
||||
/* tmxreader.cpp - Copyright (C) 2015-2022 a dinosaur (zlib, see COPYING.txt) */
|
||||
/* tmxreader.cpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */
|
||||
|
||||
#include "tmxreader.hpp"
|
||||
#include "tmxtileset.hpp"
|
||||
#include "tmxobject.hpp"
|
||||
#include "tmxlayer.hpp"
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include "tmxlite/Map.hpp"
|
||||
#include "tmxlite/TileLayer.hpp"
|
||||
#include "tmxlite/ObjectGroup.hpp"
|
||||
#include <optional>
|
||||
#include <algorithm>
|
||||
#include <rapidxml/rapidxml.hpp>
|
||||
#include <base64.h>
|
||||
#include <miniz.h>
|
||||
|
||||
|
||||
TmxReader::~TmxReader()
|
||||
TmxReader::Error TmxReader::Open(const std::string& inPath,
|
||||
const std::string_view graphicsName,
|
||||
const std::string_view paletteName,
|
||||
const std::string_view collisionName,
|
||||
const std::map<std::string, uint32_t>& objMapping)
|
||||
{
|
||||
// Delete old tilesets
|
||||
for (auto pTileset : mTilesets)
|
||||
delete pTileset;
|
||||
mTilesets.clear();
|
||||
tmx::Map map;
|
||||
if (!map.load(inPath))
|
||||
return Error::LOAD_FAILED;
|
||||
|
||||
// Delete old layers
|
||||
for (auto pLay : mLayers)
|
||||
delete pLay;
|
||||
mLayers.clear();
|
||||
}
|
||||
using tmx::TileLayer;
|
||||
using tmx::ObjectGroup;
|
||||
using std::optional;
|
||||
using std::reference_wrapper;
|
||||
|
||||
optional<reference_wrapper<const TileLayer>> layerGfx;
|
||||
optional<reference_wrapper<const TileLayer>> layerCls;
|
||||
optional<reference_wrapper<const TileLayer>> layerPal;
|
||||
std::vector<reference_wrapper<const ObjectGroup>> objGroups;
|
||||
|
||||
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)
|
||||
// Read layers
|
||||
for (const auto& layer : map.getLayers())
|
||||
{
|
||||
// TODO: don't assume base64 & zlib
|
||||
tileDat = new uint32_t[width * height];
|
||||
if (!DecodeMap(tileDat, width * height * sizeof(uint32_t), std::string(xData->value())))
|
||||
auto name = layer->getName();
|
||||
if (layer->getType() == tmx::Layer::Type::Tile)
|
||||
{
|
||||
delete[] tileDat;
|
||||
tileDat = nullptr;
|
||||
if (layerGfx == std::nullopt && (graphicsName.empty() || name == graphicsName))
|
||||
layerGfx = layer->getLayerAs<TileLayer>();
|
||||
if (!collisionName.empty() && layerCls == std::nullopt && name == collisionName)
|
||||
layerCls = layer->getLayerAs<TileLayer>();
|
||||
if (!paletteName.empty() && layerPal == std::nullopt && name == paletteName)
|
||||
layerPal = layer->getLayerAs<TileLayer>();
|
||||
}
|
||||
else if (!objMapping.empty() && layer->getType() == tmx::Layer::Type::Object)
|
||||
{
|
||||
objGroups.emplace_back(layer->getLayerAs<ObjectGroup>());
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
// Check layers
|
||||
if (layerGfx == std::nullopt)
|
||||
{
|
||||
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);
|
||||
if (graphicsName.empty())
|
||||
return Error::NO_LAYERS;
|
||||
else
|
||||
if (strcmp(xNode->name(), "tileset") == 0)
|
||||
ReadTileset(xNode);
|
||||
else
|
||||
if (strcmp(xNode->name(), "objectgroup") == 0)
|
||||
ReadObjects(xNode);
|
||||
return Error::GRAPHICS_NOTFOUND;
|
||||
}
|
||||
if (layerCls == std::nullopt && !collisionName.empty())
|
||||
return Error::GRAPHICS_NOTFOUND;
|
||||
if (layerPal == std::nullopt && !paletteName.empty())
|
||||
return Error::PALETTE_NOTFOUND;
|
||||
|
||||
// Read TMX map
|
||||
mSize = Size { map.getTileCount().x, map.getTileCount().y };
|
||||
size_t numTiles = static_cast<size_t>(mSize.width) * static_cast<size_t>(mSize.height);
|
||||
|
||||
// Read graphics layer
|
||||
mGraphics.reserve(numTiles);
|
||||
for (auto tmxTile : layerGfx.value().get().getTiles())
|
||||
mGraphics.emplace_back(Tile { tmxTile.ID, tmxTile.flipFlags });
|
||||
|
||||
// Read optional layers
|
||||
if (layerPal != std::nullopt)
|
||||
{
|
||||
std::vector<uint32_t> v;
|
||||
v.reserve(numTiles);
|
||||
for (auto tmxTile : layerPal.value().get().getTiles())
|
||||
v.emplace_back(tmxTile.ID);
|
||||
mPalette.emplace(v);
|
||||
}
|
||||
if (layerCls != std::nullopt)
|
||||
{
|
||||
std::vector<uint32_t> v;
|
||||
v.reserve(numTiles);
|
||||
for (auto tmxTile : layerCls.value().get().getTiles())
|
||||
v.emplace_back(tmxTile.ID);
|
||||
mCollision.emplace(v);
|
||||
}
|
||||
|
||||
// Generate global id table
|
||||
for (auto tileset : mTilesets)
|
||||
mGidTable.push_back(tileset->GetFirstGid());
|
||||
std::sort(mGidTable.rbegin(), mGidTable.rend());
|
||||
}
|
||||
// Read tilesets
|
||||
const auto& tilesets = map.getTilesets();
|
||||
mGidTable.reserve(tilesets.size());
|
||||
for (const auto& set : tilesets)
|
||||
mGidTable.emplace_back(std::make_pair(set.getFirstGID(), set.getLastGID()));
|
||||
|
||||
const TmxLayer* TmxReader::GetLayer(const std::string& aName) const
|
||||
{
|
||||
for (auto layer : mLayers)
|
||||
// Read objects
|
||||
if (!objMapping.empty())
|
||||
{
|
||||
if (layer->GetName() == aName)
|
||||
return layer;
|
||||
std::vector<Object> v;
|
||||
for (const auto& group : objGroups)
|
||||
{
|
||||
const auto& tmxObjects = group.get().getObjects();
|
||||
v.reserve(v.size() + tmxObjects.size());
|
||||
for (const auto& tmxObj : tmxObjects)
|
||||
{
|
||||
auto it = objMapping.find(tmxObj.getName());
|
||||
if (it == objMapping.end())
|
||||
continue;
|
||||
|
||||
const auto& aabb = tmxObj.getAABB();
|
||||
Object obj;
|
||||
obj.id = it->second;
|
||||
obj.x = aabb.left;
|
||||
obj.y = aabb.top;
|
||||
|
||||
v.emplace_back(obj);
|
||||
}
|
||||
}
|
||||
mObjects.emplace(v);
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
return Error::OK;
|
||||
}
|
||||
|
||||
uint32_t TmxReader::LidFromGid(uint32_t aGid)
|
||||
uint32_t TmxReader::LidFromGid(uint32_t aGid) const
|
||||
{
|
||||
for (uint32_t first : mGidTable)
|
||||
for (auto range : mGidTable)
|
||||
{
|
||||
if (first <= aGid)
|
||||
return aGid - (first - 1);
|
||||
if (aGid >= range.first && aGid <= range.second)
|
||||
return aGid - (range.first - 1);
|
||||
}
|
||||
return aGid;
|
||||
}
|
||||
|
||||
@@ -1,50 +1,80 @@
|
||||
/* tmxreader.hpp - Copyright (C) 2015-2022 a dinosaur (zlib, see COPYING.txt) */
|
||||
/* tmxreader.hpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */
|
||||
|
||||
#ifndef TMXREADER_HPP
|
||||
#define TMXREADER_HPP
|
||||
|
||||
#include <istream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <cstdint>
|
||||
#include <rapidxml/rapidxml.hpp>
|
||||
|
||||
class TmxTileset;
|
||||
class TmxLayer;
|
||||
class TmxObject;
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
class TmxReader
|
||||
{
|
||||
public:
|
||||
TmxReader() = default;
|
||||
~TmxReader();
|
||||
static constexpr uint8_t FLIP_HORZ = 0x8;
|
||||
static constexpr uint8_t FLIP_VERT = 0x4;
|
||||
static constexpr uint8_t FLIP_DIAG = 0x2;
|
||||
static constexpr uint8_t FLIP_MASK = 0xE;
|
||||
|
||||
void Open(std::istream& aIn);
|
||||
enum class Error
|
||||
{
|
||||
OK,
|
||||
LOAD_FAILED,
|
||||
NO_LAYERS,
|
||||
GRAPHICS_NOTFOUND,
|
||||
PALETTE_NOTFOUND,
|
||||
COLLISION_NOTFOUND
|
||||
};
|
||||
|
||||
constexpr int GetWidth() const { return mWidth; }
|
||||
constexpr int GetHeight() const { return mHeight; }
|
||||
[[nodiscard]] Error Open(const std::string& inPath,
|
||||
const std::string_view graphicsName,
|
||||
const std::string_view paletteName,
|
||||
const std::string_view collisionName,
|
||||
const std::map<std::string, uint32_t>& objMapping);
|
||||
struct Size { unsigned width, height; };
|
||||
|
||||
inline const TmxLayer* GetLayer(size_t aId) const { return mLayers.at(aId); }
|
||||
const TmxLayer* GetLayer(const std::string& aName) const;
|
||||
inline std::size_t GetLayerCount() const { return mLayers.size(); }
|
||||
[[nodiscard]] constexpr Size GetSize() const { return mSize; }
|
||||
[[nodiscard]] constexpr size_t TileCount() const { return
|
||||
static_cast<size_t>(mSize.width) *
|
||||
static_cast<size_t>(mSize.height); }
|
||||
|
||||
inline const TmxObject* GetObject(size_t aId) const { return mObjects.at(aId); }
|
||||
inline size_t GetObjectCount() const { return mObjects.size(); }
|
||||
[[nodiscard]] uint32_t LidFromGid(uint32_t aGid) const;
|
||||
|
||||
uint32_t LidFromGid(uint32_t aGid);
|
||||
struct Tile { uint32_t id; uint8_t flags; };
|
||||
struct Object { unsigned id; float x, y; };
|
||||
|
||||
[[nodiscard]] constexpr bool HasCollisionTiles() const { return mCollision.has_value(); }
|
||||
[[nodiscard]] constexpr bool HasObjects() const { return mObjects.has_value(); }
|
||||
|
||||
[[nodiscard]] constexpr const std::span<const Tile> GetGraphicsTiles() const { return mGraphics; }
|
||||
[[nodiscard]] constexpr const std::optional<std::span<const uint32_t>> GetPaletteTiles() const
|
||||
{
|
||||
if (mPalette.has_value()) { return { mPalette.value() }; }
|
||||
return std::nullopt;
|
||||
}
|
||||
[[nodiscard]] constexpr const std::optional<std::span<const uint32_t>> GetCollisionTiles() const
|
||||
{
|
||||
if (mCollision.has_value()) { return { mCollision.value() }; }
|
||||
return std::nullopt;
|
||||
}
|
||||
[[nodiscard]] constexpr const std::optional<std::span<const Object>> GetObjects() const
|
||||
{
|
||||
if (mObjects.has_value()) { return { mObjects.value() }; }
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool DecodeMap(uint32_t* aOut, size_t aOutSize, const std::string& aBase64Dat);
|
||||
void ReadTileset(rapidxml::xml_node<>* aXNode);
|
||||
void ReadLayer(rapidxml::xml_node<>* aXNode);
|
||||
void ReadObjects(rapidxml::xml_node<>* aXNode);
|
||||
Size mSize;
|
||||
|
||||
int mWidth, mHeight;
|
||||
std::vector<TmxTileset*> mTilesets;
|
||||
std::vector<TmxLayer*> mLayers;
|
||||
std::vector<TmxObject*> mObjects;
|
||||
std::vector<uint32_t> mGidTable;
|
||||
std::vector<std::pair<uint32_t, uint32_t>> mGidTable;
|
||||
|
||||
std::vector<Tile> mGraphics;
|
||||
std::optional<std::vector<uint32_t>> mPalette;
|
||||
std::optional<std::vector<uint32_t>> mCollision;
|
||||
std::optional<std::vector<Object>> mObjects;
|
||||
};
|
||||
|
||||
#endif//TMXREADER_HPP
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/* 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