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:
		@@ -14,6 +14,10 @@
 | 
			
		||||
        <BackgroundRenderer />
 | 
			
		||||
    </GameObject>
 | 
			
		||||
    
 | 
			
		||||
    <GameObject name="Object Layer">
 | 
			
		||||
        <Grid w="380" h="250" />
 | 
			
		||||
    </GameObject>
 | 
			
		||||
    
 | 
			
		||||
    <!-- Player object -->
 | 
			
		||||
    <GameObject name="Player">
 | 
			
		||||
        <Transform x="120" y="100" />
 | 
			
		||||
@@ -32,4 +36,10 @@
 | 
			
		||||
        <DebugController />
 | 
			
		||||
    </GameObject>
 | 
			
		||||
    
 | 
			
		||||
    <GameObject name="enemyTest">
 | 
			
		||||
        <Transform x="125" y="110" />
 | 
			
		||||
        <Sprite src="sprites/Player.sprite" />
 | 
			
		||||
        <SpriteRenderer />
 | 
			
		||||
    </GameObject>
 | 
			
		||||
    
 | 
			
		||||
</Scene>
 | 
			
		||||
@@ -49,8 +49,8 @@ FILE_TYPES = [
 | 
			
		||||
    ([".sprite"], "Sprite"),
 | 
			
		||||
    ([".config"], "Configuration"),
 | 
			
		||||
    ([".scene"], "Scene"),
 | 
			
		||||
    ([".back"], "Background"),
 | 
			
		||||
    ([".csv"], "BackgroundLayer"),
 | 
			
		||||
    ([".back"], "Map"),
 | 
			
		||||
    ([".csv"], "MapLayer"),
 | 
			
		||||
    ([".item"], "Item"),
 | 
			
		||||
    ([".items"], "ItemCollection"),
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
@@ -11,9 +11,10 @@ namespace farmlands {
 | 
			
		||||
GameState GameState::s_current;
 | 
			
		||||
 | 
			
		||||
GameState::GameState()
 | 
			
		||||
	: renderContext(),
 | 
			
		||||
	: config(nullptr),
 | 
			
		||||
	  renderContext(),
 | 
			
		||||
	  scene(nullptr),
 | 
			
		||||
	  config(nullptr),
 | 
			
		||||
	  itemPrefabs(),
 | 
			
		||||
	  elapsedTime(0),
 | 
			
		||||
	  gameInitialized(false)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -1,80 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Background.cpp
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: Dec 1, 2016
 | 
			
		||||
 *      Author: tibi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <components/Background.h>
 | 
			
		||||
#include <utils/Assert.h>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Background::Background(size_t layerCount, size_t rowCount, size_t columnCount)
 | 
			
		||||
	: m_cells(new Cell[layerCount * rowCount * columnCount]),
 | 
			
		||||
	  m_textures(new resources::ResourceId[layerCount]),
 | 
			
		||||
	  m_layers(layerCount),
 | 
			
		||||
	  m_rows(rowCount),
 | 
			
		||||
	  m_columns(columnCount)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Background::~Background()
 | 
			
		||||
{
 | 
			
		||||
	delete[] m_cells;
 | 
			
		||||
	delete[] m_textures;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model::Component* Background::clone()
 | 
			
		||||
{
 | 
			
		||||
	Background* clone = new Background(m_layers, m_rows, m_columns);
 | 
			
		||||
	memcpy(clone->m_cells, m_cells, sizeof(Cell) * m_layers * m_rows * m_columns);
 | 
			
		||||
	memcpy(clone->m_textures, m_textures, sizeof(resources::ResourceId) * m_layers);
 | 
			
		||||
 | 
			
		||||
	return clone;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Cell Background::cell(size_t layer, size_t row, size_t col) const
 | 
			
		||||
{
 | 
			
		||||
	Assert(layer < m_layers, "Layer out of bounds.");
 | 
			
		||||
	Assert(row < m_rows, "Row out of bounds.");
 | 
			
		||||
	Assert(col < m_columns, "Column out of bounds.");
 | 
			
		||||
 | 
			
		||||
	return m_cells[layer * m_rows * m_columns + row * m_columns + col];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Background::setCell(size_t layer, size_t row, size_t col, Cell value)
 | 
			
		||||
{
 | 
			
		||||
	Assert(layer < m_layers, "Layer out of bounds.");
 | 
			
		||||
	Assert(row < m_rows, "Row out of bounds.");
 | 
			
		||||
	Assert(col < m_columns, "Column out of bounds.");
 | 
			
		||||
 | 
			
		||||
	m_cells[layer * m_rows * m_columns + row * m_columns + col] = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
resources::ResourceId Background::texture(size_t layer) const
 | 
			
		||||
{
 | 
			
		||||
	Assert(layer < m_layers, "Layer out of bounds.");
 | 
			
		||||
	return m_textures[layer];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Background::setTexture(size_t layer, resources::ResourceId textureId) const
 | 
			
		||||
{
 | 
			
		||||
	Assert(layer < m_layers, "Layer out of bounds.");
 | 
			
		||||
	m_textures[layer] = textureId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Background::dump(unsigned level)
 | 
			
		||||
{
 | 
			
		||||
	for (unsigned i = 0; i < level; i++)
 | 
			
		||||
		std::cout<<"    ";
 | 
			
		||||
 | 
			
		||||
	std::cout << "  .Component: Background\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace model */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
@@ -1,49 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Background.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: Dec 1, 2016
 | 
			
		||||
 *      Author: tibi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef MODEL_BACKGROUND_H_
 | 
			
		||||
#define MODEL_BACKGROUND_H_
 | 
			
		||||
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
#include <resources/ResourceManager.h>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
 | 
			
		||||
	typedef int16_t Cell;
 | 
			
		||||
 | 
			
		||||
	class Background: public model::Component
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		Background(size_t layerCount, size_t rowCount, size_t columnCount);
 | 
			
		||||
		virtual ~Background();
 | 
			
		||||
 | 
			
		||||
		virtual model::Component* clone() override;
 | 
			
		||||
		virtual void dump(unsigned level) override;
 | 
			
		||||
 | 
			
		||||
		inline size_t layerCount() const { return m_layers; }
 | 
			
		||||
		inline size_t rowCount()  const { return m_rows; }
 | 
			
		||||
		inline size_t columnCount() const { return m_columns; }
 | 
			
		||||
 | 
			
		||||
		Cell cell(size_t layer, size_t row, size_t col) const;
 | 
			
		||||
		void setCell(size_t layer, size_t row, size_t col, Cell value);
 | 
			
		||||
 | 
			
		||||
		resources::ResourceId texture(size_t layer) const;
 | 
			
		||||
		void setTexture(size_t layer, resources::ResourceId textureId) const;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		Cell* m_cells;
 | 
			
		||||
		resources::ResourceId* m_textures;
 | 
			
		||||
		size_t m_layers;
 | 
			
		||||
		size_t m_rows;
 | 
			
		||||
		size_t m_columns;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
} /* namespace model */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
 | 
			
		||||
#endif /* MODEL_BACKGROUND_H_ */
 | 
			
		||||
							
								
								
									
										113
									
								
								src/components/Map.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/components/Map.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Background.cpp
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: Dec 1, 2016
 | 
			
		||||
 *      Author: tibi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <components/Map.h>
 | 
			
		||||
#include <utils/Assert.h>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
 | 
			
		||||
/****** MapLayer implementation ******/
 | 
			
		||||
 | 
			
		||||
MapLayer::MapLayer(size_t w, size_t h)
 | 
			
		||||
	: name(),
 | 
			
		||||
	  tileSet(),
 | 
			
		||||
	  m_cells(new Cell[w * h]),
 | 
			
		||||
	  m_w(w), m_h(h)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MapLayer* MapLayer::clone()
 | 
			
		||||
{
 | 
			
		||||
	auto clone = new MapLayer(m_w, m_h);
 | 
			
		||||
	clone->name = name;
 | 
			
		||||
	clone->tileSet = tileSet;
 | 
			
		||||
	memcpy(clone->m_cells, m_cells, sizeof(Cell) * m_w * m_h);
 | 
			
		||||
 | 
			
		||||
	return clone;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Cell MapLayer::get(size_t row, size_t col) const
 | 
			
		||||
{
 | 
			
		||||
	Assert(row < m_w && col < m_h, "Index out of bounds.");
 | 
			
		||||
 | 
			
		||||
	return m_cells[row * m_w + col];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Cell* MapLayer::operator [](size_t row)
 | 
			
		||||
{
 | 
			
		||||
	Assert(row < m_w, "Index out of bounds.");
 | 
			
		||||
 | 
			
		||||
	return m_cells + (row * m_w);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MapLayer::set(size_t row, size_t col, Cell value)
 | 
			
		||||
{
 | 
			
		||||
	m_cells[row * m_w + col] = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/****** Map implementation ******/
 | 
			
		||||
 | 
			
		||||
Map::~Map()
 | 
			
		||||
{
 | 
			
		||||
	for (MapLayer* layer : m_layers)
 | 
			
		||||
		delete layer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model::Component* Map::clone()
 | 
			
		||||
{
 | 
			
		||||
	Map* clone = new Map();
 | 
			
		||||
	clone->width = width;
 | 
			
		||||
	clone->height = height;
 | 
			
		||||
 | 
			
		||||
	for (MapLayer* layer : m_layers)
 | 
			
		||||
	{
 | 
			
		||||
		MapLayer* layerClone = layer->clone();
 | 
			
		||||
		clone->m_layers.push_back(layerClone);
 | 
			
		||||
		clone->m_layersStr.emplace(layerClone->name, clone);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return clone;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Map::dump(unsigned level)
 | 
			
		||||
{
 | 
			
		||||
	for (unsigned i = 0; i < level; i++)
 | 
			
		||||
		std::cout<<"    ";
 | 
			
		||||
 | 
			
		||||
	std::cout << "  .Component: Background\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MapLayer& Map::addLayer(std::string name)
 | 
			
		||||
{
 | 
			
		||||
	Assert(m_layersStr.count(name) == 0, "Layer with same name already exists!");
 | 
			
		||||
 | 
			
		||||
	MapLayer* layer = new MapLayer(width, height);
 | 
			
		||||
	layer->name = name;
 | 
			
		||||
	m_layers.push_back(layer);
 | 
			
		||||
	m_layersStr.emplace(name, layer);
 | 
			
		||||
 | 
			
		||||
	return *layer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MapLayer& Map::layer(size_t index)
 | 
			
		||||
{
 | 
			
		||||
	return *m_layers.at(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MapLayer& Map::layer(std::string name)
 | 
			
		||||
{
 | 
			
		||||
	return *(MapLayer*)m_layersStr.at(name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace model */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										73
									
								
								src/components/Map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/components/Map.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Map.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: Dec 1, 2016
 | 
			
		||||
 *      Author: tibi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef MODEL_MAP_H_
 | 
			
		||||
#define MODEL_MAP_H_
 | 
			
		||||
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
#include <model/TileSet.h>
 | 
			
		||||
#include <resources/ResourceManager.h>
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
 | 
			
		||||
	typedef int16_t Cell;
 | 
			
		||||
 | 
			
		||||
	class MapLayer : utils::ICloneable<MapLayer>
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		MapLayer(size_t w, size_t h);
 | 
			
		||||
		virtual MapLayer* clone() override;
 | 
			
		||||
 | 
			
		||||
		// Getters
 | 
			
		||||
		Cell get(size_t row, size_t col) const;
 | 
			
		||||
		Cell* operator[] (size_t row);
 | 
			
		||||
 | 
			
		||||
		// Setters
 | 
			
		||||
		void set(size_t row, size_t col, Cell value);
 | 
			
		||||
 | 
			
		||||
		// Public properties
 | 
			
		||||
		std::string name;
 | 
			
		||||
		model::TileSet tileSet;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		Cell* m_cells;
 | 
			
		||||
		size_t m_w, m_h;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class Map: public model::Component
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		virtual ~Map();
 | 
			
		||||
 | 
			
		||||
		virtual model::Component* clone() override;
 | 
			
		||||
		virtual void dump(unsigned level) override;
 | 
			
		||||
 | 
			
		||||
		// Layer operations
 | 
			
		||||
		MapLayer& addLayer(std::string name);
 | 
			
		||||
		MapLayer& layer(size_t index);
 | 
			
		||||
		MapLayer& layer(std::string name);
 | 
			
		||||
 | 
			
		||||
		size_t layersCount() const { return m_layers.size(); }
 | 
			
		||||
 | 
			
		||||
		// Size counted in cells
 | 
			
		||||
		size_t width, height;
 | 
			
		||||
		size_t cellWidth, cellHeight;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		std::vector<MapLayer*> m_layers;
 | 
			
		||||
		std::map<std::string, void*> m_layersStr; // gcc gives error if I use MapLayer*
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
} /* namespace model */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
 | 
			
		||||
#endif /* MODEL_BACKGROUND_H_ */
 | 
			
		||||
							
								
								
									
										146
									
								
								src/components/basic/Grid.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								src/components/basic/Grid.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Grid.cpp
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: Dec 4, 2016
 | 
			
		||||
 *      Author: tibi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <components/basic/Grid.h>
 | 
			
		||||
#include <components/basic/Transform.h>
 | 
			
		||||
#include <utils/Assert.h>
 | 
			
		||||
#include <utils/Exceptions.h>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
using namespace farmlands::model;
 | 
			
		||||
using namespace farmlands::utils;
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace basic {
 | 
			
		||||
 | 
			
		||||
Grid::Grid()
 | 
			
		||||
	: m_bounds(0, 0, 1, 1),
 | 
			
		||||
	  m_grid(nullptr)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Grid::~Grid()
 | 
			
		||||
{
 | 
			
		||||
	if (m_grid != nullptr)
 | 
			
		||||
		delete[] m_grid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model::Component* Grid::clone()
 | 
			
		||||
{
 | 
			
		||||
	Grid* clone = new Grid();
 | 
			
		||||
	clone->m_bounds = m_bounds;
 | 
			
		||||
 | 
			
		||||
	return clone;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Grid::dump(unsigned level)
 | 
			
		||||
{
 | 
			
		||||
	for (unsigned i = 0; i < level; i++)
 | 
			
		||||
		std::cout<<"    ";
 | 
			
		||||
 | 
			
		||||
	std::cout << "  .Component: Grid bounds=[";
 | 
			
		||||
	std::cout << m_bounds.x << "," << m_bounds.y << ",";
 | 
			
		||||
	std::cout << m_bounds.w << "," << m_bounds.h << "]\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Grid::onInitialize()
 | 
			
		||||
{
 | 
			
		||||
	// Allocate memory
 | 
			
		||||
	m_grid = new model::GameObject*[m_bounds.w * m_bounds.h];
 | 
			
		||||
	memset(m_grid, 0, sizeof(model::GameObject*) * m_bounds.w * m_bounds.h);
 | 
			
		||||
 | 
			
		||||
	// Add objects
 | 
			
		||||
	for (auto it = gameObject->childrenBegin(); it != gameObject->childrenEnd(); it++)
 | 
			
		||||
	{
 | 
			
		||||
		GameObject* obj = *it;
 | 
			
		||||
 | 
			
		||||
		// Get transform
 | 
			
		||||
		Transform* tr = obj->component<Transform>();
 | 
			
		||||
		if (tr == nullptr)
 | 
			
		||||
		{
 | 
			
		||||
			std::cerr << "Grid: ignoring object " << obj->name << ": object has no transform.";
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Compute grid position(s)
 | 
			
		||||
		Rect<int> bounds(tr->x, tr->y, roundf(tr->w), roundf(tr->h));
 | 
			
		||||
		if (!bounds.intersects(m_bounds))
 | 
			
		||||
		{
 | 
			
		||||
			std::cerr << "Grid: ignoring object " << obj->name << ": object outside allowed bounds.";
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Set
 | 
			
		||||
		for (int y = bounds.y; y < bounds.y + bounds.h; y++)
 | 
			
		||||
			for (int x = bounds.x; x < bounds.x + bounds.w; x++)
 | 
			
		||||
				set(obj, x, y, false);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Grid::setBounds(const utils::Rect<int>& bounds)
 | 
			
		||||
{
 | 
			
		||||
	if (m_grid == nullptr)
 | 
			
		||||
		m_bounds = bounds;
 | 
			
		||||
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		// Get rid of old grid
 | 
			
		||||
		delete[] m_grid;
 | 
			
		||||
		m_grid = nullptr;
 | 
			
		||||
 | 
			
		||||
		m_bounds = bounds;
 | 
			
		||||
 | 
			
		||||
		// Reinitialize
 | 
			
		||||
		onInitialize();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
utils::Rect<int> Grid::bounds() const
 | 
			
		||||
{
 | 
			
		||||
	return m_bounds;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model::GameObject* Grid::get(int x, int y)
 | 
			
		||||
{
 | 
			
		||||
	Assert(m_grid != nullptr, "Grid not initialized!!!");
 | 
			
		||||
 | 
			
		||||
	if (m_bounds.contains(x, y))
 | 
			
		||||
	{
 | 
			
		||||
		int gx = x - m_bounds.x;
 | 
			
		||||
		int gy = y - m_bounds.y;
 | 
			
		||||
 | 
			
		||||
		return m_grid[gy * m_bounds.w + gx];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Grid::set(model::GameObject* obj, int x, int y, bool throwOnOverwrite)
 | 
			
		||||
{
 | 
			
		||||
	int gx = x - m_bounds.x;
 | 
			
		||||
	int gy = y - m_bounds.y;
 | 
			
		||||
	int index = gy * m_bounds.w + gx;
 | 
			
		||||
 | 
			
		||||
	if (m_grid[index] != nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		if (throwOnOverwrite)
 | 
			
		||||
			THROW(InvalidArgumentException, "Position already occupied!");
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			std::cerr << "Grid: cannot set " << obj->name << " to position " << x << ", " << y;
 | 
			
		||||
			std::cerr << ": cell already occupied";
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m_grid[index] = obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace basic */
 | 
			
		||||
} /* namespace components */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
							
								
								
									
										82
									
								
								src/components/basic/Grid.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/components/basic/Grid.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Grid.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: Dec 4, 2016
 | 
			
		||||
 *      Author: tibi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef COMPONENTS_BASIC_GRID_H_
 | 
			
		||||
#define COMPONENTS_BASIC_GRID_H_
 | 
			
		||||
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
#include <model/GameObject.h>
 | 
			
		||||
#include <utils/Rect.h>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace basic {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Manages all the children components so that they are in a grid.
 | 
			
		||||
	 * Uses the x and y positions of the game objects to find the grid position.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Positions are read in the initialize method.
 | 
			
		||||
	 * If there are multiple objects in the same cell position, only the first one is considered.
 | 
			
		||||
	 * If there are objects outside the given bounds, they are ignored.
 | 
			
		||||
	 *
 | 
			
		||||
	 *
 | 
			
		||||
	 * Operation:
 | 
			
		||||
	 *   After initialization, use get to obtain the element in a specific grid position.
 | 
			
		||||
	 *   When adding a game object to the parent, make sure to call "update on the grid".
 | 
			
		||||
	 *
 | 
			
		||||
	 *   The update/move methods check if a non-empty cell will be written over, and they throw
 | 
			
		||||
	 *   an exception.
 | 
			
		||||
	 */
 | 
			
		||||
	class Grid: public model::Component
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		Grid();
 | 
			
		||||
		virtual ~Grid();
 | 
			
		||||
 | 
			
		||||
		virtual model::Component* clone() override;
 | 
			
		||||
		virtual void dump(unsigned level) override;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Initializes the grid component.
 | 
			
		||||
		 *
 | 
			
		||||
		 * When this method gets called, the grid puts all the children game objects in corresponding
 | 
			
		||||
		 * cells. The object transform is used to calculate what cells the objects occupy (x, y, w, h).
 | 
			
		||||
		 *
 | 
			
		||||
		 * If there are multiple objects in the same cell position, only the first one is considered.
 | 
			
		||||
		 * (a warning is printed to stderr).
 | 
			
		||||
		 * Also, if there are objects outside the given bounds, they are ignored.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual void onInitialize() override;
 | 
			
		||||
 | 
			
		||||
		// Setters
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Sets the bounds of the grid.
 | 
			
		||||
		 *
 | 
			
		||||
		 * If the bounds are changed after initialization, the positions will be updated.
 | 
			
		||||
		 */
 | 
			
		||||
		void setBounds(const utils::Rect<int>& bounds);
 | 
			
		||||
 | 
			
		||||
		// Getters
 | 
			
		||||
		utils::Rect<int> bounds() const;
 | 
			
		||||
 | 
			
		||||
		// Operations
 | 
			
		||||
		model::GameObject* get(int x, int y);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void set(model::GameObject* obj, int x, int y, bool throwOnOverwrite);
 | 
			
		||||
 | 
			
		||||
		utils::Rect<int> m_bounds;
 | 
			
		||||
		model::GameObject** m_grid;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
} /* namespace basic */
 | 
			
		||||
} /* namespace components */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
 | 
			
		||||
#endif /* COMPONENTS_BASIC_GRID_H_ */
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <GameState.h>
 | 
			
		||||
#include <components/basic/Transform.h>
 | 
			
		||||
#include <components/basic/Sprite.h>
 | 
			
		||||
#include <utils/Assert.h>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,16 +6,18 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <GameState.h>
 | 
			
		||||
#include <components/GuiController.h>
 | 
			
		||||
#include <components/gui/GuiController.h>
 | 
			
		||||
#include <gui/widgets/TextArea.h>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace gui {
 | 
			
		||||
 | 
			
		||||
GuiController::GuiController()
 | 
			
		||||
	: m_canvas()
 | 
			
		||||
	: m_canvas(),
 | 
			
		||||
	  m_context(nullptr)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -36,16 +38,16 @@ void GuiController::onInitialize()
 | 
			
		||||
	m_canvas.setSize(m_context->viewport.width, m_context->viewport.height);
 | 
			
		||||
 | 
			
		||||
	// Add a text element
 | 
			
		||||
	auto text = new gui::widgets::TextArea();
 | 
			
		||||
	auto text = new farmlands::gui::widgets::TextArea();
 | 
			
		||||
	text->setText("Hello world!");
 | 
			
		||||
	text->setSize(50, 5);
 | 
			
		||||
	text->setPosition(100, 10);
 | 
			
		||||
	text->setColor(0, 1, 0);
 | 
			
		||||
	text->setBackColor(0.5f, 0, 0, 0.5f);
 | 
			
		||||
	text->setTextSize(11);
 | 
			
		||||
	text->setHorizontalWrap(gui::widgets::TextHorizontalWrapping::Ellipsis);
 | 
			
		||||
	text->setVerticalWrap(gui::widgets::TextVerticalWrapping::Trim);
 | 
			
		||||
	text->setAlignment(gui::widgets::TextAlign::BottomRight);
 | 
			
		||||
	text->setHorizontalWrap(farmlands::gui::widgets::TextHorizontalWrapping::Ellipsis);
 | 
			
		||||
	text->setVerticalWrap(farmlands::gui::widgets::TextVerticalWrapping::Trim);
 | 
			
		||||
	text->setAlignment(farmlands::gui::widgets::TextAlign::BottomRight);
 | 
			
		||||
	m_canvas.addChild(text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -82,5 +84,6 @@ void GuiController::dump(unsigned level)
 | 
			
		||||
	std::cout << "  .Component: DebugController\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} /* namespace controller */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
@@ -16,6 +16,7 @@
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace gui {
 | 
			
		||||
 | 
			
		||||
	class GuiController : public model::Component
 | 
			
		||||
	{
 | 
			
		||||
@@ -34,10 +35,11 @@ namespace components {
 | 
			
		||||
		virtual void onRender() override;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		gui::layout::Canvas m_canvas;
 | 
			
		||||
		farmlands::gui::layout::Canvas m_canvas;
 | 
			
		||||
		graphics::RenderContext* m_context;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} /* namespace controller */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
 | 
			
		||||
@@ -8,14 +8,14 @@
 | 
			
		||||
#ifndef COMPONENTS_ITEMS_AXE_H_
 | 
			
		||||
#define COMPONENTS_ITEMS_AXE_H_
 | 
			
		||||
 | 
			
		||||
#include <components/items/ITool.h>
 | 
			
		||||
#include <components/items/IPlayerAction.h>
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace items {
 | 
			
		||||
 | 
			
		||||
	class Axe: public model::Component, public ITool
 | 
			
		||||
	class Axe: public model::Component, public IPlayerAction
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		Axe();
 | 
			
		||||
 
 | 
			
		||||
@@ -8,14 +8,14 @@
 | 
			
		||||
#ifndef CONTROLLER_ITEMS_GIFTABLE_H_
 | 
			
		||||
#define CONTROLLER_ITEMS_GIFTABLE_H_
 | 
			
		||||
 | 
			
		||||
#include <components/items/ITool.h>
 | 
			
		||||
#include <components/items/IPlayerAction.h>
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace items {
 | 
			
		||||
 | 
			
		||||
	class Giftable: public model::Component, public ITool
 | 
			
		||||
	class Giftable: public model::Component, public IPlayerAction
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		Giftable();
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ namespace components {
 | 
			
		||||
namespace items {
 | 
			
		||||
 | 
			
		||||
Hoe::Hoe()
 | 
			
		||||
	: m_back(nullptr)
 | 
			
		||||
	: m_map(nullptr)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -47,15 +47,15 @@ void Hoe::onInitialize()
 | 
			
		||||
	model::GameObject* root = &GameState::current().scene->root;
 | 
			
		||||
 | 
			
		||||
	// Find background object
 | 
			
		||||
	auto it = root->findByComponent<Background>();
 | 
			
		||||
	auto it = root->findByComponent<Map>();
 | 
			
		||||
	Assert(it != root->childrenEnd(), "Can't find background game object.");
 | 
			
		||||
 | 
			
		||||
	m_back = (*it)->component<Background>();
 | 
			
		||||
	m_map = (*it)->component<Map>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Hoe::performAction(float x, float y, model::Direction d)
 | 
			
		||||
{
 | 
			
		||||
	Assert(m_back, "No background object!!!");
 | 
			
		||||
	Assert(m_map, "No background object!!!");
 | 
			
		||||
 | 
			
		||||
	// Compute watering position
 | 
			
		||||
	float digX, digY;
 | 
			
		||||
@@ -65,11 +65,11 @@ void Hoe::performAction(float x, float y, model::Direction d)
 | 
			
		||||
	size_t row = floorf(digY);
 | 
			
		||||
 | 
			
		||||
	// See what the cell contains
 | 
			
		||||
	Cell backCell = m_back->cell(0, row, col);
 | 
			
		||||
	Cell soilCell = m_back->cell(1, row, col);
 | 
			
		||||
	Cell backCell = m_map->layer(0).get(row, col);
 | 
			
		||||
	Cell soilCell = m_map->layer(1).get(row, col);
 | 
			
		||||
 | 
			
		||||
	if (groundIsDirt(backCell) && soilCell == Ground::None)
 | 
			
		||||
		m_back->setCell(1, row, col, Ground::SoilDry);
 | 
			
		||||
		m_map->layer(1)[row][col] = Ground::SoilDry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace items */
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,8 @@
 | 
			
		||||
#ifndef COMPONENTS_ITEMS_HOE_H_
 | 
			
		||||
#define COMPONENTS_ITEMS_HOE_H_
 | 
			
		||||
 | 
			
		||||
#include <components/Background.h>
 | 
			
		||||
#include <components/items/ITool.h>
 | 
			
		||||
#include <components/items/IPlayerAction.h>
 | 
			
		||||
#include <components/Map.h>
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
#include <model/Direction.h>
 | 
			
		||||
 | 
			
		||||
@@ -17,7 +17,7 @@ namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace items {
 | 
			
		||||
 | 
			
		||||
	class Hoe: public model::Component, public ITool
 | 
			
		||||
	class Hoe: public model::Component, public IPlayerAction
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		Hoe();
 | 
			
		||||
@@ -31,7 +31,7 @@ namespace items {
 | 
			
		||||
		virtual void performAction(float x, float y, model::Direction d) override;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		Background* m_back;
 | 
			
		||||
		Map* m_map;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
} /* namespace items */
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@
 | 
			
		||||
 *      Author: tibi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef COMPONENTS_ITEMS_ITOOL_H_
 | 
			
		||||
#define COMPONENTS_ITEMS_ITOOL_H_
 | 
			
		||||
#ifndef COMPONENTS_ITEMS_IPLAYERACTION_H_
 | 
			
		||||
#define COMPONENTS_ITEMS_IPLAYERACTION_H_
 | 
			
		||||
 | 
			
		||||
#include <model/Direction.h>
 | 
			
		||||
 | 
			
		||||
@@ -14,15 +14,17 @@ namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace items {
 | 
			
		||||
 | 
			
		||||
	class ITool
 | 
			
		||||
	class IPlayerAction
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		virtual ~ITool() { }
 | 
			
		||||
		virtual ~IPlayerAction() { }
 | 
			
		||||
		virtual void performAction(float playerX, float playerY, model::Direction) = 0;
 | 
			
		||||
 | 
			
		||||
		float actionCost;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
} /* namespace items */
 | 
			
		||||
} /* namespace components */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
 | 
			
		||||
#endif /* COMPONENTS_ITEMS_ITOOL_H_ */
 | 
			
		||||
#endif /* COMPONENTS_ITEMS_IPLAYERACTION_H_ */
 | 
			
		||||
@@ -8,14 +8,14 @@
 | 
			
		||||
#ifndef COMPONENTS_ITEMS_PICKAXE_H_
 | 
			
		||||
#define COMPONENTS_ITEMS_PICKAXE_H_
 | 
			
		||||
 | 
			
		||||
#include <components/items/ITool.h>
 | 
			
		||||
#include <components/items/IPlayerAction.h>
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace items {
 | 
			
		||||
 | 
			
		||||
	class Pickaxe: public model::Component, public ITool
 | 
			
		||||
	class Pickaxe: public model::Component, public IPlayerAction
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		Pickaxe();
 | 
			
		||||
 
 | 
			
		||||
@@ -8,14 +8,14 @@
 | 
			
		||||
#ifndef COMPONENTS_ITEMS_SCYTHE_H_
 | 
			
		||||
#define COMPONENTS_ITEMS_SCYTHE_H_
 | 
			
		||||
 | 
			
		||||
#include <components/items/ITool.h>
 | 
			
		||||
#include <components/items/IPlayerAction.h>
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace items {
 | 
			
		||||
 | 
			
		||||
	class Scythe: public model::Component, public ITool
 | 
			
		||||
	class Scythe: public model::Component, public IPlayerAction
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		Scythe();
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ namespace items {
 | 
			
		||||
WateringCan::WateringCan()
 | 
			
		||||
	: capacity(10),
 | 
			
		||||
	  amountLeft(10),
 | 
			
		||||
	  m_back(nullptr)
 | 
			
		||||
	  m_map(nullptr)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -52,15 +52,15 @@ void WateringCan::onInitialize()
 | 
			
		||||
	model::GameObject* root = &GameState::current().scene->root;
 | 
			
		||||
 | 
			
		||||
	// Find background object
 | 
			
		||||
	auto it = root->findByComponent<Background>();
 | 
			
		||||
	auto it = root->findByComponent<Map>();
 | 
			
		||||
	Assert(it != root->childrenEnd(), "Can't find background game object.");
 | 
			
		||||
 | 
			
		||||
	m_back = (*it)->component<Background>();
 | 
			
		||||
	m_map = (*it)->component<Map>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WateringCan::performAction(float x, float y, model::Direction d)
 | 
			
		||||
{
 | 
			
		||||
	Assert(m_back, "No background object!!!");
 | 
			
		||||
	Assert(m_map, "No background object!!!");
 | 
			
		||||
 | 
			
		||||
	// Compute watering position
 | 
			
		||||
	float digX, digY;
 | 
			
		||||
@@ -70,8 +70,8 @@ void WateringCan::performAction(float x, float y, model::Direction d)
 | 
			
		||||
	size_t row = floorf(digY);
 | 
			
		||||
 | 
			
		||||
	// See what the cell contains
 | 
			
		||||
	Cell backCell = m_back->cell(0, row, col);
 | 
			
		||||
	Cell soilCell = m_back->cell(1, row, col);
 | 
			
		||||
	Cell backCell = m_map->layer(0).get(row, col);
 | 
			
		||||
	Cell soilCell = m_map->layer(1).get(row, col);
 | 
			
		||||
 | 
			
		||||
	// If there is water, fill can
 | 
			
		||||
	if (backCell == Ground::Water)
 | 
			
		||||
@@ -83,7 +83,7 @@ void WateringCan::performAction(float x, float y, model::Direction d)
 | 
			
		||||
	// If there is dry soil, wet it
 | 
			
		||||
	if (groundIsDrySoil(soilCell) && amountLeft > 0)
 | 
			
		||||
	{
 | 
			
		||||
		m_back->setCell(1, row, col, Ground::SoilWet);
 | 
			
		||||
		m_map->layer(1)[row][col] = Ground::SoilWet;
 | 
			
		||||
		--amountLeft;
 | 
			
		||||
 | 
			
		||||
		std::cout << "Watering can: " << amountLeft << "\n";
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,8 @@
 | 
			
		||||
#ifndef COMPONENTS_ITEMS_WATERINGCAN_H_
 | 
			
		||||
#define COMPONENTS_ITEMS_WATERINGCAN_H_
 | 
			
		||||
 | 
			
		||||
#include <components/Background.h>
 | 
			
		||||
#include <components/items/ITool.h>
 | 
			
		||||
#include <components/items/IPlayerAction.h>
 | 
			
		||||
#include <components/Map.h>
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
#include <model/Direction.h>
 | 
			
		||||
 | 
			
		||||
@@ -17,7 +17,7 @@ namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace items {
 | 
			
		||||
 | 
			
		||||
	class WateringCan: public model::Component, public ITool
 | 
			
		||||
	class WateringCan: public model::Component, public IPlayerAction
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		WateringCan();
 | 
			
		||||
@@ -35,7 +35,7 @@ namespace items {
 | 
			
		||||
		uint32_t amountLeft;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		Background* m_back;
 | 
			
		||||
		Map* m_map;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
} /* namespace items */
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
#define CONTROLLER_ITEMS_WEAPON_H_
 | 
			
		||||
 | 
			
		||||
#include <components/basic/Sprite.h>
 | 
			
		||||
#include <components/items/ITool.h>
 | 
			
		||||
#include <components/items/IPlayerAction.h>
 | 
			
		||||
#include <graphics/SpriteRenderer.h>
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
 | 
			
		||||
@@ -17,7 +17,7 @@ namespace farmlands {
 | 
			
		||||
namespace components {
 | 
			
		||||
namespace items {
 | 
			
		||||
 | 
			
		||||
	class Weapon: public model::Component, public ITool
 | 
			
		||||
	class Weapon: public model::Component, public IPlayerAction
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		Weapon();
 | 
			
		||||
 
 | 
			
		||||
@@ -91,6 +91,7 @@ void PlayerInventory::onInitialize()
 | 
			
		||||
bool PlayerInventory::onEvent(SDL_Event& event)
 | 
			
		||||
{
 | 
			
		||||
	handleAttackEvents(event);
 | 
			
		||||
	handleCurrentInventoryItemEvent(event);
 | 
			
		||||
	handleInventoryEvents(event);
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
@@ -106,9 +107,18 @@ void PlayerInventory::onPreRender()
 | 
			
		||||
	if (currentItem)
 | 
			
		||||
	{
 | 
			
		||||
		Transform* itemTransf = currentItem->component<Transform>();
 | 
			
		||||
 | 
			
		||||
		if (m_playerMovement->facingDirection & Direction::East)
 | 
			
		||||
		{
 | 
			
		||||
			itemTransf->x = 0.2f;
 | 
			
		||||
			itemTransf->y = -0.8f;
 | 
			
		||||
		}
 | 
			
		||||
		else if (m_playerMovement->facingDirection & Direction::West)
 | 
			
		||||
		{
 | 
			
		||||
			itemTransf->x = -0.8f;
 | 
			
		||||
			itemTransf->y = -0.8f;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PlayerInventory::handleAttackEvents(SDL_Event& event)
 | 
			
		||||
@@ -123,14 +133,14 @@ void PlayerInventory::handleAttackEvents(SDL_Event& event)
 | 
			
		||||
		// Call components which implement ITool
 | 
			
		||||
		for (auto it = currentItem->componentsBegin(); it != currentItem->componentsEnd(); it++)
 | 
			
		||||
		{
 | 
			
		||||
			ITool* tool = dynamic_cast<ITool*>(it->second);
 | 
			
		||||
			IPlayerAction* tool = dynamic_cast<IPlayerAction*>(it->second);
 | 
			
		||||
			if (tool != nullptr)
 | 
			
		||||
				tool->performAction(x, y, d);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PlayerInventory::handleInventoryEvents(SDL_Event& event)
 | 
			
		||||
void PlayerInventory::handleCurrentInventoryItemEvent(SDL_Event& event)
 | 
			
		||||
{
 | 
			
		||||
	// See what key was pressed
 | 
			
		||||
	int slot = -1;
 | 
			
		||||
@@ -159,8 +169,6 @@ void PlayerInventory::handleInventoryEvents(SDL_Event& event)
 | 
			
		||||
 | 
			
		||||
		// Enable new object
 | 
			
		||||
		currentItem->setEnabled(true);
 | 
			
		||||
 | 
			
		||||
		gameObject->dumpTree(0);
 | 
			
		||||
	}
 | 
			
		||||
	else if (0 <= slot)
 | 
			
		||||
	{
 | 
			
		||||
@@ -168,6 +176,21 @@ void PlayerInventory::handleInventoryEvents(SDL_Event& event)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PlayerInventory::handleInventoryEvents(SDL_Event& event)
 | 
			
		||||
{
 | 
			
		||||
	bool inventoryDrop = Input::instance().down(GameKey::InventoryDrop, event);
 | 
			
		||||
 | 
			
		||||
	if (inventoryDrop && currentItem != nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		// For now we delete the object. We may want to save its state later on
 | 
			
		||||
		m_inventory->destroyChild(currentItem);
 | 
			
		||||
 | 
			
		||||
		currentItemIndex = -1;
 | 
			
		||||
		currentItem = nullptr;
 | 
			
		||||
		currentWeapon = nullptr;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} /* namespace player */
 | 
			
		||||
} /* namespace components */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
 
 | 
			
		||||
@@ -42,6 +42,7 @@ namespace player {
 | 
			
		||||
	private:
 | 
			
		||||
 | 
			
		||||
		void handleAttackEvents(SDL_Event& event);
 | 
			
		||||
		void handleCurrentInventoryItemEvent(SDL_Event& event);
 | 
			
		||||
		void handleInventoryEvents(SDL_Event& event);
 | 
			
		||||
 | 
			
		||||
		// Inventory
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
#include <GameState.h>
 | 
			
		||||
#include <model/GameObject.h>
 | 
			
		||||
#include <graphics/backend/SdlRenderer.h>
 | 
			
		||||
#include <graphics/BackgroundRenderer.h>
 | 
			
		||||
#include <graphics/MapRenderer.h>
 | 
			
		||||
#include <resources/ResourceManager.h>
 | 
			
		||||
#include <math/GameMath.h>
 | 
			
		||||
#include <utils/Assert.h>
 | 
			
		||||
@@ -23,33 +23,36 @@ using namespace farmlands::resources;
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace graphics {
 | 
			
		||||
 | 
			
		||||
BackgroundRenderer::BackgroundRenderer()
 | 
			
		||||
MapRenderer::MapRenderer()
 | 
			
		||||
	: m_context(nullptr),
 | 
			
		||||
	  m_back(nullptr)
 | 
			
		||||
	  m_map(nullptr)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BackgroundRenderer::~BackgroundRenderer()
 | 
			
		||||
MapRenderer::~MapRenderer()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model::Component* BackgroundRenderer::clone()
 | 
			
		||||
model::Component* MapRenderer::clone()
 | 
			
		||||
{
 | 
			
		||||
	return new BackgroundRenderer();
 | 
			
		||||
	return new MapRenderer();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BackgroundRenderer::onInitialize()
 | 
			
		||||
void MapRenderer::onInitialize()
 | 
			
		||||
{
 | 
			
		||||
	Assert(gameObject != nullptr, "Component not properly initialized!");
 | 
			
		||||
 | 
			
		||||
	m_context = &GameState::current().renderContext;
 | 
			
		||||
	m_back = gameObject->component<Background>();
 | 
			
		||||
	m_map = gameObject->component<Map>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BackgroundRenderer::onRender()
 | 
			
		||||
void MapRenderer::onRender()
 | 
			
		||||
{
 | 
			
		||||
	float cellW = m_context->viewport.pixelsPerUnitX * m_context->camera()->scale;
 | 
			
		||||
	float cellH = m_context->viewport.pixelsPerUnitY * m_context->camera()->scale;
 | 
			
		||||
	Assert(m_map != nullptr, "Can't find map component.");
 | 
			
		||||
 | 
			
		||||
	float scale = m_context->camera()->scale;
 | 
			
		||||
	float cellW = m_map->cellWidth * scale;
 | 
			
		||||
	float cellH = m_map->cellHeight * scale;
 | 
			
		||||
 | 
			
		||||
	// Compute how many cells fit on the screen
 | 
			
		||||
	float cellsOnScreenX = m_context->viewport.width / cellW;
 | 
			
		||||
@@ -61,37 +64,40 @@ void BackgroundRenderer::onRender()
 | 
			
		||||
	int maxCellY = ceilf(m_context->cameraTransform()->y + cellsOnScreenY / 2);
 | 
			
		||||
 | 
			
		||||
	// Clamp cell positions
 | 
			
		||||
	minCellX = clamp(minCellX, 0, (int)m_back->columnCount() - 1);
 | 
			
		||||
	maxCellX = clamp(maxCellX, 0, (int)m_back->columnCount() - 1);
 | 
			
		||||
	minCellY = clamp(minCellY, 0, (int)m_back->rowCount() - 1);
 | 
			
		||||
	maxCellY = clamp(maxCellY, 0, (int)m_back->rowCount() - 1);
 | 
			
		||||
	minCellX = clamp(minCellX, 0, (int)m_map->width - 1);
 | 
			
		||||
	maxCellX = clamp(maxCellX, 0, (int)m_map->width - 1);
 | 
			
		||||
	minCellY = clamp(minCellY, 0, (int)m_map->height - 1);
 | 
			
		||||
	maxCellY = clamp(maxCellY, 0, (int)m_map->height - 1);
 | 
			
		||||
 | 
			
		||||
	// Draw each layer
 | 
			
		||||
	for (size_t i = 0; i < m_back->layerCount(); i++)
 | 
			
		||||
	for (size_t i = 0; i < m_map->layersCount(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		resources::ResourceId textureId = m_back->texture(i);
 | 
			
		||||
		MapLayer& layer = m_map->layer(i);
 | 
			
		||||
		resources::ResourceId textureId = layer.tileSet.texture;
 | 
			
		||||
 | 
			
		||||
		// Render only visible tiles
 | 
			
		||||
		for (int y = minCellY; y <= maxCellY; y++)
 | 
			
		||||
			for (int x = minCellX; x <= maxCellX; x++)
 | 
			
		||||
			{
 | 
			
		||||
				int cellId = m_back->cell(i, y, x);
 | 
			
		||||
				Cell cellId = layer[y][x];
 | 
			
		||||
 | 
			
		||||
				// Obtain texture
 | 
			
		||||
				SDL_Texture* texture = ResourceManager::instance().texture(textureId);
 | 
			
		||||
 | 
			
		||||
				// Calculate source rect
 | 
			
		||||
				SDL_Rect src;
 | 
			
		||||
				getCell(texture, cellId, &src.x, &src.y);
 | 
			
		||||
				src.w = m_context->viewport.pixelsPerUnitX;
 | 
			
		||||
				src.h = m_context->viewport.pixelsPerUnitY;
 | 
			
		||||
				auto r = layer.tileSet.getCell(cellId);
 | 
			
		||||
				src.x = r.x;
 | 
			
		||||
				src.y = r.y;
 | 
			
		||||
				src.w = r.w;
 | 
			
		||||
				src.h = r.h;
 | 
			
		||||
 | 
			
		||||
				// Compute destination rect
 | 
			
		||||
				SDL_Rect dest;
 | 
			
		||||
				dest.x = floorf(m_context->xToScreen(x));
 | 
			
		||||
				dest.y = floorf(m_context->yToScreen(y));
 | 
			
		||||
				dest.w = ceilf(cellW);
 | 
			
		||||
				dest.h = ceilf(cellH);
 | 
			
		||||
				dest.y = floorf(m_context->yToScreen(y + 1) - src.h * scale); // Anchor should be bottom right corner
 | 
			
		||||
				dest.w = ceilf(src.w * scale);
 | 
			
		||||
				dest.h = ceilf(src.h * scale);
 | 
			
		||||
 | 
			
		||||
				// Blit
 | 
			
		||||
				SdlRenderer::instance().renderTexture(texture, &src, &dest);
 | 
			
		||||
@@ -99,20 +105,7 @@ void BackgroundRenderer::onRender()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BackgroundRenderer::getCell(SDL_Texture* texture, uint32_t cell, int* outX, int* outY)
 | 
			
		||||
{
 | 
			
		||||
	int texWidth, texHeight;
 | 
			
		||||
	SdlRenderer::instance().getTextureSize(texture, &texWidth, &texHeight);
 | 
			
		||||
 | 
			
		||||
	int ppuX = m_context->viewport.pixelsPerUnitX;
 | 
			
		||||
	int ppuY = m_context->viewport.pixelsPerUnitY;
 | 
			
		||||
 | 
			
		||||
	// Compute texture coordinates
 | 
			
		||||
	*outX = (cell * ppuX) % texWidth;
 | 
			
		||||
	*outY = ((cell * ppuX) / texWidth) * ppuY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BackgroundRenderer::dump(unsigned level)
 | 
			
		||||
void MapRenderer::dump(unsigned level)
 | 
			
		||||
{
 | 
			
		||||
	for (unsigned i = 0; i < level; i++)
 | 
			
		||||
		std::cout<<"    ";
 | 
			
		||||
@@ -5,23 +5,23 @@
 | 
			
		||||
 *      Author: tibi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef GRAPHICS_BACKGROUNDRENDERER_H_
 | 
			
		||||
#define GRAPHICS_BACKGROUNDRENDERER_H_
 | 
			
		||||
#ifndef GRAPHICS_MAPRENDERER_H_
 | 
			
		||||
#define GRAPHICS_MAPRENDERER_H_
 | 
			
		||||
 | 
			
		||||
#include <model/Component.h>
 | 
			
		||||
#include <components/Background.h>
 | 
			
		||||
#include <components/basic/Camera.h>
 | 
			
		||||
#include <components/basic/Transform.h>
 | 
			
		||||
#include <components/Map.h>
 | 
			
		||||
#include <graphics/RenderContext.h>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace graphics {
 | 
			
		||||
 | 
			
		||||
	class BackgroundRenderer: public model::Component
 | 
			
		||||
	class MapRenderer: public model::Component
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		BackgroundRenderer();
 | 
			
		||||
		virtual ~BackgroundRenderer();
 | 
			
		||||
		MapRenderer();
 | 
			
		||||
		virtual ~MapRenderer();
 | 
			
		||||
 | 
			
		||||
		virtual model::Component* clone() override;
 | 
			
		||||
		virtual void dump(unsigned level) override;
 | 
			
		||||
@@ -30,14 +30,13 @@ namespace graphics {
 | 
			
		||||
		virtual void onRender() override;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void getCell(SDL_Texture* texture, uint32_t cell, int* outX, int* outY);
 | 
			
		||||
 | 
			
		||||
		// Private fields
 | 
			
		||||
		graphics::RenderContext* m_context;
 | 
			
		||||
		components::Background* m_back;
 | 
			
		||||
		components::Map* m_map;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
} /* namespace graphics */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
 | 
			
		||||
#endif /* GRAPHICS_BACKGROUNDRENDERER_H_ */
 | 
			
		||||
#endif /* GRAPHICS_MAPRENDERER_H_ */
 | 
			
		||||
@@ -22,8 +22,8 @@ namespace farmlands {
 | 
			
		||||
namespace graphics {
 | 
			
		||||
 | 
			
		||||
SpriteRenderer::SpriteRenderer()
 | 
			
		||||
	: m_transform(nullptr),
 | 
			
		||||
	  m_context(nullptr),
 | 
			
		||||
	: m_context(nullptr),
 | 
			
		||||
	  m_transform(nullptr),
 | 
			
		||||
	  m_sprite(nullptr)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
#include <GameState.h>
 | 
			
		||||
#include <graphics/backend/SdlRenderer.h>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
@@ -29,7 +30,8 @@ SdlRenderer& SdlRenderer::instance()
 | 
			
		||||
 | 
			
		||||
SdlRenderer::SdlRenderer()
 | 
			
		||||
	: m_sdlWindow(nullptr),
 | 
			
		||||
	  m_sdlRenderer(nullptr)
 | 
			
		||||
	  m_sdlRenderer(nullptr),
 | 
			
		||||
	  m_queue()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -85,10 +87,20 @@ void SdlRenderer::renderBegin()
 | 
			
		||||
{
 | 
			
		||||
	SDL_SetRenderDrawColor(m_sdlRenderer, 0, 0, 0, 255);
 | 
			
		||||
	SDL_RenderClear(m_sdlRenderer);
 | 
			
		||||
 | 
			
		||||
	m_queue.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SdlRenderer::renderEnd()
 | 
			
		||||
{
 | 
			
		||||
	// Sort by z index, but keep relative order
 | 
			
		||||
	std::stable_sort(m_queue.begin(), m_queue.end(), compareQueueItems);
 | 
			
		||||
 | 
			
		||||
	// Render everything to screen
 | 
			
		||||
	for (auto item : m_queue)
 | 
			
		||||
		SDL_RenderCopy(m_sdlRenderer, item.texture, &item.src, &item.dest);
 | 
			
		||||
 | 
			
		||||
	// Swap buffers
 | 
			
		||||
	SDL_RenderPresent(m_sdlRenderer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -97,6 +109,17 @@ void SdlRenderer::renderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* d
 | 
			
		||||
	SDL_RenderCopy(m_sdlRenderer, texture, src, dest);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SdlRenderer::queueRenderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* dest, float z)
 | 
			
		||||
{
 | 
			
		||||
	QueueItem q;
 | 
			
		||||
	q.texture = texture;
 | 
			
		||||
	q.src = *src;
 | 
			
		||||
	q.dest = *dest;
 | 
			
		||||
	q.z = z;
 | 
			
		||||
 | 
			
		||||
	m_queue.push_back(q);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SDL_Texture* SdlRenderer::renderText(const std::string& text, TTF_Font* font, SDL_Color color)
 | 
			
		||||
{
 | 
			
		||||
	assert(font != nullptr);
 | 
			
		||||
@@ -116,6 +139,16 @@ void SdlRenderer::getTextureSize(SDL_Texture* texture, int* width, int* height)
 | 
			
		||||
	SDL_QueryTexture(texture, NULL, NULL, width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SdlRenderer::compareQueueItems(const QueueItem& a, const QueueItem& b)
 | 
			
		||||
{
 | 
			
		||||
	// First criteria is the z index
 | 
			
		||||
	if (a.z != b.z)
 | 
			
		||||
		return (a.z < b.z);
 | 
			
		||||
 | 
			
		||||
	// Second criteria is the Y position
 | 
			
		||||
	return (a.dest.y < b.dest.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
} /* namespace graphics */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
#include <graphics/RenderContext.h>
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <SDL2/SDL.h>
 | 
			
		||||
#include <SDL2/SDL_ttf.h>
 | 
			
		||||
@@ -49,10 +50,17 @@ namespace backend {
 | 
			
		||||
		SDL_Texture* renderText(const std::string& text, TTF_Font* font, SDL_Color color);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Renders a textue
 | 
			
		||||
		 * Renders a texture immediately
 | 
			
		||||
		 */
 | 
			
		||||
		void renderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* dest);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Queues a texture for rendering later.
 | 
			
		||||
		 *
 | 
			
		||||
		 * When using the queue, you can specify a z index.
 | 
			
		||||
		 */
 | 
			
		||||
		void queueRenderTexture(SDL_Texture* texture, SDL_Rect* src, SDL_Rect* dest, float z = 0.0f);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Returns the size of a texture
 | 
			
		||||
		 */
 | 
			
		||||
@@ -68,8 +76,25 @@ namespace backend {
 | 
			
		||||
 | 
			
		||||
		SdlRenderer();
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Render queue item
 | 
			
		||||
		 */
 | 
			
		||||
		struct QueueItem
 | 
			
		||||
		{
 | 
			
		||||
			SDL_Texture* texture;
 | 
			
		||||
			SDL_Rect src;
 | 
			
		||||
			SDL_Rect dest;
 | 
			
		||||
			float z;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Compares queue items.
 | 
			
		||||
		 */
 | 
			
		||||
		static bool compareQueueItems(const QueueItem& a, const QueueItem& b);
 | 
			
		||||
 | 
			
		||||
		SDL_Window* m_sdlWindow;
 | 
			
		||||
		SDL_Renderer* m_sdlRenderer;
 | 
			
		||||
		std::vector<QueueItem> m_queue;
 | 
			
		||||
 | 
			
		||||
		static SdlRenderer s_instance;
 | 
			
		||||
	};
 | 
			
		||||
 
 | 
			
		||||
@@ -42,6 +42,7 @@ namespace input {
 | 
			
		||||
		Inventory8,
 | 
			
		||||
		Inventory9,
 | 
			
		||||
		Inventory10,
 | 
			
		||||
		InventoryDrop,
 | 
			
		||||
 | 
			
		||||
		// Debug keys
 | 
			
		||||
		Debug_ZoomIn,
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,7 @@ namespace input {
 | 
			
		||||
			SDL_SCANCODE_8,				// Inventory8
 | 
			
		||||
			SDL_SCANCODE_9,				// Inventory9
 | 
			
		||||
			SDL_SCANCODE_0,				// Inventory10
 | 
			
		||||
			SDL_SCANCODE_G,				// InventoryDrop
 | 
			
		||||
 | 
			
		||||
			// Debug
 | 
			
		||||
			SDL_SCANCODE_KP_PLUS,		// Debug_ZoomIn,
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,8 @@
 | 
			
		||||
#ifndef COMPONENT_H_
 | 
			
		||||
#define COMPONENT_H_
 | 
			
		||||
 | 
			
		||||
#include <model/ICloneable.h>
 | 
			
		||||
#include <model/INonAssignable.h>
 | 
			
		||||
#include <utils/ICloneable.h>
 | 
			
		||||
#include <utils/INonAssignable.h>
 | 
			
		||||
 | 
			
		||||
#include <SDL2/SDL.h>
 | 
			
		||||
 | 
			
		||||
@@ -18,7 +18,7 @@ namespace model {
 | 
			
		||||
 | 
			
		||||
	class GameObject;
 | 
			
		||||
 | 
			
		||||
	class Component : public INonAssignable, public ICloneable<Component>
 | 
			
		||||
	class Component : public utils::INonAssignable, public utils::ICloneable<Component>
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		Component();
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,9 @@
 | 
			
		||||
#ifndef GAMEOBJECT_H_
 | 
			
		||||
#define GAMEOBJECT_H_
 | 
			
		||||
 | 
			
		||||
#include <model/ICloneable.h>
 | 
			
		||||
#include <model/INonAssignable.h>
 | 
			
		||||
#include <utils/Assert.h>
 | 
			
		||||
#include <utils/ICloneable.h>
 | 
			
		||||
#include <utils/INonAssignable.h>
 | 
			
		||||
 | 
			
		||||
#include <SDL2/SDL.h>
 | 
			
		||||
 | 
			
		||||
@@ -24,7 +24,7 @@ namespace model {
 | 
			
		||||
	class Component;
 | 
			
		||||
	class RenderContext;
 | 
			
		||||
 | 
			
		||||
	class GameObject : public INonAssignable, public ICloneable<GameObject>
 | 
			
		||||
	class GameObject : public utils::INonAssignable, public utils::ICloneable<GameObject>
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		typedef std::unordered_map<std::type_index, Component*> ComponentContainer;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										42
									
								
								src/model/TileSet.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/model/TileSet.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
/*
 | 
			
		||||
 * TileMap.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: Dec 5, 2016
 | 
			
		||||
 *      Author: tibi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef MODEL_TILESET_H_
 | 
			
		||||
#define MODEL_TILESET_H_
 | 
			
		||||
 | 
			
		||||
#include <resources/ResourceManager.h>
 | 
			
		||||
#include <utils/Rect.h>
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace model {
 | 
			
		||||
 | 
			
		||||
	struct TileSet
 | 
			
		||||
	{
 | 
			
		||||
		resources::ResourceId texture;
 | 
			
		||||
		size_t width, height;
 | 
			
		||||
		size_t tileWidth, tileHeight;
 | 
			
		||||
 | 
			
		||||
		// Gets the boundary of a cell based on its id
 | 
			
		||||
		utils::Rect<int> getCell(int cellId);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	inline utils::Rect<int> TileSet::getCell(int cellId)
 | 
			
		||||
	{
 | 
			
		||||
		utils::Rect<int> r;
 | 
			
		||||
		size_t tilesRow = width / tileWidth;
 | 
			
		||||
 | 
			
		||||
		r.x = tileWidth * (cellId % tilesRow);
 | 
			
		||||
		r.y = tileHeight * (cellId / tilesRow);
 | 
			
		||||
		r.w = tileWidth;
 | 
			
		||||
		r.h = tileHeight;
 | 
			
		||||
		return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
} /* namespace model */
 | 
			
		||||
} /* namespace farmlands */
 | 
			
		||||
 | 
			
		||||
#endif /* MODEL_TILESET_H_ */
 | 
			
		||||
@@ -19,8 +19,8 @@ namespace resources {
 | 
			
		||||
		Sprite,
 | 
			
		||||
		Configuration,
 | 
			
		||||
		Scene,
 | 
			
		||||
		Background,
 | 
			
		||||
		BackgroundLayer,
 | 
			
		||||
		Map,
 | 
			
		||||
		MapLayer,
 | 
			
		||||
		Item,
 | 
			
		||||
		ItemCollection,
 | 
			
		||||
	};
 | 
			
		||||
 
 | 
			
		||||
@@ -87,9 +87,9 @@ namespace resources {
 | 
			
		||||
        { "tilesets/Ground.png", ResourceType::Texture },
 | 
			
		||||
        { "ui/mini_inventory.png", ResourceType::Texture },
 | 
			
		||||
        { "ui/cursor.png", ResourceType::Texture },
 | 
			
		||||
        { "levels/Farm_Background.csv", ResourceType::BackgroundLayer },
 | 
			
		||||
        { "levels/Farm.back", ResourceType::Background },
 | 
			
		||||
        { "levels/Farm_Soil.csv", ResourceType::BackgroundLayer },
 | 
			
		||||
        { "levels/Farm_Background.csv", ResourceType::MapLayer },
 | 
			
		||||
        { "levels/Farm.back", ResourceType::Map },
 | 
			
		||||
        { "levels/Farm_Soil.csv", ResourceType::MapLayer },
 | 
			
		||||
        { "config/Default.config", ResourceType::Configuration },
 | 
			
		||||
        { "items/Tools.items", ResourceType::ItemCollection },
 | 
			
		||||
        { "items/Weapons.items", ResourceType::ItemCollection },
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
 *      Author: tibi
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <graphics/backend/SdlRenderer.h>
 | 
			
		||||
#include <storage/Parsers.h>
 | 
			
		||||
#include <resources/Resources.h>
 | 
			
		||||
 | 
			
		||||
@@ -15,9 +16,9 @@ namespace storage {
 | 
			
		||||
 | 
			
		||||
/****** Components ******/
 | 
			
		||||
 | 
			
		||||
void parseBackgroundCells(resources::ResourceId cellsResource, components::Background* back, size_t layer)
 | 
			
		||||
void parseMapCells(resources::ResourceId cellsResource, components::Map* map, components::MapLayer& layer)
 | 
			
		||||
{
 | 
			
		||||
	Assert(RInfo[cellsResource].type == ResourceType::BackgroundLayer, "Resource must be a level layer.");
 | 
			
		||||
	Assert(RInfo[cellsResource].type == ResourceType::MapLayer, "Resource must be a level layer.");
 | 
			
		||||
 | 
			
		||||
	char buffer[1024 * 10];
 | 
			
		||||
 | 
			
		||||
@@ -28,7 +29,7 @@ void parseBackgroundCells(resources::ResourceId cellsResource, components::Backg
 | 
			
		||||
		THROW(utils::ResourceLoadException, "Could not load level layer " + pathIn);
 | 
			
		||||
 | 
			
		||||
	// Read CSV file line by line
 | 
			
		||||
	for (size_t row = 0; row < back->rowCount(); row++)
 | 
			
		||||
	for (size_t row = 0; row < map->height; row++)
 | 
			
		||||
	{
 | 
			
		||||
		in.getline(buffer, sizeof(buffer));
 | 
			
		||||
 | 
			
		||||
@@ -37,10 +38,10 @@ void parseBackgroundCells(resources::ResourceId cellsResource, components::Backg
 | 
			
		||||
 | 
			
		||||
		// Separated by comma (or maybe semicolon)
 | 
			
		||||
		char* nextNum = strtok(buffer, ",;");
 | 
			
		||||
		for (size_t col = 0; col < back->columnCount() && nextNum != NULL; col++)
 | 
			
		||||
		for (size_t col = 0; col < map->width && nextNum != NULL; col++)
 | 
			
		||||
		{
 | 
			
		||||
			components::Cell cell = (components::Cell) strtol(nextNum, NULL, 10);
 | 
			
		||||
			back->setCell(layer, row, col, cell);
 | 
			
		||||
			layer[row][col] = cell;
 | 
			
		||||
 | 
			
		||||
			nextNum = strtok(NULL, ",;");
 | 
			
		||||
		}
 | 
			
		||||
@@ -50,10 +51,10 @@ void parseBackgroundCells(resources::ResourceId cellsResource, components::Backg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
components::Background* parse<components::Background> (boost::property_tree::ptree& root)
 | 
			
		||||
components::Map* parse<components::Map> (boost::property_tree::ptree& root)
 | 
			
		||||
{
 | 
			
		||||
	// Ensure we are on the model::Scene node (property tree seems to add root of its own)
 | 
			
		||||
	if (root.front().first == "Background")
 | 
			
		||||
	if (root.front().first == "Map")
 | 
			
		||||
		root = root.front().second;
 | 
			
		||||
 | 
			
		||||
	// This object can be declared in another file
 | 
			
		||||
@@ -61,39 +62,42 @@ components::Background* parse<components::Background> (boost::property_tree::ptr
 | 
			
		||||
	if (!src.empty())
 | 
			
		||||
	{
 | 
			
		||||
		ResourceId id = ResourceManager::instance().getId(src);
 | 
			
		||||
		return parse<components::Background>(id);
 | 
			
		||||
		return parse<components::Map>(id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Read sizes
 | 
			
		||||
	uint32_t layers = root.count("Layer");
 | 
			
		||||
	uint32_t rows = root.get<uint32_t>("<xmlattr>.rows");
 | 
			
		||||
	uint32_t cols = root.get<uint32_t>("<xmlattr>.columns");
 | 
			
		||||
	// Read map attributes
 | 
			
		||||
	components::Map* map = new components::Map();
 | 
			
		||||
 | 
			
		||||
	// Create components::Background object
 | 
			
		||||
	components::Background* back = new components::Background(layers, rows, cols);
 | 
			
		||||
	map->width = root.get<size_t>("<xmlattr>.width");
 | 
			
		||||
	map->height = root.get<size_t>("<xmlattr>.height");
 | 
			
		||||
	map->cellWidth = root.get<size_t>("<xmlattr>.cellWidth");
 | 
			
		||||
	map->cellHeight = root.get<size_t>("<xmlattr>.cellHeight");
 | 
			
		||||
 | 
			
		||||
	// Read layers
 | 
			
		||||
	size_t layerNum = 0;
 | 
			
		||||
	for (auto layer : root)
 | 
			
		||||
	for (auto layerNode : root)
 | 
			
		||||
	{
 | 
			
		||||
		if (layer.first == "Layer")
 | 
			
		||||
		if (layerNode.first == "Layer")
 | 
			
		||||
		{
 | 
			
		||||
			// Read layer name
 | 
			
		||||
			std::string name = layerNode.second.get<std::string>("<xmlattr>.name");
 | 
			
		||||
			components::MapLayer& layer = map->addLayer(name);
 | 
			
		||||
 | 
			
		||||
			// Read tile set
 | 
			
		||||
			auto tileSetNode = layerNode.second.get_child("TileSet");
 | 
			
		||||
 | 
			
		||||
			model::TileSet* tileSet = parse<model::TileSet>(tileSetNode);
 | 
			
		||||
			layer.tileSet = *tileSet;
 | 
			
		||||
			delete tileSet;
 | 
			
		||||
 | 
			
		||||
			// Read cells
 | 
			
		||||
			std::string cellsPath = layer.second.get<std::string>("<xmlattr>.cells");
 | 
			
		||||
			std::string cellsPath = layerNode.second.get<std::string>("<xmlattr>.cells");
 | 
			
		||||
			resources::ResourceId cellsId = resources::ResourceManager::instance().getId(cellsPath);
 | 
			
		||||
			parseBackgroundCells(cellsId, back, layerNum);
 | 
			
		||||
 | 
			
		||||
			// Read texture name
 | 
			
		||||
			std::string texPath = layer.second.get<std::string>("<xmlattr>.texture");
 | 
			
		||||
			resources::ResourceId tex = resources::ResourceManager::instance().getId(texPath);
 | 
			
		||||
			back->setTexture(layerNum, tex);
 | 
			
		||||
 | 
			
		||||
			++layerNum;
 | 
			
		||||
			parseMapCells(cellsId, map, layer);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return back;
 | 
			
		||||
	return map;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
@@ -130,6 +134,27 @@ components::basic::Frame* parse<components::basic::Frame> (boost::property_tree:
 | 
			
		||||
	return frame;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
components::basic::Grid* parse<components::basic::Grid> (boost::property_tree::ptree& root)
 | 
			
		||||
{
 | 
			
		||||
	// Ensure we are on the model::Scene node (property tree seems to add root of its own)
 | 
			
		||||
	if (root.front().first == "Grid")
 | 
			
		||||
		root = root.front().second;
 | 
			
		||||
 | 
			
		||||
	components::basic::Grid* grid = new components::basic::Grid();
 | 
			
		||||
 | 
			
		||||
	// Set properties
 | 
			
		||||
	utils::Rect<int> bounds;
 | 
			
		||||
	bounds.x = root.get<int>("<xmlattr>.x", 0);
 | 
			
		||||
	bounds.y = root.get<int>("<xmlattr>.y", 0);
 | 
			
		||||
	bounds.w = root.get<int>("<xmlattr>.w");
 | 
			
		||||
	bounds.h = root.get<int>("<xmlattr>.h");
 | 
			
		||||
 | 
			
		||||
	grid->setBounds(bounds);
 | 
			
		||||
	return grid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
components::basic::Sprite* parse<components::basic::Sprite> (boost::property_tree::ptree& root)
 | 
			
		||||
{
 | 
			
		||||
@@ -197,8 +222,8 @@ components::basic::Transform* parse<components::basic::Transform> (boost::proper
 | 
			
		||||
	components::basic::Transform* transform = new components::basic::Transform();
 | 
			
		||||
	transform->x = root.get<float>("<xmlattr>.x", 0.0f);
 | 
			
		||||
	transform->y = root.get<float>("<xmlattr>.y", 0.0f);
 | 
			
		||||
	transform->w = root.get<float>("<xmlattr>.w", 0.0f);
 | 
			
		||||
	transform->h = root.get<float>("<xmlattr>.h", 0.0f);
 | 
			
		||||
	transform->w = root.get<float>("<xmlattr>.w", 1.0f);
 | 
			
		||||
	transform->h = root.get<float>("<xmlattr>.h", 1.0f);
 | 
			
		||||
 | 
			
		||||
	return transform;
 | 
			
		||||
}
 | 
			
		||||
@@ -347,13 +372,13 @@ components::player::PlayerMovement* parse<components::player::PlayerMovement> (b
 | 
			
		||||
/****** Graphics ******/
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
graphics::BackgroundRenderer* parse<graphics::BackgroundRenderer> (boost::property_tree::ptree& root)
 | 
			
		||||
graphics::MapRenderer* parse<graphics::MapRenderer> (boost::property_tree::ptree& root)
 | 
			
		||||
{
 | 
			
		||||
	// Ensure we are on the model::Scene node (property tree seems to add root of its own)
 | 
			
		||||
	if (root.front().first == "BackgroundRenderer")
 | 
			
		||||
	if (root.front().first == "MapRenderer")
 | 
			
		||||
		root = root.front().second;
 | 
			
		||||
 | 
			
		||||
	graphics::BackgroundRenderer* renderer = new graphics::BackgroundRenderer();
 | 
			
		||||
	graphics::MapRenderer* renderer = new graphics::MapRenderer();
 | 
			
		||||
	return renderer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -432,15 +457,15 @@ model::GameObject* parse<model::GameObject> (boost::property_tree::ptree& root)
 | 
			
		||||
			gameObj->addComponent(parse<components::player::PlayerMovement>(child.second));
 | 
			
		||||
 | 
			
		||||
		// Components
 | 
			
		||||
		else if (child.first == "Background")
 | 
			
		||||
			gameObj->addComponent(parse<components::Background>(child.second));
 | 
			
		||||
		else if (child.first == "Map")
 | 
			
		||||
			gameObj->addComponent(parse<components::Map>(child.second));
 | 
			
		||||
 | 
			
		||||
		else if (child.first == "DebugController")
 | 
			
		||||
			gameObj->addComponent(parse<components::DebugController>(child.second));
 | 
			
		||||
 | 
			
		||||
		// Graphics
 | 
			
		||||
		else if (child.first == "BackgroundRenderer")
 | 
			
		||||
			gameObj->addComponent(parse<graphics::BackgroundRenderer>(child.second));
 | 
			
		||||
		else if (child.first == "MapRenderer")
 | 
			
		||||
			gameObj->addComponent(parse<graphics::MapRenderer>(child.second));
 | 
			
		||||
 | 
			
		||||
		else if (child.first == "SpriteRenderer")
 | 
			
		||||
			gameObj->addComponent(parse<graphics::SpriteRenderer>(child.second));
 | 
			
		||||
@@ -487,6 +512,39 @@ model::Scene* parse<model::Scene> (boost::property_tree::ptree& root)
 | 
			
		||||
	return scene;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<>
 | 
			
		||||
model::TileSet* parse<model::TileSet> (boost::property_tree::ptree& root)
 | 
			
		||||
{
 | 
			
		||||
	// Ensure we are on the model::Scene node (property tree seems to add root of its own)
 | 
			
		||||
	if (root.front().first == "TileSet")
 | 
			
		||||
		root = root.front().second;
 | 
			
		||||
 | 
			
		||||
	// This object can be declared in another file
 | 
			
		||||
	std::string src = root.get<std::string>("<xmlattr>.src", "");
 | 
			
		||||
	if (!src.empty())
 | 
			
		||||
	{
 | 
			
		||||
		ResourceId id = ResourceManager::instance().getId(src);
 | 
			
		||||
		return parse<model::TileSet>(id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Read attributes
 | 
			
		||||
	model::TileSet* tileSet = new model::TileSet();
 | 
			
		||||
 | 
			
		||||
	std::string texPath = root.get<std::string>("<xmlattr>.texture");
 | 
			
		||||
	tileSet->texture = resources::ResourceManager::instance().getId(texPath);
 | 
			
		||||
	tileSet->tileWidth = root.get<size_t>("<xmlattr>.tileWidth");
 | 
			
		||||
	tileSet->tileHeight = root.get<size_t>("<xmlattr>.tileHeight");
 | 
			
		||||
 | 
			
		||||
	// Get image size
 | 
			
		||||
	int w, h;
 | 
			
		||||
	SDL_Texture* sdlTex = ResourceManager::instance().texture(tileSet->texture);
 | 
			
		||||
	graphics::backend::SdlRenderer::instance().getTextureSize(sdlTex, &w, &h);
 | 
			
		||||
	tileSet->width = w;
 | 
			
		||||
	tileSet->height = h;
 | 
			
		||||
 | 
			
		||||
	return tileSet;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,8 @@
 | 
			
		||||
#ifndef STORAGE_PARSERS_PARSERS_H_
 | 
			
		||||
#define STORAGE_PARSERS_PARSERS_H_
 | 
			
		||||
 | 
			
		||||
#include <components/Background.h>
 | 
			
		||||
#include <components/basic/Camera.h>
 | 
			
		||||
#include <components/basic/Grid.h>
 | 
			
		||||
#include <components/basic/Sprite.h>
 | 
			
		||||
#include <components/basic/Transform.h>
 | 
			
		||||
#include <components/DebugController.h>
 | 
			
		||||
@@ -21,14 +21,15 @@
 | 
			
		||||
#include <components/items/Scythe.h>
 | 
			
		||||
#include <components/items/WateringCan.h>
 | 
			
		||||
#include <components/items/Weapon.h>
 | 
			
		||||
#include <components/Map.h>
 | 
			
		||||
#include <components/player/PlayerInventory.h>
 | 
			
		||||
#include <components/player/PlayerMovement.h>
 | 
			
		||||
#include <graphics/BackgroundRenderer.h>
 | 
			
		||||
#include <graphics/MapRenderer.h>
 | 
			
		||||
#include <graphics/SpriteRenderer.h>
 | 
			
		||||
 | 
			
		||||
#include <model/GameObject.h>
 | 
			
		||||
#include <model/Configuration.h>
 | 
			
		||||
#include <model/Scene.h>
 | 
			
		||||
#include <model/TileSet.h>
 | 
			
		||||
 | 
			
		||||
#include <storage/Parse.h>
 | 
			
		||||
 | 
			
		||||
@@ -38,7 +39,7 @@ namespace storage {
 | 
			
		||||
	/****** Components ******/
 | 
			
		||||
 | 
			
		||||
	template <>
 | 
			
		||||
	components::Background* parse<components::Background> (boost::property_tree::ptree& root);
 | 
			
		||||
	components::Map* parse<components::Map> (boost::property_tree::ptree& root);
 | 
			
		||||
 | 
			
		||||
	template <>
 | 
			
		||||
	components::basic::Camera* parse<components::basic::Camera> (boost::property_tree::ptree& root);
 | 
			
		||||
@@ -46,6 +47,9 @@ namespace storage {
 | 
			
		||||
	template <>
 | 
			
		||||
	components::basic::Frame* parse<components::basic::Frame> (boost::property_tree::ptree& root);
 | 
			
		||||
 | 
			
		||||
	template <>
 | 
			
		||||
	components::basic::Grid* parse<components::basic::Grid> (boost::property_tree::ptree& root);
 | 
			
		||||
 | 
			
		||||
	template <>
 | 
			
		||||
	components::basic::Sprite* parse<components::basic::Sprite> (boost::property_tree::ptree& root);
 | 
			
		||||
 | 
			
		||||
@@ -92,7 +96,7 @@ namespace storage {
 | 
			
		||||
	/****** Graphics ******/
 | 
			
		||||
 | 
			
		||||
	template <>
 | 
			
		||||
	graphics::BackgroundRenderer* parse<graphics::BackgroundRenderer> (boost::property_tree::ptree& root);
 | 
			
		||||
	graphics::MapRenderer* parse<graphics::MapRenderer> (boost::property_tree::ptree& root);
 | 
			
		||||
 | 
			
		||||
	template <>
 | 
			
		||||
	graphics::SpriteRenderer* parse<graphics::SpriteRenderer> (boost::property_tree::ptree& root);
 | 
			
		||||
@@ -109,6 +113,9 @@ namespace storage {
 | 
			
		||||
	template <>
 | 
			
		||||
	model::Scene* parse<model::Scene> (boost::property_tree::ptree& root);
 | 
			
		||||
 | 
			
		||||
	template<>
 | 
			
		||||
	model::TileSet* parse<model::TileSet> (boost::property_tree::ptree& root);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
#define BASE_ICLONEABLE_H_
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace model {
 | 
			
		||||
namespace utils {
 | 
			
		||||
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	class ICloneable
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
#define BASE_INONASSIGNABLE_H_
 | 
			
		||||
 | 
			
		||||
namespace farmlands {
 | 
			
		||||
namespace model {
 | 
			
		||||
namespace utils {
 | 
			
		||||
 | 
			
		||||
	class INonAssignable
 | 
			
		||||
	{
 | 
			
		||||
							
								
								
									
										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