Spirit parser to load simple 2D maps.
This commit is contained in:
parent
bd241bbbd2
commit
e17f77ae05
5 changed files with 111 additions and 4 deletions
|
@ -6,6 +6,14 @@
|
|||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <iterator>
|
||||
|
||||
//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 <iomanip>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace dk {
|
||||
template <typename T, size_t D>
|
||||
|
@ -22,9 +30,12 @@ namespace dk {
|
|||
TileStreamer& operator= ( const TileStreamer& ) = delete;
|
||||
|
||||
void copy ( std::vector<T>& parDest, const coords& parFrom, const coords& parTo );
|
||||
const coords& tilesCount ( void ) const { return m_count; }
|
||||
|
||||
private:
|
||||
StreamPtr m_stream;
|
||||
coords m_count;
|
||||
std::vector<T> m_wholedata;
|
||||
};
|
||||
} //namespace dk
|
||||
|
||||
|
|
56
include/implem/asciimap_parser.hpp
Normal file
56
include/implem/asciimap_parser.hpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef idB6D0694FDF6B4902A244C7A51C9727FE
|
||||
#define idB6D0694FDF6B4902A244C7A51C9727FE
|
||||
|
||||
#define BOOST_SPIRIT_USE_PHOENIX_V3
|
||||
#include <boost/config/warning_disable.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/support_istream_iterator.hpp>
|
||||
#include <boost/spirit/include/support_line_pos_iterator.hpp>
|
||||
#include <boost/spirit/repository/include/qi_iter_pos.hpp>
|
||||
#include <boost/spirit/include/support_multi_pass.hpp>
|
||||
#include <boost/spirit/include/phoenix.hpp>
|
||||
#include <boost/spirit/include/phoenix_stl.hpp>
|
||||
|
||||
namespace dk { namespace implem {
|
||||
struct get_line_f {
|
||||
template <typename> struct result { typedef size_t type; };
|
||||
template <typename I> size_t operator()(const I& parStart, const I& parPosIter) const {
|
||||
return boost::spirit::get_column(parStart, parPosIter) - 1;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename I, typename T>
|
||||
struct AsciiMapGrammar : boost::spirit::qi::grammar<I, std::vector<T>()> {
|
||||
explicit AsciiMapGrammar ( const I& parItStart );
|
||||
|
||||
boost::spirit::qi::rule<I, std::vector<T>()> start;
|
||||
std::vector<int> lengths;
|
||||
boost::phoenix::function<get_line_f> getline;
|
||||
boost::spirit::qi::int_parser<T, 10, 1, 1> digit_int;
|
||||
};
|
||||
|
||||
template <typename I, typename T>
|
||||
AsciiMapGrammar<I, T>::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
|
|
@ -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 <typename T, size_t D>
|
||||
void Layer<T, D>::setActiveViewport (const coords& parFrom, const coords& parCount) {
|
||||
m_tiles.clear();
|
||||
const auto area = implem::area(parCount);
|
||||
const auto area = implem::area<D>(parCount);
|
||||
m_tiles.reserve(area);
|
||||
m_streamer.copy(m_tiles, parFrom, parFrom + parCount);
|
||||
m_activeViewport.setFrom(parFrom);
|
||||
|
|
|
@ -3,5 +3,38 @@ namespace dk {
|
|||
TileStreamer<T, D>::TileStreamer (StreamPtr&& parStream) :
|
||||
m_stream(std::move(parStream))
|
||||
{
|
||||
//TODO: this loader /only/ works with 2D tilesets, remove it asap
|
||||
|
||||
typedef std::istream_iterator<char> DataIterator;
|
||||
typedef boost::spirit::multi_pass<DataIterator> WrappedIterator;
|
||||
|
||||
*m_stream >> std::noskipws;
|
||||
|
||||
auto first = WrappedIterator(DataIterator(*m_stream));
|
||||
auto last = WrappedIterator(DataIterator());
|
||||
implem::AsciiMapGrammar<WrappedIterator, T> 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 <typename T, size_t D>
|
||||
void TileStreamer<T, D>::copy (std::vector<T>& 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
|
||||
|
|
11
src/main.cpp
11
src/main.cpp
|
@ -8,10 +8,15 @@ int main() {
|
|||
typedef dk::Tyler<2> Tiler;
|
||||
typedef std::unique_ptr<std::ifstream> 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<int>(dk::Layer<int, 2>::streamer_type(ifstreamptr(new std::ifstream(DATA_PATH"test.map"))));
|
||||
tiler.push_layer<char>(dk::Layer<char, 2>::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<int>(dk::Layer<int, 2>::streamer_type(ifstreamptr(new std::ifstream(map1))));
|
||||
std::cout << "Loading " << map2 << '\n';
|
||||
tiler.push_layer<char>(dk::Layer<char, 2>::streamer_type(ifstreamptr(new std::ifstream(map2))), dk::Vector<int, 2>(2));
|
||||
|
||||
{
|
||||
auto ittest = bottom_layer->begin();
|
||||
|
|
Loading…
Add table
Reference in a new issue