Implemented resource manager which can load textures and levels.

Implemented script to generate Resources.g.h file linking assets to code.
Added assets from old project.
This commit is contained in:
2016-11-12 14:17:00 +02:00
parent 294fd6e2ac
commit 914ae0de0d
74 changed files with 14937 additions and 304 deletions

View File

@ -6,6 +6,8 @@
*/
#include "FarmlandsGame.h"
#include <resources/Resources.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
@ -53,7 +55,8 @@ bool FarmlandsGame::initialize()
}
// Load resources
m_resourceManager.loadGame(m_sdlRenderer);
m_resourceManager.initialize(m_sdlRenderer);
m_resourceManager.loadLevel(resources::R::Levels::Farm);
return true;
}
@ -68,10 +71,11 @@ void FarmlandsGame::onRender()
SDL_RenderClear(m_sdlRenderer);
SDL_Rect dest = { 0, 0, 0, 0};
SDL_QueryTexture(m_resourceManager.texture(0), NULL, NULL, &dest.w, &dest.h);
dest.w *= 2;
SDL_QueryTexture(m_resourceManager.texture(resources::R::Tilesets::Ground), NULL, NULL, &dest.w, &dest.h);
dest.w *= 4;
dest.h *= 4;
SDL_RenderCopy(m_sdlRenderer, m_resourceManager.texture(0), nullptr, &dest);
SDL_RenderCopy(m_sdlRenderer, m_resourceManager.texture(resources::R::Tilesets::Ground), nullptr, &dest);
// Render loading screen
SDL_Delay(10);

View File

@ -8,7 +8,7 @@
#ifndef FARMLANDSGAME_H_
#define FARMLANDSGAME_H_
#include "storage/ResourceManager.h"
#include "resources/ResourceManager.h"
#include <SDL2/SDL.h>
@ -41,9 +41,9 @@ namespace farmlands
bool m_running;
SDL_Window* m_sdlWindow;
SDL_Renderer* m_sdlRenderer;
enum GameState m_state;
//enum GameState m_state;
storage::ResourceManager m_resourceManager;
resources::ResourceManager m_resourceManager;
};
}
#endif /* FARMLANDSGAME_H_ */

View File

@ -32,6 +32,8 @@ namespace model {
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);
size_t m_cellWidth, m_cellHeight;
private:
Cell* m_cells;
size_t m_layers;

24
src/model/Player.h Normal file
View File

@ -0,0 +1,24 @@
/*
* Player.h
*
* Created on: Nov 12, 2016
* Author: tibi
*/
#ifndef MODEL_PLAYER_H_
#define MODEL_PLAYER_H_
namespace farmlands {
namespace model {
struct Player
{
float posX, posY;
};
}
}
#endif /* MODEL_PLAYER_H_ */

View File

@ -0,0 +1,33 @@
/*
* ResourceType.h
*
* Created on: Nov 12, 2016
* Author: tibi
*/
#ifndef RESOURCES_RESOURCEINFO_H_
#define RESOURCES_RESOURCEINFO_H_
namespace farmlands {
namespace resources {
enum class ResourceType
{
None,
Texture,
Level,
LevelLayer,
Font,
};
struct ResourceInfo
{
const char* path;
ResourceType type;
};
}
}
#endif /* RESOURCES_RESOURCEINFO_H_ */

View File

@ -0,0 +1,86 @@
/*
* ResourceManager.h
*
* Created on: Nov 7, 2016
* Author: tibi
*/
#ifndef STORAGE_RESOURCEMANAGER_H_
#define STORAGE_RESOURCEMANAGER_H_
#include <model/Level.h>
#include <vector>
#include <map>
#include <memory>
#include <string>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
namespace farmlands {
namespace resources {
union LoadedResource
{
struct
{
SDL_Surface* m_surface;
SDL_Texture* m_texture;
} texture;
};
class ResourceManager
{
public:
ResourceManager();
virtual ~ResourceManager();
void initialize(SDL_Renderer* renderer);
// Loading routines
void loadMainMenu();
void loadLevel(int levelId);
TTF_Font* font(int id, int pointSize);
SDL_Texture* texture(int id);
private:
/**
* Obtains the path of the resource in native format.
*/
std::string getPath(int resourceId);
/**
* Obtains the id of a resource based on its path.
* Returns: the resource id, or -1 if resource not found.
*/
int getId(std::string resourcePath);
/**
* Loads the cell data for a level tile layer.
*/
void loadLevelLayer(std::shared_ptr<model::Level> level, size_t layerNumber, int resourceId);
/**
* Loads a texture into memory.
*/
void loadTexture(int textureId);
void loadFont(int fontId, int pointSize);
// SDL Renderer
SDL_Renderer* m_renderer;
// Loaded resources
std::shared_ptr<model::Level> m_loadedLevel;
LoadedResource* m_loadedResources;
typedef int FontId;
std::map<FontId, TTF_Font*> m_fontCache;
};
} /* namespace resources */
} /* namespace farmlands */
#endif /* STORAGE_RESOURCEMANAGER_H_ */

