This commit is contained in:
Isuru Samarathunga
2025-10-14 01:50:56 +05:30
parent 13e8c538c7
commit 58f2190199
13 changed files with 261 additions and 45 deletions

View File

@ -36,6 +36,13 @@ namespace ia::iae
glm::orthoLH(0.0f, (FLOAT32) width, (FLOAT32) height, 0.0f, Renderer::MIN_DEPTH, Renderer::MAX_DEPTH); glm::orthoLH(0.0f, (FLOAT32) width, (FLOAT32) height, 0.0f, Renderer::MIN_DEPTH, Renderer::MAX_DEPTH);
} }
CONST Mat4 *CameraComponent::GetViewMatrix()
{
const auto pos = m_node->GetPosition() + m_positionOffset;
m_viewMatrix = glm::lookAtLH(glm::vec3{pos, -2.0f}, {pos, 0.0f}, {0.0f, 1.0f, 0.0f});
return &m_viewMatrix;
}
VOID CameraComponent::Draw() VOID CameraComponent::Draw()
{ {
} }
@ -46,8 +53,6 @@ namespace ia::iae
VOID CameraComponent::Update() VOID CameraComponent::Update()
{ {
const auto pos = m_node->GetPosition() + m_positionOffset;
m_viewMatrix = glm::lookAtLH(glm::vec3{pos, -2.0f}, {pos, 0.0f}, {0.0f, 1.0f, 0.0f});
} }
VOID CameraComponent::FixedUpdate() VOID CameraComponent::FixedUpdate()

View File

