From e17f77ae050583b9f3509df3c28097dc4e68963b Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Sat, 13 Dec 2014 04:50:23 +0100 Subject: [PATCH] Spirit parser to load simple 2D maps. --- include/components/tilestreamer.hpp | 11 ++++++ include/implem/asciimap_parser.hpp | 56 +++++++++++++++++++++++++++++ include/implem/layer.inl | 4 ++- include/implem/tilestreamer.inl | 33 +++++++++++++++++ src/main.cpp | 11 ++++-- 5 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 include/implem/asciimap_parser.hpp diff --git a/include/components/tilestreamer.hpp b/include/components/tilestreamer.hpp index 1d7ea02..41d1ed8 100644 --- a/include/components/tilestreamer.hpp +++ b/include/components/tilestreamer.hpp @@ -6,6 +6,14 @@ #include #include #include +#include + +//This code might need to be removed, but for now it's handy to read a simple +//ascii file into a vector without worrying too much about details. +//TODO: remove along with the code in the constructor +#include "implem/asciimap_parser.hpp" +#include +#include namespace dk { template @@ -22,9 +30,12 @@ namespace dk { TileStreamer& operator= ( const TileStreamer& ) = delete; void copy ( std::vector& parDest, const coords& parFrom, const coords& parTo ); + const coords& tilesCount ( void ) const { return m_count; } private: StreamPtr m_stream; + coords m_count; + std::vector m_wholedata; }; } //namespace dk diff --git a/include/implem/asciimap_parser.hpp b/include/implem/asciimap_parser.hpp new file mode 100644 index 0000000..5c0816b --- /dev/null +++ b/include/implem/asciimap_parser.hpp @@ -0,0 +1,56 @@ +#ifndef idB6D0694FDF6B4902A244C7A51C9727FE +#define idB6D0694FDF6B4902A244C7A51C9727FE + +#define BOOST_SPIRIT_USE_PHOENIX_V3 +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dk { namespace implem { + struct get_line_f { + template struct result { typedef size_t type; }; + template size_t operator()(const I& parStart, const I& parPosIter) const { + return boost::spirit::get_column(parStart, parPosIter) - 1; + } + }; + + template + struct AsciiMapGrammar : boost::spirit::qi::grammar()> { + explicit AsciiMapGrammar ( const I& parItStart ); + + boost::spirit::qi::rule()> start; + std::vector lengths; + boost::phoenix::function getline; + boost::spirit::qi::int_parser digit_int; + }; + + template + AsciiMapGrammar::AsciiMapGrammar (const I& parItStart) : + AsciiMapGrammar::base_type(start) + { + using boost::phoenix::push_back; + using boost::spirit::qi::_1; + using boost::spirit::qi::eol; + using boost::spirit::qi::eoi; + using boost::spirit::qi::raw; + using boost::phoenix::begin; + using boost::spirit::qi::int_parser; + + start %= *digit_int % + raw[ + eol + ][push_back(boost::phoenix::ref(lengths), getline(boost::phoenix::val(parItStart), begin(_1)))] + ; + } + + +}} //namespace dk::implem + +#undef BOOST_SPIRIT_USE_PHOENIX_V3 + +#endif diff --git a/include/implem/layer.inl b/include/implem/layer.inl index d3ebd29..3b9202d 100644 --- a/include/implem/layer.inl +++ b/include/implem/layer.inl @@ -31,6 +31,8 @@ namespace dk { m_streamer(std::move(parStreamer)), m_activeViewport(*this) { + DK_ASSERT(m_streamer.tilesCount() == this->m_count); + setActiveViewport(coords(0), parCount); } ///-------------------------------------------------------------------------- @@ -45,7 +47,7 @@ namespace dk { template void Layer::setActiveViewport (const coords& parFrom, const coords& parCount) { m_tiles.clear(); - const auto area = implem::area(parCount); + const auto area = implem::area(parCount); m_tiles.reserve(area); m_streamer.copy(m_tiles, parFrom, parFrom + parCount); m_activeViewport.setFrom(parFrom); diff --git a/include/implem/tilestreamer.inl b/include/implem/tilestreamer.inl index c68e80b..f886908 100644 --- a/include/implem/tilestreamer.inl +++ b/include/implem/tilestreamer.inl @@ -3,5 +3,38 @@ namespace dk { TileStreamer::TileStreamer (StreamPtr&& parStream) : m_stream(std::move(parStream)) { + //TODO: this loader /only/ works with 2D tilesets, remove it asap + + typedef std::istream_iterator DataIterator; + typedef boost::spirit::multi_pass WrappedIterator; + + *m_stream >> std::noskipws; + + auto first = WrappedIterator(DataIterator(*m_stream)); + auto last = WrappedIterator(DataIterator()); + implem::AsciiMapGrammar grammar(first); + const bool p = boost::spirit::qi::parse( + first, + last, + grammar, + m_wholedata + ); + + if (not p or last != first) { + throw std::runtime_error("Invalid data: can't parse file"); + } + + //Only look at the front. Besides a bug in spirit makes the other counts + //invalid, see + //http://boost.2283326.n4.nabble.com/Possible-bug-in-line-pos-iterator-td4636592.html + m_count.x() = grammar.lengths.front(); + m_count.y() = m_wholedata.size() / m_count.x(); + } + + template + void TileStreamer::copy (std::vector& parDest, const coords& /*parFrom*/, const coords& /*parTo*/) { + parDest.clear(); + parDest.reserve(m_wholedata.size()); + std::copy(m_wholedata.begin(), m_wholedata.end(), std::back_inserter(parDest)); } } //namespace dk diff --git a/src/main.cpp b/src/main.cpp index b1bae91..5e40e71 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,10 +8,15 @@ int main() { typedef dk::Tyler<2> Tiler; typedef std::unique_ptr ifstreamptr; - Tiler tiler(Tiler::coords(8, 6), Tiler::coords(64)); + Tiler tiler(Tiler::coords(10, 6), Tiler::coords(64)); - auto bottom_layer = &tiler.push_layer(dk::Layer::streamer_type(ifstreamptr(new std::ifstream(DATA_PATH"test.map")))); - tiler.push_layer(dk::Layer::streamer_type(ifstreamptr(new std::ifstream(DATA_PATH"test_2.map")))); + const std::string map1(DATA_PATH"/test.map"); + const std::string map2(DATA_PATH"/test_2.map"); + + std::cout << "Loading " << map1 << '\n'; + auto bottom_layer = &tiler.push_layer(dk::Layer::streamer_type(ifstreamptr(new std::ifstream(map1)))); + std::cout << "Loading " << map2 << '\n'; + tiler.push_layer(dk::Layer::streamer_type(ifstreamptr(new std::ifstream(map2))), dk::Vector(2)); { auto ittest = bottom_layer->begin();