View File

@ -0,0 +1,78 @@
/*
* ResourceManager.cpp
*
* Created on: Nov 7, 2016
* Author: tibi
*/
#include <resources/ResourceManager.h>
#include <resources/Resources.h>
#include <boost/filesystem.hpp>
#define FONTID(id,size) (id * 1000 + size)
#define FONTID_SIZE(fontid) (fontid % 1000)
#define FONTID_ID(fontid) (fontid / 1000)
namespace farmlands {
namespace resources {
ResourceManager::ResourceManager()
: m_renderer(nullptr),
m_loadedLevel(nullptr),
m_loadedResources(new LoadedResource[sizeof(RInfo) / sizeof(RInfo[0])])
{
}
ResourceManager::~ResourceManager()
{
delete[] m_loadedResources;
}
void ResourceManager::initialize(SDL_Renderer* renderer)
{
m_renderer = renderer;
}
void ResourceManager::loadMainMenu()
{
}
TTF_Font* ResourceManager::font(int id, int pointSize)
{
// Open from cache
auto it = m_fontCache.find(FONTID(id, pointSize));
if (it != m_fontCache.end())
return it->second;
// Open font
TTF_Font* font = TTF_OpenFont(RInfo[id].path, pointSize);
m_fontCache.emplace(FONTID(id, pointSize), font);
return font;
}
std::string ResourceManager::getPath(int resourceId)
{
boost::filesystem::path resPath(ASSETS_DIR);
resPath.append(RInfo[resourceId].path);
return resPath.native();
}
int ResourceManager::getId(std::string resPathStr)
{
boost::filesystem::path resPath(resPathStr);
for(size_t i = 0; i < sizeof(RInfo) / sizeof(RInfo[0]); i++)
{
boost::filesystem::path iPath (RInfo[i].path);
if (resPath == iPath)
return (int)i;
}
return -1;
}
} /* namespace storage */
} /* namespace farmlands */

View File

@ -0,0 +1,99 @@
/*
* ResourceManager_Levels.cpp
*
* Created on: Nov 11, 2016
* Author: tibi
*/
#include <resources/ResourceManager.h>
#include <resources/Resources.h>
#include <fstream>
#include <string>
#include <json.hpp>
using namespace nlohmann;
namespace farmlands {
namespace resources {
void ResourceManager::loadLevelLayer(std::shared_ptr<model::Level> level, size_t layer, int resourceId)
{
assert(RInfo[resourceId].type == ResourceType::LevelLayer);
char buffer[1024 * 10];
// Open file
std::ifstream in(getPath(resourceId));
if (!in)
throw 0; // TODO: replace with exception type
// Read CSV file line by line
for (size_t row = 0; row < level->rowCount(); row++)
{
in.getline(buffer, sizeof(buffer));
if (in.eof())
throw 0; // TODO: replace with exception type
// Separated by comma (or maybe semicolon)
char* nextNum = strtok(buffer, ",;");
for (size_t col = 0; col < level->columnCount() && nextNum != NULL; col++)
{
model::Cell cell = (model::Cell)strtol(nextNum, NULL, 10);
level->setCell(layer, row, col, cell);
nextNum = strtok(NULL, ",;");
}
}
in.close();
}
void ResourceManager::loadLevel(int levelId)
{
// Sanity checks
assert(RInfo[levelId].type == ResourceType::Level);
// Open file
std::ifstream levelIn(getPath(levelId));
if (!levelIn)
throw 0; // TODO: replace with exception type
// Parse file
json levelJs;
levelIn>>levelJs;
size_t layerCount = levelJs.value("layerCount", 0u);
size_t rowCount = levelJs.value("height", 0u);
size_t colCount = levelJs.value("width", 0u);
assert(layerCount > 0 && rowCount > 0 && colCount > 0);
std::shared_ptr<model::Level> level(new model::Level(layerCount, rowCount, colCount));
level->m_cellWidth = levelJs.value("cellWidth", 0u);
level->m_cellHeight = levelJs.value("cellHeight", 0u);
// Read layers
json layersJs = levelJs["layers"];
size_t layer = 0;
for (auto it = layersJs.begin(); it != layersJs.end(); it++, layer++)
{
std::string cellsFileName = it->value("cellsFile", std::string());
loadLevelLayer(level, layer, getId(cellsFileName));
std::string textureFileName = it->value("textureFile", std::string());
loadTexture(getId(textureFileName));
}
m_loadedLevel = level;
}
}
}