@ -38,11 +38,26 @@ namespace ia::iae
#endif #endif
} }
String Engine::ReadTextAsset(IN CONST String &path)
{
SDL_IOStream *f = SDL_IOFromFile(path.c_str(), "r");
if (!f)
THROW_FILE_OPEN_READ(path);
Vector<CHAR> result;
SDL_SeekIO(f, 0, SDL_IO_SEEK_END);
result.resize(SDL_TellIO(f) + 1);
SDL_SeekIO(f, 0, SDL_IO_SEEK_SET);
SDL_ReadIO(f, result.data(), result.size());
result.back() = '\0';
SDL_CloseIO(f);
return result.data();
}
Vector<UINT8> Engine::ReadBinaryAsset(IN CONST String &path) Vector<UINT8> Engine::ReadBinaryAsset(IN CONST String &path)
{ {
SDL_IOStream* f = SDL_IOFromFile(path.c_str(), "rb"); SDL_IOStream *f = SDL_IOFromFile(path.c_str(), "rb");
if(!f) if (!f)
THROW_FILE_OPEN_READ(path); THROW_FILE_OPEN_READ(path);
Vector<UINT8> result; Vector<UINT8> result;
SDL_SeekIO(f, 0, SDL_IO_SEEK_END); SDL_SeekIO(f, 0, SDL_IO_SEEK_END);
result.resize(SDL_TellIO(f)); result.resize(SDL_TellIO(f));
@ -90,12 +105,6 @@ namespace ia::iae
return CreateSound(name, data.data(), data.size()); return CreateSound(name, data.data(), data.size());
} }
RefPtr<Scene> Engine::CreateSceneFromFile(IN CONST String &path)
{
const auto data = File::ReadToString(path.c_str());
return Scene::Create(data);
}
Handle Engine::ResizeImage(IN CONST String &name, IN INT32 newWidth, IN INT32 newHeight) Handle Engine::ResizeImage(IN CONST String &name, IN INT32 newWidth, IN INT32 newHeight)
{ {
return ResizeImage(GetImage(name), newWidth, newHeight); return ResizeImage(GetImage(name), newWidth, newHeight);

View File

@ -27,6 +27,8 @@
namespace ia::iae namespace ia::iae
{ {
STATIC Mat4 IdentityMatrix(1.0f);
EXTERN SDL_Window *g_windowHandle; EXTERN SDL_Window *g_windowHandle;
INT32 Renderer::s_screenWidth{}; INT32 Renderer::s_screenWidth{};
@ -136,8 +138,6 @@ namespace ia::iae
VOID Renderer::BeginFrame() VOID Renderer::BeginFrame()
{ {
STATIC Mat4 IdentityMatrix(1.0f);
if (!(s_state.ActiveCommandBuffer = SDL_AcquireGPUCommandBuffer(s_gpuDevice))) if (!(s_state.ActiveCommandBuffer = SDL_AcquireGPUCommandBuffer(s_gpuDevice)))
THROW_UNKNOWN("Failed to acquire SDL GPU command buffer: ", SDL_GetError()); THROW_UNKNOWN("Failed to acquire SDL GPU command buffer: ", SDL_GetError());
@ -152,10 +152,6 @@ namespace ia::iae
SDL_PushGPUVertexUniformData( SDL_PushGPUVertexUniformData(
s_state.ActiveCommandBuffer, 0, s_state.ActiveCommandBuffer, 0,
s_state.ActiveCamera ? s_state.ActiveCamera->GetProjectionMatrix() : &IdentityMatrix, sizeof(Mat4)); s_state.ActiveCamera ? s_state.ActiveCamera->GetProjectionMatrix() : &IdentityMatrix, sizeof(Mat4));
SDL_PushGPUVertexUniformData(
s_state.ActiveCommandBuffer, 1,
(s_state.ActiveCamera && s_state.CameraRelative) ? s_state.ActiveCamera->GetViewMatrix() : &IdentityMatrix,
sizeof(Mat4));
} }
VOID Renderer::EndFrame() VOID Renderer::EndFrame()
@ -236,9 +232,9 @@ namespace ia::iae
const auto activeScene = WorldManager::GetActiveScene(); const auto activeScene = WorldManager::GetActiveScene();
if (activeScene) if (activeScene)
{ {
const auto sceneExtent = activeScene->Extent(); const auto sceneViewport = activeScene->Viewport();
s_state.SceneScaleFactor = {(FLOAT32) newWidth / (FLOAT32) sceneExtent.x, s_state.SceneScaleFactor = {(FLOAT32) newWidth / (FLOAT32) sceneViewport.x,
(FLOAT32) newHeight / (FLOAT32) sceneExtent.y}; (FLOAT32) newHeight / (FLOAT32) sceneViewport.y};
IAE_LOG_INFO("Updated Scene Scale Factor: (", s_state.SceneScaleFactor.x, ", ", s_state.SceneScaleFactor.y, IAE_LOG_INFO("Updated Scene Scale Factor: (", s_state.SceneScaleFactor.x, ", ", s_state.SceneScaleFactor.y,
")"); ")");
} }
@ -282,6 +278,11 @@ namespace ia::iae
#pragma pack(pop) #pragma pack(pop)
SDL_PushGPUVertexUniformData(
s_state.ActiveCommandBuffer, 1,
(s_state.ActiveCamera && s_state.CameraRelative) ? s_state.ActiveCamera->GetViewMatrix() : &IdentityMatrix,
sizeof(Mat4));
s_fragmentUniform.ColorOverlay = s_state.ColorOverlay.GetAsFloatVec(); s_fragmentUniform.ColorOverlay = s_state.ColorOverlay.GetAsFloatVec();
s_fragmentUniform.FlippedH = s_state.FlippedH; s_fragmentUniform.FlippedH = s_state.FlippedH;
s_fragmentUniform.FlippedV = s_state.FlippedV; s_fragmentUniform.FlippedV = s_state.FlippedV;
@ -385,7 +386,7 @@ namespace ia::iae
sortIndex += static_cast<INT16>(position.y); sortIndex += static_cast<INT16>(position.y);
position *= Renderer::s_state.SceneScaleFactor; position *= Renderer::s_state.SceneScaleFactor;
// scale *= Renderer::s_state.SceneScaleFactor; scale *= Renderer::s_state.SceneScaleFactor;
Renderer::s_state.ModelMatrix = Renderer::s_state.ModelMatrix =
glm::translate(glm::mat4(1.0f), glm::vec3{position.x, position.y, glm::translate(glm::mat4(1.0f), glm::vec3{position.x, position.y,

View File

@ -17,20 +17,138 @@
#include <IAEngine/Engine.hpp> #include <IAEngine/Engine.hpp>
#include <IAEngine/Scene.hpp> #include <IAEngine/Scene.hpp>
#include <IAEngine/pugixml/pugixml.hpp>
namespace ia::iae namespace ia::iae
{ {
// -----------------------------------------------
// getInnerXML and xml_string_writer were taken from https://stackoverflow.com/a/60337372
struct xml_string_writer : pugi::xml_writer
{
std::string result;
virtual void write(const void *data, size_t size)
{
result.append(static_cast<const char *>(data), size);
}
};
const auto getInnerXML = [](pugi::xml_node target) {
xml_string_writer writer;
for (pugi::xml_node child = target.first_child(); child; child = child.next_sibling())
child.print(writer, "");
return writer.result;
};
// -----------------------------------------------
RefPtr<Scene> Scene::Create() RefPtr<Scene> Scene::Create()
{ {
const auto scene = MakeRefPtr<Scene>(); const auto scene = MakeRefPtr<Scene>();
scene->Extent() = Engine::GetDisplayExtent(); scene->Extent() = Engine::GetDisplayExtent();
const auto cameraNode = MakeRefPtr<CameraNode>("MainCamera");
scene->AddNode(cameraNode);
scene->m_camera = cameraNode->GetCameraComponent();
return scene; return scene;
} }
RefPtr<Scene> Scene::Create(IN CONST String &sceneXML) RefPtr<Scene> Scene::Create(IN CONST String &sceneXML,
IN std::function<RefPtr<Node2D>(IN CONST String &, IN Handle)> getCustomNode,
IN std::function<Handle(IN ResourceType type, IN CONST String &, IN INT64)> getResource)
{ {
const auto scene = MakeRefPtr<Scene>(); const auto scene = Create();
scene->Extent() = Engine::GetDisplayExtent();
pugi::xml_document doc;
doc.load_string(sceneXML.c_str());
const auto sceneRoot = doc.child("Scene");
Map<String, Handle> resources;
// Process Resources
const auto resRoot = sceneRoot.child("Resources");
if (!resRoot)
THROW_INVALID_DATA("Scene file is missing 'Resources' tag");
{
for (const auto &t : resRoot.children())
{
if (!strcmp(t.name(), "Image"))
{
resources[t.attribute("name").as_string()] = getResource(
ResourceType::IMAGE, t.attribute("path").as_string(), t.attribute("index").as_llong());
}
else if (!strcmp(t.name(), "Audio"))
{
resources[t.attribute("name").as_string()] =
getResource(ResourceType::SOUND, t.attribute("path").as_string(), 0);
}
}
}
// Process Properties
const auto propRoot = sceneRoot.child("Properties");
if (!propRoot)
THROW_INVALID_DATA("Scene file is missing 'Properties' tag");
{
auto t = propRoot.child("Extent");
scene->Extent() = Vec2{t.attribute("width").as_float(), t.attribute("height").as_float()};
t = propRoot.child("Viewport");
scene->Viewport() = Vec2{t.attribute("width").as_float(), t.attribute("height").as_float()};
}
// Process Nodes
const auto nodeRoot = sceneRoot.child("Nodes");
if (!nodeRoot)
THROW_INVALID_DATA("Scene file is missing 'Nodes' tag");
{
for (const auto &t : nodeRoot)
{
Node2D* n{};
if (!strcmp(t.name(), "TextureNode"))
{
const auto node = MakeRefPtr<TextureNode>(Engine::GetUniqueResourceName());
node->GetTextureComponent()->SetTexture(resources[t.attribute("texture").as_string()]);
scene->AddNode(node);
n = node.get();
}
else
{
Handle id{INVALID_HANDLE};
const auto attrID = t.attribute("id");
if(attrID)
id = (Handle)attrID.as_ullong();
const auto node = getCustomNode(t.name(), id);
scene->AddNode(node);
n = node.get();
}
if(!n) continue;
if(t.attribute("X") && t.attribute("Y"))
{
n->SetLocalPosition({
t.attribute("X").as_float(),
t.attribute("Y").as_float()
});
}
}
}
// Process UI
const auto uiRoot = sceneRoot.child("UI");
if (!uiRoot)
THROW_INVALID_DATA("Scene file is missing 'UI' tag");
{
scene->UIMarkupStyles() = getInnerXML(uiRoot.child("CSS")).c_str();
auto html = String(getInnerXML(uiRoot.child("HTML")).c_str());
html =
Utils::RegexReplaceGroups(html, "<img(.*?)src=\"(.*?)\"", [&](IN INT32 index, IN CONST String &match) {
if(index == 1)
return BuildString("$H$", resources[match]);
return match;
});
scene->UIMarkup() = html;
}
return scene; return scene;
} }
@ -72,4 +190,11 @@ namespace ia::iae
{ {
m_nodes[name] = nullptr; m_nodes[name] = nullptr;
} }
VOID Scene::OnActivate()
{
UI::SetMarkup(UIMarkup(), UIMarkupStyles());
if(m_camera)
Engine::SetActiveCamera(m_camera);
}
} // namespace ia::iae } // namespace ia::iae

View File

@ -452,10 +452,11 @@ namespace ia::iae
Rml::LoadFontFace(path.c_str()); Rml::LoadFontFace(path.c_str());
} }
VOID UI::SetHTML(IN CONST String &source) VOID UI::SetMarkup(IN CONST String &markup, IN CONST String &styles)
{ {
g_document->SetStyleSheetContainer(Rml::Factory::InstanceStyleSheetString(styles.c_str()));
g_document->SetInnerRML( g_document->SetInnerRML(
BuildString("<body style=\"display: block; width: 100%; height: 100%;\">", source, "</body>").c_str()); BuildString("<body style=\"display: block; width: 100%; height: 100%;\">", markup, "</body>").c_str());
} }
VOID UI::AddClickEvent(IN PCCHAR elementId, IN std::function<VOID()> callback) VOID UI::AddClickEvent(IN PCCHAR elementId, IN std::function<VOID()> callback)
@ -502,8 +503,14 @@ namespace ia::iae
Rml::TextureHandle RmlUIRenderInterface::LoadTexture(Rml::Vector2i &texture_dimensions, const Rml::String &source) Rml::TextureHandle RmlUIRenderInterface::LoadTexture(Rml::Vector2i &texture_dimensions, const Rml::String &source)
{ {
return Engine::CreateImageFromFile(Engine::GetUniqueResourceName(), source.c_str(), texture_dimensions.x, Handle result;
texture_dimensions.y); if (source.starts_with("$H$"))
result = (Handle) std::stoi(source.substr(3));
else
result = Engine::CreateImageFromFile(Engine::GetUniqueResourceName(), source.c_str());
const auto extent = Engine::GetImageExtent(result);
texture_dimensions = {extent.x, extent.y};
return result;
} }
Rml::TextureHandle RmlUIRenderInterface::GenerateTexture(Rml::Span<const Rml::byte> source, Rml::TextureHandle RmlUIRenderInterface::GenerateTexture(Rml::Span<const Rml::byte> source,

View File

@ -18,13 +18,15 @@
#include <zlib.h> #include <zlib.h>
#include <regex>
namespace ia::iae namespace ia::iae
{ {
Vector<UINT8> Utils::Inflate(IN PCUINT8 data, IN SIZE_T dataSize) Vector<UINT8> Utils::Inflate(IN PCUINT8 data, IN SIZE_T dataSize)
{ {
STATIC UINT8 TMP_BUFFER[16384]; STATIC UINT8 TMP_BUFFER[16384];
Vector<UINT8> result; Vector<UINT8> result;
result.reserve(ia_min((SIZE_T)(dataSize * 3), sizeof(TMP_BUFFER))); result.reserve(ia_min((SIZE_T) (dataSize * 3), sizeof(TMP_BUFFER)));
z_stream stream; z_stream stream;
stream.zalloc = Z_NULL; stream.zalloc = Z_NULL;
stream.zfree = Z_NULL; stream.zfree = Z_NULL;
@ -35,7 +37,8 @@ namespace ia::iae
THROW_UNKNOWN("Inflate failed: init zlib inflate"); THROW_UNKNOWN("Inflate failed: init zlib inflate");
stream.avail_in = dataSize; stream.avail_in = dataSize;
stream.next_in = (Bytef *) data; stream.next_in = (Bytef *) data;
while (true) { while (true)
{
stream.avail_out = sizeof(TMP_BUFFER); stream.avail_out = sizeof(TMP_BUFFER);
stream.next_out = TMP_BUFFER; stream.next_out = TMP_BUFFER;
const auto r = inflate(&stream, Z_SYNC_FLUSH); const auto r = inflate(&stream, Z_SYNC_FLUSH);
@ -58,4 +61,35 @@ namespace ia::iae
result.resize(deflateBound); result.resize(deflateBound);
return result; return result;
} }
String Utils::RegexReplaceString(IN CONST String &input, IN CONST String &from, IN CONST String &to)
{
return std::regex_replace(input.c_str(), std::regex(from.c_str()), to.c_str()).c_str();
}
String Utils::RegexReplaceGroups(IN CONST String &input, IN CONST String &pattern,
IN std::function<String(IN INT32, IN CONST String &)> groupTransformer)
{
std::string text = input.c_str();
std::smatch match;
std::string result;
std::string::const_iterator search_start(text.cbegin());
SIZE_T t1 = 0, t2 = 0;
while (std::regex_search(search_start, text.cend(), match, std::regex(pattern.c_str())))
{
for(SIZE_T i = 1; i < match.size(); i++)
{
result += text.substr(t1, match.position(i) - t1);
result += std::string(groupTransformer(i - 1, match.str(i).c_str()).c_str());
t1 = match.position(i);
t2 = match.str(i).length();
}
result += text.substr(match.suffix().first - text.begin() - 1);
search_start = match.suffix().first;
}
return result.c_str();
}
} // namespace ia::iae } // namespace ia::iae

View File

@ -54,6 +54,7 @@ namespace ia::iae
VOID WorldManager::ChangeActiveScene(IN RefPtr<Scene> scene) VOID WorldManager::ChangeActiveScene(IN RefPtr<Scene> scene)
{ {
s_activeScene = scene; s_activeScene = scene;
scene->OnActivate();
} }
VOID WorldManager::AddNodeToActiveScene(IN RefPtr<INode> node) VOID WorldManager::AddNodeToActiveScene(IN RefPtr<INode> node)

View File

@ -102,7 +102,8 @@ namespace ia::iae
Vec4 Color{}; Vec4 Color{};
}; };
enum class Direction : UINT8 { enum class Direction : UINT8
{
NONE = 255, NONE = 255,
DOWN = 0, DOWN = 0,
DOWN_LEFT, DOWN_LEFT,
@ -114,6 +115,12 @@ namespace ia::iae
DOWN_RIGHT DOWN_RIGHT
}; };
enum class ResourceType
{
IMAGE,
SOUND,
};
struct Color struct Color
{ {
UINT8 R{0xFF}; UINT8 R{0xFF};

View File

@ -45,10 +45,7 @@ namespace ia::iae
return m_viewport; return m_viewport;
} }
CONST Mat4 *GetViewMatrix() CONST CONST Mat4 *GetViewMatrix();
{
return &m_viewMatrix;
}
CONST Mat4 *GetProjectionMatrix() CONST CONST Mat4 *GetProjectionMatrix() CONST
{ {
@ -57,8 +54,8 @@ namespace ia::iae
private: private:
Vec4 m_viewport{}; Vec4 m_viewport{};
Mat4 m_viewMatrix{1.0f};
Vec2 m_positionOffset{}; Vec2 m_positionOffset{};
Mat4 m_viewMatrix{1.0f};
Mat4 m_projectionMatrix{1.0f}; Mat4 m_projectionMatrix{1.0f};
}; };
} // namespace ia::iae } // namespace ia::iae

View File

@ -93,7 +93,6 @@ namespace ia::iae
STATIC CameraComponent *GetActiveCamera(); STATIC CameraComponent *GetActiveCamera();
// Scene Functions // Scene Functions
STATIC RefPtr<Scene> CreateSceneFromFile(IN CONST String &path);
STATIC Scene *GetActiveScene(); STATIC Scene *GetActiveScene();
STATIC VOID ChangeActiveScene(IN RefPtr<Scene> scene); STATIC VOID ChangeActiveScene(IN RefPtr<Scene> scene);
STATIC VOID AddNodeToActiveScene(IN RefPtr<INode> node); STATIC VOID AddNodeToActiveScene(IN RefPtr<INode> node);
@ -118,6 +117,7 @@ namespace ia::iae
STATIC VOID BindInputAxis(IN InputKey upKey, IN InputKey downKey, IN InputKey leftKey, IN InputKey rightKey); STATIC VOID BindInputAxis(IN InputKey upKey, IN InputKey downKey, IN InputKey leftKey, IN InputKey rightKey);
// Utility Functions // Utility Functions
STATIC String ReadTextAsset(IN CONST String& path);
STATIC Direction GetVectorPointingDirection(IN Vec2 v); STATIC Direction GetVectorPointingDirection(IN Vec2 v);
STATIC Vector<UINT8> ReadBinaryAsset(IN CONST String& path); STATIC Vector<UINT8> ReadBinaryAsset(IN CONST String& path);

View File

@ -16,6 +16,7 @@
#pragma once #pragma once
#include <IAEngine/Components/CameraComponent.hpp>
#include <IAEngine/Nodes/INode.hpp> #include <IAEngine/Nodes/INode.hpp>
namespace ia::iae namespace ia::iae
@ -23,27 +24,48 @@ namespace ia::iae
class Scene class Scene
{ {
public: public:
STATIC RefPtr<Scene> Create(); STATIC RefPtr<Scene> Create();
STATIC RefPtr<Scene> Create(IN CONST String &sceneXML); STATIC RefPtr<Scene> Create(
IN CONST String &sceneXML, IN std::function<RefPtr<Node2D>(IN CONST String &, IN Handle)> getCustomNode,
IN std::function<Handle(IN ResourceType type, IN CONST String &, IN INT64)> getResource);
public: public:
VOID AddNode(IN RefPtr<INode> node); VOID AddNode(IN RefPtr<INode> node);
INode *GetNode(IN CONST String &name); INode *GetNode(IN CONST String &name);
VOID RemoveNode(IN CONST String &name); VOID RemoveNode(IN CONST String &name);
public: public:
IVec2& Extent() String &UIMarkup()
{
return m_uiMarkup;
}
String &UIMarkupStyles()
{
return m_uiMarkupStyles;
}
IVec2 &Extent()
{ {
return m_extent; return m_extent;
} }
IVec2 &Viewport()
{
return m_viewport;
}
Color &BackgroundColor() Color &BackgroundColor()
{ {
return m_backgroundColor; return m_backgroundColor;
} }
private: private:
String m_uiMarkup{};
String m_uiMarkupStyles{};
IVec2 m_extent{100, 100}; IVec2 m_extent{100, 100};
IVec2 m_viewport{100, 100};
CameraComponent *m_camera{};
Color m_backgroundColor{0, 0, 0, 255}; Color m_backgroundColor{0, 0, 0, 255};
Map<String, RefPtr<INode>> m_nodes; Map<String, RefPtr<INode>> m_nodes;
@ -53,5 +75,10 @@ namespace ia::iae
VOID FixedUpdate(); VOID FixedUpdate();
VOID Update(); VOID Update();
private:
VOID OnActivate();
friend class WorldManager;
}; };
} // namespace ia::iae } // namespace ia::iae

View File

@ -25,7 +25,7 @@ namespace ia::iae
public: public:
STATIC VOID AddFontFromFile(IN CONST String &path); STATIC VOID AddFontFromFile(IN CONST String &path);
STATIC VOID SetHTML(IN CONST String &source); STATIC VOID SetMarkup(IN CONST String &markup, IN CONST String &styles);
STATIC VOID AddClickEvent(IN PCCHAR elementId, IN std::function<VOID()> callback); STATIC VOID AddClickEvent(IN PCCHAR elementId, IN std::function<VOID()> callback);

View File

@ -25,5 +25,8 @@ namespace ia::iae
public: public:
STATIC Vector<UINT8> Inflate(IN PCUINT8 data, IN SIZE_T dataSize); STATIC Vector<UINT8> Inflate(IN PCUINT8 data, IN SIZE_T dataSize);
STATIC Vector<UINT8> Deflate(IN PCUINT8 data, IN SIZE_T dataSize); STATIC Vector<UINT8> Deflate(IN PCUINT8 data, IN SIZE_T dataSize);
STATIC String RegexReplaceString(IN CONST String& input, IN CONST String& from, IN CONST String& to);
STATIC String RegexReplaceGroups(IN CONST String& input, IN CONST String& pattern, IN std::function<String(IN INT32, IN CONST String&)> groupTransformer);
}; };
} }