Implemented grid. Modified map renderer so that it can render tiles that have a different size than the map tiles. (Note: this change is not tested yet).
This commit is contained in:
27
src/utils/ICloneable.h
Normal file
27
src/utils/ICloneable.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* ICloneable.h
|
||||
*
|
||||
* Created on: Dec 2, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef BASE_ICLONEABLE_H_
|
||||
#define BASE_ICLONEABLE_H_
|
||||
|
||||
namespace farmlands {
|
||||
namespace utils {
|
||||
|
||||
template <typename T>
|
||||
class ICloneable
|
||||
{
|
||||
public:
|
||||
virtual ~ICloneable() { };
|
||||
virtual T* clone() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* BASE_ICLONEABLE_H_ */
|
28
src/utils/INonAssignable.h
Normal file
28
src/utils/INonAssignable.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* INonAssignable.h
|
||||
*
|
||||
* Created on: Dec 2, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef BASE_INONASSIGNABLE_H_
|
||||
#define BASE_INONASSIGNABLE_H_
|
||||
|
||||
namespace farmlands {
|
||||
namespace utils {
|
||||
|
||||
class INonAssignable
|
||||
{
|
||||
public:
|
||||
virtual ~INonAssignable() { };
|
||||
|
||||
INonAssignable() { }
|
||||
INonAssignable(const INonAssignable&) = delete;
|
||||
INonAssignable& operator=(const INonAssignable&) = delete;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* BASE_INONASSIGNABLE_H_ */
|
265
src/utils/QTree.h
Normal file
265
src/utils/QTree.h
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* QTree.h
|
||||
*
|
||||
* Created on: Dec 4, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef UTILS_QTREE_H_
|
||||
#define UTILS_QTREE_H_
|
||||
|
||||
#include <utils/Assert.h>
|
||||
#include <utils/INonAssignable.h>
|
||||
#include <utils/Rect.h>
|
||||
|
||||
namespace farmlands {
|
||||
namespace utils {
|
||||
|
||||
#if 0
|
||||
// Commented because no longer needed.
|
||||
|
||||
template <typename T>
|
||||
struct QTreeItem
|
||||
{
|
||||
T data;
|
||||
float x, y;
|
||||
};
|
||||
|
||||
/**
|
||||
* Quad tree
|
||||
*/
|
||||
template <typename T, size_t Capacity>
|
||||
class QTree : public INonAssignable
|
||||
{
|
||||
public:
|
||||
typedef int iterator;
|
||||
|
||||
QTree(const RectF& bounds);
|
||||
virtual ~QTree();
|
||||
|
||||
// Container operations
|
||||
iterator begin();
|
||||
iterator end();
|
||||
|
||||
bool empty() const;
|
||||
size_t size() const;
|
||||
|
||||
void insert(T element, float x, float y);
|
||||
void erase(iterator it);
|
||||
void clear();
|
||||
|
||||
iterator find(T element);
|
||||
iterator find(float x, float y);
|
||||
|
||||
iterator lower_bound(float x, float y);
|
||||
iterator lower_bound(float x, float y, float distance);
|
||||
iterator lower_bound(const RectF& area);
|
||||
|
||||
iterator upper_bound(float x, float y);
|
||||
iterator upper_bound(float x, float y, float distance);
|
||||
iterator upper_bound(const RectF& area);
|
||||
|
||||
private:
|
||||
void subdivide();
|
||||
void merge();
|
||||
|
||||
RectF m_bounds;
|
||||
bool m_isSplit;
|
||||
QTree* m_children[4];
|
||||
QTreeItem m_items[Capacity];
|
||||
size_t m_itemsCount;
|
||||
};
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
QTree<T, Capacity>::QTree(const RectF& bounds)
|
||||
: m_bounds(bounds),
|
||||
m_isSplit(false),
|
||||
m_children(),
|
||||
m_items(),
|
||||
m_itemsCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
QTree<T, Capacity>::~QTree()
|
||||
{
|
||||
if (m_isSplit)
|
||||
{
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
delete m_children[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::begin()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::end()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline bool QTree<T, Capacity>::empty() const
|
||||
{
|
||||
return (m_itemsCount == 0);
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline size_t QTree<T, Capacity>::size() const
|
||||
{
|
||||
return m_itemsCount;
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline void QTree<T, Capacity>::insert(T element, float x, float y)
|
||||
{
|
||||
Assert(m_bounds.contains(x, y), "Can't add element outside bounds.");
|
||||
|
||||
// Not split case
|
||||
if (!m_isSplit && m_itemsCount >= Capacity)
|
||||
subdivide();
|
||||
|
||||
// If split, add element in one of the subtrees
|
||||
if (m_isSplit)
|
||||
{
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
if (m_children[i]->m_bounds.contains(x, y))
|
||||
{
|
||||
m_children[i]->insert(element, x, y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QTreeItem<T> item =
|
||||
{
|
||||
.data = element,
|
||||
.x = x,
|
||||
.y = y
|
||||
};
|
||||
|
||||
m_items[m_itemsCount] = item;
|
||||
}
|
||||
|
||||
m_itemsCount++;
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline void QTree<T, Capacity>::erase(iterator it)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline void QTree<T, Capacity>::clear()
|
||||
{
|
||||
if (m_isSplit)
|
||||
{
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
delete m_children[i];
|
||||
m_isSplit = false;
|
||||
}
|
||||
|
||||
m_itemsCount = 0;
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::find(T element)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::find(float x, float y)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::lower_bound(float x, float y)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::lower_bound(float x, float y, float distance)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::lower_bound(const RectF& area)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::upper_bound(float x, float y)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::upper_bound(float x, float y, float distance)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
inline QTree<T, Capacity>::iterator QTree<T, Capacity>::upper_bound(const RectF& area)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
void QTree<T, Capacity>::subdivide()
|
||||
{
|
||||
Assert(!m_isSplit, "Can't subdivide if already subdivided!");
|
||||
|
||||
float halfW = m_bounds.w / 2;
|
||||
float halfH = m_bounds.h / 2;
|
||||
|
||||
RectF rects[4] =
|
||||
{
|
||||
{ m_bounds.x, m_bounds.y, halfW, halfH },
|
||||
{ m_bounds.x + halfW, m_bounds.y, halfW, halfH },
|
||||
{ m_bounds.x, m_bounds.y + halfH, halfW, halfH },
|
||||
{ m_bounds.x + halfW, m_bounds.y + halfH, halfW, halfH },
|
||||
};
|
||||
|
||||
// Allocate subtrees
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
m_children[i] = new QTree<T, Capacity>(rects[i]);
|
||||
|
||||
// Set split flag
|
||||
m_isSplit = true;
|
||||
|
||||
// Re-insert all the children
|
||||
size_t itemsCount = m_itemsCount;
|
||||
m_itemsCount = 0;
|
||||
|
||||
for (size_t i = 0; i < itemsCount; i++)
|
||||
insert(m_items[i].data, m_items[i].x, m_items[i].y);
|
||||
}
|
||||
|
||||
template<typename T, size_t Capacity>
|
||||
void QTree<T, Capacity>::merge()
|
||||
{
|
||||
Assert(m_isSplit, "Can't merge if not subdivided!");
|
||||
|
||||
// Unset split flag
|
||||
m_isSplit = false;
|
||||
|
||||
// Put all the children in their places
|
||||
m_itemsCount = 0;
|
||||
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
{
|
||||
Assert(!m_children[i].m_isSplit, "Cannot merge if children are split!!!");
|
||||
|
||||
for (size_t j = 0; j < m_children[i].m_itemsCount; j++)
|
||||
insert(m_children[i].m_items[j].data, m_children[i].m_items[j].x, m_children[i].m_items[j].y);
|
||||
|
||||
delete m_children[i];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} /* namespace utils */
|
||||
} /* namespace farmlands */
|
||||
|
||||
#endif /* UTILS_QTREE_H_ */
|
50
src/utils/Rect.h
Normal file
50
src/utils/Rect.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Rect.h
|
||||
*
|
||||
* Created on: Dec 4, 2016
|
||||
* Author: tibi
|
||||
*/
|
||||
|
||||
#ifndef UTILS_RECT_H_
|
||||
#define UTILS_RECT_H_
|
||||
|
||||
namespace farmlands {
|
||||
namespace utils {
|
||||
|
||||
template <typename T>
|
||||
class Rect
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
Rect()
|
||||
: x(), y(), w(), h() { }
|
||||
|
||||
Rect(T x, T y, T w, T h)
|
||||
: x(x), y(y), w(w), h(h) { }
|
||||
|
||||
bool contains(T px, T py)
|
||||
{
|
||||
bool containsX = (x <= px && px <= x + w);
|
||||
bool containsY = (y <= px && px <= x + w);
|
||||
|
||||
return containsX && containsY;
|
||||
}
|
||||
|
||||
bool intersects(const Rect<T> other)
|
||||
{
|
||||
bool intersectsX = (x <= other.x && other.x <= x + w) || (other.x <= x && other.x + other.w >= x);
|
||||
bool intersectsY = (y <= other.y && other.y <= y + h) || (other.y <= y && other.y + other.h >= y);
|
||||
|
||||
return intersectsX && intersectsY;
|
||||
}
|
||||
|
||||
// Values
|
||||
T x, y, w, h;
|
||||
};
|
||||
|
||||
typedef Rect<float> RectF;
|
||||
|
||||
} /* namespace utils */
|
||||
} /* namespace farmlands */
|
||||
|
||||
#endif /* UTILS_RECT_H_ */
|
Reference in New Issue
Block a user