Grid Loading from XML

This commit is contained in:
Isuru Samarathunga
2025-11-03 04:36:05 +05:30
parent a00fe1a165
commit ca75777f19
9 changed files with 374 additions and 19 deletions

View File

@ -25,7 +25,83 @@
</Nodes>
<Grid tileWidth="16" tileHeight="16">
<Repeat times="1900">
<Repeat times="50">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="30">
<Cell tileSheet="TileSheet_MiddleWater" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="30">
<Cell tileSheet="TileSheet_MiddleWater" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="13">
<Cell tileSheet="TileSheet_MiddleWater" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Cell tileSheet="TileSheet_Beach" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
<Cell tileSheet="TileSheet_Beach" tileX="1" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
<Cell tileSheet="TileSheet_Beach" tileX="2" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
<Repeat times="14">
<Cell tileSheet="TileSheet_MiddleWater" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="13">
<Cell tileSheet="TileSheet_MiddleWater" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Cell tileSheet="TileSheet_Beach" tileX="0" tileY="1" collisionMask="0" colorOverlay="#ffffffff"></Cell>
<Cell tileSheet="TileSheet_Beach" tileX="1" tileY="1" collisionMask="0" colorOverlay="#ffffffff"></Cell>
<Cell tileSheet="TileSheet_Beach" tileX="2" tileY="1" collisionMask="0" colorOverlay="#ffffffff"></Cell>
<Repeat times="14">
<Cell tileSheet="TileSheet_MiddleWater" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="13">
<Cell tileSheet="TileSheet_MiddleWater" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Cell tileSheet="TileSheet_Beach" tileX="0" tileY="2" collisionMask="0" colorOverlay="#ffffffff"></Cell>
<Cell tileSheet="TileSheet_Beach" tileX="1" tileY="2" collisionMask="0" colorOverlay="#ffffffff"></Cell>
<Cell tileSheet="TileSheet_Beach" tileX="2" tileY="2" collisionMask="0" colorOverlay="#ffffffff"></Cell>
<Repeat times="14">
<Cell tileSheet="TileSheet_MiddleWater" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="30">
<Cell tileSheet="TileSheet_MiddleWater" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="10">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
<Repeat times="50">
<Cell tileSheet="TileSheet_MiddleGrass" tileX="0" tileY="0" collisionMask="0" colorOverlay="#ffffffff"></Cell>
</Repeat>
</Grid>

View File

@ -75,7 +75,7 @@ namespace ia::iae::rpg
VOID OnUpdate(IN FLOAT32 deltaTime)
{
//IAEngine::DrawSprite(g_playerSpriteSheet, 2, 0, {100.0f, 100.0f}, {1.0f, 1.0f}, 0.0f);
//IAEngine::DrawSprite(0, 2, 0, {100.0f, 100.0f}, {1.0f, 1.0f}, 0.0f);
}
VOID OnResize(IN INT32 newWidth, IN INT32 newHeight)

View File

@ -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

View File

@ -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

View File

@ -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++;
}
}
}

View File

@ -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();

View File

@ -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:

View File

@ -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

2
Vendor/IACore vendored