View File

@ -0,0 +1,47 @@
/*
* ResourceManager_Textures.cpp
*
* Created on: Nov 12, 2016
* Author: tibi
*/
#include <resources/ResourceManager.h>
#include <resources/Resources.h>
#include <cassert>
namespace farmlands {
namespace resources {
void ResourceManager::loadTexture(int resourceId)
{
assert(RInfo[resourceId].type == ResourceType::Texture);
// Open file
SDL_Surface* surface = IMG_Load(getPath(resourceId).c_str());
if (surface == NULL)
throw 0; // TODO: error handling
SDL_Texture* texture = SDL_CreateTextureFromSurface(m_renderer, surface);
if (texture == NULL)
throw 0; // TODO: error handling
m_loadedResources[resourceId].texture.m_surface = surface;
m_loadedResources[resourceId].texture.m_texture = texture;
}
SDL_Texture* ResourceManager::texture(int id)
{
assert(RInfo[id].type == ResourceType::Texture);
return m_loadedResources[id].texture.m_texture;
}
}
}

View File

@ -0,0 +1,46 @@
// WARNING: This file is auto generated by the build/prepareAssets.py script.
#ifndef STORAGE_RESOURCES_G_H_
#define STORAGE_RESOURCES_G_H_
#include <resources/ResourceInfo.h>
namespace farmlands {
namespace resources {
/**
* This namespace contains all the resource IDs, used by the resource manager.
* The IDs are generated at build time by the 'prepareAssets.py' script.
*/
namespace R {
enum Fonts
{
DejaVuSans = 0,
};
enum Tilesets
{
Ground = 1,
};
enum Levels
{
Farm_Background = 2,
Farm = 3,
};
}
const int RInfo_Fonts_Begin = 0;
const int RInfo_Tilesets_Begin = 1;
const int RInfo_Levels_Begin = 2;
/**
* This array contains the names of all the files, and the corresponding file type.
*/
const ResourceInfo RInfo[] = {
{ "fonts/DejaVuSans.ttf", ResourceType::Font },
{ "tilesets/Ground.png", ResourceType::Texture },
{ "levels/Farm_Background.csv", ResourceType::LevelLayer },
{ "levels/Farm.level", ResourceType::Level },
};
}
}
#endif /* STORAGE_RESOURCES_G_H_ */

13
src/resources/Resources.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef STORAGE_RESOURCES_H_
#define STORAGE_RESOURCES_H_
#include <resources/Resources.g.h>
namespace farmlands {
namespace resources {
const char* const ASSETS_DIR = "assets";
}
}
#endif /* STORAGE_RESOURCES_H_ */

View File

@ -1,92 +0,0 @@
/*
* LoadLevel.cpp
*
* Created on: Nov 11, 2016
* Author: tibi
*/
#include <model/Level.h>
#include <fstream>
#include <string>
#include <json.hpp>
using namespace farmlands::model;
using namespace nlohmann;
namespace farmlands {
namespace storage {
namespace {
void loadLevelCells(std::shared_ptr<Level> level, size_t layer, std::string cellsFileName)
{
char buffer[1024 * 10];
// Open file
std::ifstream in(cellsFileName);
if (!in)
throw 0; // TODO: replace with exception type
// Read CSV file line by line
for (size_t row = 0; row < level->rowCount(); row++)
{
in.getline(buffer, sizeof(buffer));
if (in.eof())
throw 0; // TODO: replace with exception type
// Separated by comma (or maybe semicolon)
char* nextNum = strtok(buffer, ",;");
for (size_t col = 0; col < level->columnCount() && nextNum != NULL; col++)
{
Cell cell = (Cell)strtol(nextNum, NULL, 10);
level->setCell(layer, row, col, cell);
nextNum = strtok(NULL, ",;");
}
}
in.close();
}
}
std::shared_ptr<Level> loadLevel(std::string fileName)
{
// Open file
std::ifstream levelIn(fileName);
if (!levelIn)
throw 0; // TODO: replace with exception type
// Parse file
json levelJs;
levelIn>>levelJs;
size_t layerCount = levelJs.value("layerCount", 0u);
size_t rowCount = levelJs.value("height", 0u);
size_t colCount = levelJs.value("width", 0u);
size_t cellWidth = levelJs.value("cellWidth", 0u);
size_t cellHeight = levelJs.value("cellHeight", 0u);
std::shared_ptr<Level> level(new Level(layerCount, rowCount, colCount));
// Read layers
json layersJs = levelJs["layers"];
size_t layer = 0;
for (auto it = layersJs.begin(); it != layersJs.end(); it++, layer++)
{
std::string cellsFileName = it->value("cellsFile", std::string());
loadLevelCells(level, layer, cellsFileName);
std::string textureFileName = it->value("textureFile", std::string());
}
return level;
}
}
}

