Grid Loading from XML
This commit is contained in:
@ -19,8 +19,81 @@
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace ia::iae
|
||||
{
|
||||
class XMLData
|
||||
{
|
||||
public:
|
||||
STATIC XMLData *Load(IN CONST String &path);
|
||||
|
||||
CONST String Type;
|
||||
CONST String Name;
|
||||
CONST pugi::xml_node PropertiesNode;
|
||||
CONST Vector<pugi::xml_node> ChildNodes;
|
||||
|
||||
private:
|
||||
CONST pugi::xml_document m_document;
|
||||
|
||||
XMLData(IN pugi::xml_document &&document, IN CONST String &type, IN CONST String &name,
|
||||
IN pugi::xml_node propertiesNode, IN CONST Vector<pugi::xml_node> &childNodes);
|
||||
};
|
||||
|
||||
XMLData::XMLData(IN pugi::xml_document &&document, IN CONST String &type, IN CONST String &name,
|
||||
IN pugi::xml_node propertiesNode, IN CONST Vector<pugi::xml_node> &childNodes)
|
||||
: m_document(IA_MOVE(document)), Type(type), Name(name), PropertiesNode(propertiesNode), ChildNodes(childNodes)
|
||||
{
|
||||
}
|
||||
|
||||
XMLData *XMLData::Load(IN CONST String &path)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
if (!doc.load_file(path.c_str()))
|
||||
return nullptr;
|
||||
|
||||
if (std::distance(doc.children().begin(), doc.children().end()) != 1)
|
||||
return nullptr;
|
||||
const auto rootNode = *doc.children().begin();
|
||||
|
||||
// Verify Engine Version
|
||||
{
|
||||
const auto engineInfoNode = rootNode.child("IAEngine");
|
||||
if (!engineInfoNode)
|
||||
return nullptr;
|
||||
const auto engineVersionNode = engineInfoNode.child("EngineVersion");
|
||||
if (!engineVersionNode)
|
||||
return nullptr;
|
||||
const auto engineVersion = IA_PARSE_VERSION_STRING(engineVersionNode.text().as_string());
|
||||
if (engineVersion > IAEngine::ENGINE_VERSION)
|
||||
{
|
||||
IAE_LOG_WARN("XML data file was created with a newer version of IAEngine, skipping..");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const auto propertiesNode = rootNode.child("Properties");
|
||||
if (!propertiesNode)
|
||||
return nullptr;
|
||||
|
||||
Vector<pugi::xml_node> childNodes;
|
||||
for (auto &c : rootNode.children())
|
||||
{
|
||||
if ((!strcmp(c.name(), "Properties")) || (!strcmp(c.name(), "IAEngine")))
|
||||
continue;
|
||||
childNodes.pushBack(c);
|
||||
}
|
||||
|
||||
const auto nameAttr = rootNode.attribute("name");
|
||||
return new XMLData(IA_MOVE(doc), rootNode.name(), nameAttr ? nameAttr.as_string() : "", propertiesNode,
|
||||
childNodes);
|
||||
}
|
||||
} // namespace ia::iae
|
||||
|
||||
namespace ia::iae
|
||||
{
|
||||
RefPtr<Scene> g_entryScene{};
|
||||
|
||||
VOID GameData::Initialize()
|
||||
{
|
||||
if (!LoadResourceData())
|
||||
@ -41,17 +114,155 @@ namespace ia::iae
|
||||
|
||||
BOOL GameData::LoadSceneData()
|
||||
{
|
||||
for (const auto &entry : std::filesystem::directory_iterator("Resources/Scenes/"))
|
||||
{
|
||||
const auto scene = ParseScene(entry.path().string().c_str());
|
||||
if (!scene)
|
||||
{
|
||||
IAE_LOG_WARN("Failed to load the scene \"", entry.path().string().c_str(), "\", skipping..");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL GameData::LoadResourceData()
|
||||
{
|
||||
|
||||
auto xml = XMLData::Load("Resources/Resources.xml");
|
||||
if (!xml)
|
||||
return false;
|
||||
|
||||
pugi::xml_node entriesNode{};
|
||||
for (const auto &node : xml->ChildNodes)
|
||||
{
|
||||
if (!strcmp(node.name(), "Entries"))
|
||||
{
|
||||
entriesNode = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!entriesNode)
|
||||
return false;
|
||||
|
||||
for (const auto &entry : entriesNode.children())
|
||||
{
|
||||
if (!strcmp(entry.name(), "Sprite"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(entry.name(), "SpriteSheet"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(entry.name(), "TileSheet"))
|
||||
{
|
||||
IAEngine::AssignResourceName(
|
||||
IAEngine::CreateTileSheet(BuildString("Resources/", entry.attribute("path").as_string()),
|
||||
entry.attribute("tileWidth").as_int(),
|
||||
entry.attribute("tileHeight").as_int()),
|
||||
entry.attribute("name").as_string());
|
||||
}
|
||||
else
|
||||
THROW_INVALID_DATA();
|
||||
}
|
||||
|
||||
delete xml;
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<Scene> GameData::ParseScene(IN CONST String &path)
|
||||
{
|
||||
const auto xml = XMLData::Load(path);
|
||||
if (!xml)
|
||||
return nullptr;
|
||||
|
||||
const auto extentNode = xml->PropertiesNode.child("Extent");
|
||||
if (!extentNode)
|
||||
return nullptr;
|
||||
|
||||
const auto extent = IVec2{extentNode.attribute("width").as_int(), extentNode.attribute("height").as_int()};
|
||||
RefPtr<Scene> scene = MakeRefPtr<Scene>(extent);
|
||||
|
||||
for (const auto &child : xml->ChildNodes)
|
||||
{
|
||||
if (!strcmp(child.name(), "Resources"))
|
||||
{
|
||||
for (const auto &r : child.children())
|
||||
scene->AddReferencedResources(IAEngine::GetResourceByName(r.attribute("name").as_string()));
|
||||
}
|
||||
else if (!strcmp(child.name(), "Nodes"))
|
||||
{
|
||||
}
|
||||
else if (!strcmp(child.name(), "Grid"))
|
||||
{
|
||||
ParseSceneGrid(scene.get(), &child);
|
||||
}
|
||||
else
|
||||
THROW_INVALID_DATA();
|
||||
}
|
||||
|
||||
IAEngine::AssignResourceName(IAEngine::AddScene(scene), xml->Name);
|
||||
|
||||
if (!g_entryScene)
|
||||
g_entryScene = scene;
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
VOID GameData::ParseSceneGrid(IN Scene *scene, IN PCVOID _gridNode)
|
||||
{
|
||||
const auto gridNode = *static_cast<const pugi::xml_node *>(_gridNode);
|
||||
|
||||
const auto parseHexColor = [](IN PCCHAR hex) -> Vec4
|
||||
{
|
||||
Vec4 result{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
if((hex[0] != '#') || (strlen(hex) != 9))return result;
|
||||
THROW_NOT_IMPLEMENTED();
|
||||
return result;
|
||||
};
|
||||
|
||||
INT32 tileCursorX{}, tileCursorY{};
|
||||
const auto processCell = [&](IN pugi::xml_node cellNode) {
|
||||
if B_UNLIKELY (tileCursorY >= scene->GetGridSize().y)
|
||||
return;
|
||||
|
||||
auto& cell = scene->GetGridCell(tileCursorX, tileCursorY);
|
||||
cell.TileSheetTexture = IAEngine::GetResourceByName(cellNode.attribute("tileSheet").as_string());
|
||||
cell.TileIndex.x = cellNode.attribute("tileX").as_int();
|
||||
cell.TileIndex.y = cellNode.attribute("tileY").as_int();
|
||||
cell.CollisionMask = cellNode.attribute("collisionMask").as_ullong();
|
||||
//cell.ColorOverlay = parseHexColor(cellNode.attribute("colorOverlay").as_string());
|
||||
|
||||
tileCursorX++;
|
||||
if (tileCursorX >= scene->GetGridSize().x)
|
||||
{
|
||||
tileCursorX = 0;
|
||||
tileCursorY++;
|
||||
}
|
||||
};
|
||||
|
||||
scene->SetupGrid({gridNode.attribute("tileWidth").as_int(), gridNode.attribute("tileHeight").as_int()});
|
||||
|
||||
for (const auto &t : gridNode.children())
|
||||
{
|
||||
if (!strcmp(t.name(), "Cell"))
|
||||
{
|
||||
processCell(t);
|
||||
}
|
||||
else if (!strcmp(t.name(), "Repeat"))
|
||||
{
|
||||
const auto count = t.attribute("times").as_int();
|
||||
for (INT32 i = 0; i < count; i++)
|
||||
{
|
||||
for (const auto &cellNode : t)
|
||||
processCell(cellNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
THROW_INVALID_DATA();
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<Scene> GameData::GetEntryScene()
|
||||
{
|
||||
return nullptr;
|
||||
return g_entryScene;
|
||||
}
|
||||
} // namespace ia::iae
|
||||
|
||||
@ -15,9 +15,9 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <EmbeddedResources.hpp>
|
||||
#include <GameData.hpp>
|
||||
#include <IAEngine/LibInterface.hpp>
|
||||
#include <Renderer.hpp>
|
||||
#include <GameData.hpp>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <Vendor/stb/stb_image.h>
|
||||
@ -32,7 +32,8 @@ namespace ia::iae
|
||||
|
||||
TEXTURE,
|
||||
SPRITE_SHEET,
|
||||
SOUND
|
||||
SOUND,
|
||||
SCENE
|
||||
};
|
||||
|
||||
EType Type{EType::INVALID};
|
||||
@ -48,6 +49,11 @@ namespace ia::iae
|
||||
Vector<INT32> FrameCounts;
|
||||
};
|
||||
|
||||
struct Resource_Scene : public Resource
|
||||
{
|
||||
RefPtr<Scene> SceneRef;
|
||||
};
|
||||
|
||||
RefPtr<Scene> g_activeScene;
|
||||
Vector<Resource *> g_resources;
|
||||
Map<String, Handle> g_resourceNames;
|
||||
@ -146,9 +152,17 @@ namespace ia::iae
|
||||
{
|
||||
Renderer::Initialize(IVec2{g_designViewport.x, g_designViewport.y});
|
||||
|
||||
{ // Add default texture to resources
|
||||
const auto t = new Resource_Texture();
|
||||
t->Type = Resource::EType::TEXTURE;
|
||||
t->Texture = 0;
|
||||
g_resources.pushBack(t);
|
||||
}
|
||||
|
||||
GameData::Initialize();
|
||||
|
||||
ChangeActiveScene(GameData::GetEntryScene() ? GameData::GetEntryScene() : CreateScene({g_designViewport.x, g_designViewport.y}));
|
||||
ChangeActiveScene(GameData::GetEntryScene() ? GameData::GetEntryScene()
|
||||
: CreateScene({g_designViewport.x, g_designViewport.y}));
|
||||
|
||||
Game_OnInitialize();
|
||||
}
|
||||
@ -203,6 +217,8 @@ namespace ia::iae
|
||||
{
|
||||
INT32 w, h, n;
|
||||
auto pixels = stbi_load(path, &w, &h, &n, STBI_rgb_alpha);
|
||||
if (!pixels)
|
||||
THROW_INVALID_DATA(path);
|
||||
const auto t = Renderer::CreateTexture(pixels, w, h, tileWidth == -1 ? 1 : w / tileWidth,
|
||||
tileHeight == -1 ? 1 : h / tileHeight);
|
||||
stbi_image_free(pixels);
|
||||
@ -280,6 +296,10 @@ namespace ia::iae
|
||||
|
||||
case Resource::EType::SOUND:
|
||||
break;
|
||||
|
||||
case Resource::EType::SCENE:
|
||||
static_cast<Resource_Scene *>(g_resources[resource])->SceneRef.reset();
|
||||
break;
|
||||
}
|
||||
delete g_resources[resource];
|
||||
g_resources[resource] = nullptr;
|
||||
@ -307,6 +327,7 @@ namespace ia::iae
|
||||
{
|
||||
switch (g_resources[handle]->Type)
|
||||
{
|
||||
case Resource::EType::SCENE:
|
||||
case Resource::EType::INVALID:
|
||||
break;
|
||||
|
||||
@ -367,4 +388,18 @@ namespace ia::iae
|
||||
g_activeScene = scene;
|
||||
LoadResources(scene->GetReferencedResources());
|
||||
}
|
||||
|
||||
VOID IAEngine::ChangeActiveScene(IN Handle scene)
|
||||
{
|
||||
ChangeActiveScene(static_cast<Resource_Scene *>(g_resources[scene])->SceneRef);
|
||||
}
|
||||
|
||||
Handle IAEngine::AddScene(IN RefPtr<Scene> scene)
|
||||
{
|
||||
const auto t = new Resource_Scene();
|
||||
t->Type = Resource::EType::SCENE;
|
||||
t->SceneRef = scene;
|
||||
g_resources.pushBack(t);
|
||||
return (Handle) g_resources.size() - 1;
|
||||
}
|
||||
} // namespace ia::iae
|
||||
@ -14,8 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <Renderer.hpp>
|
||||
#include <IAEngine/IAEngine.hpp>
|
||||
#include <Renderer.hpp>
|
||||
|
||||
namespace ia::iae
|
||||
{
|
||||
@ -36,11 +36,22 @@ namespace ia::iae
|
||||
|
||||
VOID Scene::OnDraw()
|
||||
{
|
||||
for(const auto& cell: m_gridCells)
|
||||
INT32 tileCursorX{}, tileCursorY{};
|
||||
for (const auto &cell : m_gridCells)
|
||||
{
|
||||
IAEngine::DrawTile(cell.TileSheetTexture, cell.TileIndex.x, cell.TileIndex.y, {
|
||||
|
||||
}, {1.0f, 1.0f}, 0.0f);
|
||||
if (cell.TileSheetTexture)
|
||||
IAEngine::DrawTile(cell.TileSheetTexture, cell.TileIndex.x, cell.TileIndex.y,
|
||||
{
|
||||
tileCursorX * m_gridCellSize.x,
|
||||
tileCursorY * m_gridCellSize.y
|
||||
},
|
||||
{1.0f, 1.0f}, 0.0f);
|
||||
tileCursorX++;
|
||||
if (tileCursorX >= GetGridSize().x)
|
||||
{
|
||||
tileCursorX = 0;
|
||||
tileCursorY++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -29,6 +29,9 @@ namespace ia::iae
|
||||
STATIC BOOL LoadSceneData();
|
||||
STATIC BOOL LoadResourceData();
|
||||
|
||||
STATIC RefPtr<Scene> ParseScene(IN CONST String& path);
|
||||
STATIC VOID ParseSceneGrid(IN Scene* scene, IN PCVOID gridNode);
|
||||
|
||||
private:
|
||||
STATIC VOID Initialize();
|
||||
STATIC VOID Terminate();
|
||||
|
||||
@ -22,6 +22,9 @@ namespace ia::iae
|
||||
{
|
||||
class IAEngine
|
||||
{
|
||||
public:
|
||||
STATIC CONSTEXPR IA_VERSION_TYPE ENGINE_VERSION = IA_MAKE_VERSION(1, 0, 0);
|
||||
|
||||
public:
|
||||
STATIC Handle CreateSprite(IN CONST String &path);
|
||||
STATIC Handle CreateSprite(IN PCUINT8 rgbaData, IN INT32 width, IN INT32 height);
|
||||
@ -43,6 +46,8 @@ namespace ia::iae
|
||||
public:
|
||||
STATIC RefPtr<Scene> GetActiveScene();
|
||||
STATIC RefPtr<Scene> CreateScene(IN IVec2 extent);
|
||||
STATIC VOID ChangeActiveScene(IN Handle scene);
|
||||
STATIC Handle AddScene(IN RefPtr<Scene> scene);
|
||||
STATIC VOID ChangeActiveScene(IN RefPtr<Scene> scene);
|
||||
|
||||
public:
|
||||
|
||||
@ -41,7 +41,26 @@ namespace ia::iae
|
||||
INLINE GridCell &GetGridCell(IN INT32 x, IN INT32 y);
|
||||
INLINE VOID AddReferencedResources(IN Handle resource);
|
||||
|
||||
INLINE CONST Vector<Handle> &GetReferencedResources() CONST;
|
||||
public:
|
||||
CONST Vector<Handle> &GetReferencedResources() CONST
|
||||
{
|
||||
return m_referencedResources;
|
||||
}
|
||||
|
||||
CONST IVec2 &GetGridSize() CONST
|
||||
{
|
||||
return m_gridSize;
|
||||
}
|
||||
|
||||
CONST IVec2 &GetExtent() CONST
|
||||
{
|
||||
return m_extent;
|
||||
}
|
||||
|
||||
CONST IVec2 &GetGridCellSize() CONST
|
||||
{
|
||||
return m_gridCellSize;
|
||||
}
|
||||
|
||||
private:
|
||||
IVec2 m_gridSize{};
|
||||
@ -69,9 +88,4 @@ namespace ia::iae
|
||||
{
|
||||
m_referencedResources.pushBack(resource);
|
||||
}
|
||||
|
||||
CONST Vector<Handle> &Scene::GetReferencedResources() CONST
|
||||
{
|
||||
return m_referencedResources;
|
||||
}
|
||||
} // namespace ia::iae
|
||||
|
||||
Reference in New Issue
Block a user