View File

@ -1,120 +0,0 @@
/*
* ResourceManager.cpp
*
* Created on: Nov 7, 2016
* Author: tibi
*/
#include "ResourceManager.h"
#include "Resources.h"
#define FONTID(id,size) (id * 1000 + size)
#define FONTID_SIZE(fontid) (fontid % 1000)
#define FONTID_ID(fontid) (fontid / 1000)
namespace farmlands
{
namespace storage
{
ResourceManager::ResourceManager()
{
}
ResourceManager::~ResourceManager()
{
}
void ResourceManager::loadMainMenu()
{
}
void ResourceManager::loadGame(SDL_Renderer* renderer)
{
loadTextures(renderer);
}
void ResourceManager::loadTextures(SDL_Renderer* renderer)
{
for (size_t i = 0; i < sizeof(Resources_Textures) / sizeof(Resources_Textures[0]); i++)
{
SDL_Surface* surface = IMG_Load(Resources_Textures[i]);
m_surfaces.push_back(surface);
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
m_textures.push_back(texture);
}
}
TTF_Font* ResourceManager::font(const char* name, int pointSize)
{
int id = fontId(name);
return font(id, pointSize);
}
TTF_Font* ResourceManager::font(int id, int pointSize)
{
// Open from cache
auto it = m_fontCache.find(FONTID(id, pointSize));
if (it != m_fontCache.end())
return it->second;
// Open font
TTF_Font* font = TTF_OpenFont(Resources_Fonts[id], pointSize);
m_fontCache.emplace(FONTID(id, pointSize), font);
return font;
}
int ResourceManager::fontId(const char* name)
{
// Find in cache
auto it = m_fontIdCache.find(std::string(name));
if (it != m_fontIdCache.end())
return it->second;
for (size_t i = 0; i < sizeof(Resources_Fonts) / sizeof(Resources_Fonts[0]); i++)
{
// Extract name from file name
std::string fontName = Resources_Fonts[i];
size_t nameStart = fontName.find_last_of('/');
if (nameStart == std::string::npos)
nameStart = 0;
else
++nameStart;
size_t nameEnd = fontName.find_last_of('.');
size_t nameLen = (nameEnd != std::string::npos) ? nameEnd - nameStart : std::string::npos;
fontName = fontName.substr(nameStart, nameLen);
// Found?
if (fontName == name) {
m_fontIdCache.emplace(fontName, i);
return i;
}
}
return -1;
}
SDL_Texture* ResourceManager::texture(const char* name)
{
return NULL;
}
SDL_Texture* ResourceManager::texture(int id)
{
return m_textures[id];
}
int ResourceManager::textureId(const char* name)
{
return -1;
}
} /* namespace storage */
} /* namespace farmlands */

View File

@ -1,54 +0,0 @@
/*
* ResourceManager.h
*
* Created on: Nov 7, 2016
* Author: tibi
*/
#ifndef STORAGE_RESOURCEMANAGER_H_
#define STORAGE_RESOURCEMANAGER_H_
#include <vector>
#include <map>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
namespace farmlands
{
namespace storage
{
class ResourceManager
{
public:
ResourceManager();
virtual ~ResourceManager();
void loadMainMenu();
void loadGame(SDL_Renderer* renderer);
TTF_Font* font(const char* name, int pointSize);
TTF_Font* font(int id, int pointSize);
int fontId(const char* name);
SDL_Texture* texture(const char* name);
SDL_Texture* texture(int id);
int textureId(const char* name);
private:
void loadTextures(SDL_Renderer* renderer);
typedef int FontId;
std::map<FontId, TTF_Font*> m_fontCache;
std::map<std::string, int> m_fontIdCache;
std::vector<SDL_Surface*> m_surfaces;
std::vector<SDL_Texture*> m_textures;
};
} /* namespace storage */
} /* namespace farmlands */
#endif /* STORAGE_RESOURCEMANAGER_H_ */

View File

@ -1,28 +0,0 @@
/*
* Resources.h
*
* Created on: Nov 7, 2016
* Author: tibi
*/
#ifndef STORAGE_RESOURCES_H_
#define STORAGE_RESOURCES_H_
namespace farmlands {
namespace storage {
const char* const Resources_Fonts[] =
{
"assets/fonts/DejaVuSans.ttf",
};
const char* const Resources_MainMenu_Textures[] = { };
const char* const Resources_Textures[] =
{
"assets/tilesets/ground.png"
};
}
}
#endif /* STORAGE_RESOURCES_H_ */