From cdfee1981c769aa416cf9102d212b0d05a2b8af8 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Sat, 12 Jun 2021 13:01:07 -0400 Subject: [PATCH] Various improvements: Framebuffer resize queued to next frame to fix flickering Wren VM init moved to on play event Added new Wren modules Added missing components to the editor Changed how the wren scripts gets initialized --- Editor/resources/Scripts/Math.wren | 46 ++++++++ Editor/resources/Scripts/Scene.wren | 111 +++++++++++------- .../resources/Scripts/ScriptableEntity.wren | 15 +++ Editor/src/EditorInterface.cpp | 87 ++++++++++---- Nuake/Engine.cpp | 2 - Nuake/src/Rendering/Camera.h | 3 +- Nuake/src/Rendering/Framebuffer.cpp | 9 ++ Nuake/src/Rendering/Framebuffer.h | 4 +- Nuake/src/Rendering/Shaders/Shader.cpp | 2 +- Nuake/src/Resource/Project.cpp | 5 +- .../Entities/Components/InterfaceComponent.h | 8 ++ .../Entities/Components/WrenScriptComponent.h | 31 +++++ Nuake/src/Scene/Entities/Entity.cpp | 4 + Nuake/src/Scene/Scene.cpp | 46 ++++++-- Nuake/src/Scripting/Modules/MathModule.h | 6 +- Nuake/src/Scripting/Modules/SceneModule.h | 71 +++++++++++ Nuake/src/Scripting/ScriptingEngine.cpp | 16 ++- Nuake/src/Scripting/WrenScript.cpp | 33 +++++- Nuake/src/Scripting/WrenScript.h | 5 +- Nuake/src/UI/InterfaceParser.cpp | 7 +- Nuake/src/UI/Nodes/Canvas.h | 4 + Nuake/src/UI/Styling/Stylesheet.h | 27 +++-- Nuake/src/UI/UserInterface.cpp | 14 +-- Nuake/src/UI/UserInterface.h | 1 - Nuake/src/Window.cpp | 2 + 25 files changed, 451 insertions(+), 108 deletions(-) create mode 100644 Editor/resources/Scripts/ScriptableEntity.wren create mode 100644 Nuake/src/Scene/Entities/Components/InterfaceComponent.h create mode 100644 Nuake/src/Scene/Entities/Components/WrenScriptComponent.h diff --git a/Editor/resources/Scripts/Math.wren b/Editor/resources/Scripts/Math.wren index 7daa24ef..533ebbb5 100644 --- a/Editor/resources/Scripts/Math.wren +++ b/Editor/resources/Scripts/Math.wren @@ -3,6 +3,52 @@ class Math { } class Vector3 { + + x {_x} + y {_y} + z {_z} + x=(value) { + _x = value + } + y=(value) { + _y = value + } + z=(value) { + _z = value + } + + mul(other) { + if(other is Vector3) { + return Vector3.new(_x * other.x, + _y * other.y, + _z * other.z) + } else { + return Vector3.new(_x * other, _y * other, _z * other) + } + } + + *(other) { + if(other is Vector3) { + return Vector3.new(_x * other.x, + _y * other.y, + _z * other.z) + } else if(other is Num) { + return Vector3.new(_x * other, _y * other, _z * other) + } + } + + +(other) { + if(other is Vector3) { + return Vector3.new(_x + other.x, + _y + other.y, + _z + other.z) + } else if(other is Num) { + return Vector3.new(_x + other, + _y + other, + _z + other) + } + } + construct new(x, y, z) { _x = x _y = y diff --git a/Editor/resources/Scripts/Scene.wren b/Editor/resources/Scripts/Scene.wren index c6c0d099..4f6b5f36 100644 --- a/Editor/resources/Scripts/Scene.wren +++ b/Editor/resources/Scripts/Scene.wren @@ -1,4 +1,5 @@ import "Scripts/Engine" for Engine +import "Scripts/Math" for Vector3 class Scene { foreign static GetEntityID(name) @@ -11,35 +12,50 @@ class Scene { } foreign static EntityHasComponent(id, name) + static EntityGetComponent(id, component) { + if(this.EntityHasComponent(id, component) == false) { + Engine.Log("Tried getting a non-existent component of type: %(component) on entity with id: %(id)") + return + } - // Component specific private setter and getter. - foreign static GetLightIntensity_(e) - foreign static SetLightIntensity_(e, intensity) + if (component == "Light") { + return Light.new(id) + } else if (component == "CharacterController") { + return CharacterController.new(id) + } else if (component == "Camera") { + return Camera.new(id) + } + } - /* - // Transform - foreign static SetTranslation_(e, x, y, z) - foreign static SetRotation_(e, x, y, z) - foreign static SetScale_(e, x, y, z) - - // Character controller - foreign static SetVelocity(e, x, y, z) - foreign static SetStepHeight(e, x, y, z) - foreign static IsOnGround(e) - */ - // Light + // + // Components // - /* - foreign static SetLightIsVolumetric_(e, bool) - foreign static SetLightSyncDirectionWithSky_(e, bool) - foreign static SetLightColor_(e, r, g, b) + // Transform + //foreign static SetTranslation_(e, x, y, z) + //foreign static SetRotation_(e, x, y, z) + //foreign static SetScale_(e, x, y, z) + + // Light + foreign static GetLightIntensity_(e) // returns a float + foreign static SetLightIntensity_(e, intensity) + //foreign static SetLightIsVolumetric_(e, bool) + //foreign static SetLightSyncDirectionWithSky_(e, bool) + //foreign static SetLightColor_(e, r, g, b) + //foreign static GetLightColor_(e) // Camera - foreign static SetCameraFov_(e, fov) - foreign static SetCameraType(e, type) foreign static SetCameraDirection_(e, x, y, z) - */ + foreign static GetCameraDirection_(e) // returns a list x,y,z + foreign static GetCameraRight_(e) // returns a list x,y,z + //foreign static SetcameraFov(e, fov) + //foreign static GetCameraFov(e) // returns a float + + // Character controller + foreign static MoveAndSlide_(e, x, y, z) + //foreign static IsOnGround_(e) + + } class Entity { @@ -52,14 +68,7 @@ class Entity { } GetComponent(component) { - if(this.HasComponent(component) == false) { - Engine.Log("Tried getting a non-existent component of type: %(component) on entity with id: %(_entityId)") - return - } - - if (component == "Light") { - return Light.new(_entityId) - } + return Scene.EntityGetComponent(_entityId, component) } // Foreign engine functions @@ -110,17 +119,37 @@ class Light { SetColor(color) { this.SetColor_(_entityId, color.r, color.g, color.b, color.a) + }*/ + +} + +class CharacterController { + construct new(id) { + _entityId = id } - SetDirection(direction) { - var normalized = direction.Normalize() - this.SetDirection_(_entityId, normalized.x, normalized.y, normalized.z) + MoveAndSlide(vel) { + Scene.MoveAndSlide_(_entityId, vel.x, vel.y, vel.z) } - - foreign static SetType_(id, type) - foreign static SetColor_(id, r, g, b) - - foreign static SetDirection_(id, x, y, z) - */ - -} \ No newline at end of file +} + +class Camera { + construct new(id) { + _entityId = id + } + + SetDirection(dir) { + Scene.SetCameraDirection_(_entityId, dir.x, dir.y, dir.z) + } + + GetDirection() { + var dir = Scene.GetCameraDirection_(_entityId) + return Vector3.new(dir[0], dir[1], dir[2]) + } + + GetRight() { + var dir = Scene.GetCameraRight_(_entityId) + return Vector3.new(dir[0], dir[1], dir[2]) + } + +} diff --git a/Editor/resources/Scripts/ScriptableEntity.wren b/Editor/resources/Scripts/ScriptableEntity.wren new file mode 100644 index 00000000..0049e912 --- /dev/null +++ b/Editor/resources/Scripts/ScriptableEntity.wren @@ -0,0 +1,15 @@ +import "Scripts/Scene" for Scene + +class ScriptableEntity { + SetEntityId(id) { + _EntityID = id + } + + GetComponent(component) { + return Scene.EntityGetComponent(_EntityID, component) + } + + HasComponent(component) { + return Scene.EntityHasComponent(_EntityID, component) + } +} \ No newline at end of file diff --git a/Editor/src/EditorInterface.cpp b/Editor/src/EditorInterface.cpp index dc84726b..275cd48e 100644 --- a/Editor/src/EditorInterface.cpp +++ b/Editor/src/EditorInterface.cpp @@ -19,6 +19,7 @@ #include "src/Resource/Project.h" #include #include +#include Ref userInterface; ImFont* normalFont; ImFont* EditorInterface::bigIconFont; @@ -80,7 +81,7 @@ void EditorInterface::DrawViewport() glm::vec2 viewportPanelSize = glm::vec2(regionAvail.x, regionAvail.y); if(Engine::GetCurrentWindow()->GetFrameBuffer()->GetSize() != viewportPanelSize) - Engine::GetCurrentWindow()->GetFrameBuffer()->UpdateSize(viewportPanelSize); + Engine::GetCurrentWindow()->GetFrameBuffer()->QueueResize(viewportPanelSize); Ref texture = Engine::GetCurrentWindow()->GetFrameBuffer()->GetTexture(); ImGui::Image((void*)texture->GetID(), regionAvail, ImVec2(0, 1), ImVec2(1, 0)); @@ -321,16 +322,22 @@ void EditorInterface::DrawEntityPropreties() } if (ImGui::BeginPopup("add_component_popup")) { - if (ImGui::MenuItem("Lua script") && !m_SelectedEntity.HasComponent()) - m_SelectedEntity.AddComponent(); - if (ImGui::MenuItem("Light Component") && !m_SelectedEntity.HasComponent()) - m_SelectedEntity.AddComponent(); - if (ImGui::MenuItem("Mesh Component") && !m_SelectedEntity.HasComponent()) - m_SelectedEntity.AddComponent(); + if (ImGui::MenuItem("Wren Script") && !m_SelectedEntity.HasComponent()) + m_SelectedEntity.AddComponent(); + ImGui::Separator(); if (ImGui::MenuItem("Camera Component") && !m_SelectedEntity.HasComponent()) m_SelectedEntity.AddComponent(); + ImGui::Separator(); + if (ImGui::MenuItem("Light Component") && !m_SelectedEntity.HasComponent()) + m_SelectedEntity.AddComponent(); + ImGui::Separator(); + if (ImGui::MenuItem("Mesh Component") && !m_SelectedEntity.HasComponent()) + m_SelectedEntity.AddComponent(); if (ImGui::MenuItem("Quake map Component") && !m_SelectedEntity.HasComponent()) m_SelectedEntity.AddComponent(); + ImGui::Separator(); + if (ImGui::MenuItem("Character controller") && !m_SelectedEntity.HasComponent()) + m_SelectedEntity.AddComponent(); if (ImGui::MenuItem("Rigidbody Component") && !m_SelectedEntity.HasComponent()) { m_SelectedEntity.AddComponent(); @@ -377,32 +384,43 @@ void EditorInterface::DrawEntityPropreties() } - if (m_SelectedEntity.HasComponent()) { + if (m_SelectedEntity.HasComponent()) { std::string icon = ICON_FA_FILE; - if (ImGui::CollapsingHeader((icon + " " + "Lua script").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) + if (ImGui::CollapsingHeader((icon + " " + "Wren Script").c_str(), ImGuiTreeNodeFlags_DefaultOpen)) { - auto& component = m_SelectedEntity.GetComponent(); + auto& component = m_SelectedEntity.GetComponent(); + + // Path std::string path = component.Script; - - char pathBuffer[256]; + memset(pathBuffer, 0, sizeof(pathBuffer)); std::strncpy(pathBuffer, path.c_str(), sizeof(pathBuffer)); + if (ImGui::InputText("##ScriptPath", pathBuffer, sizeof(pathBuffer))) - { - path = std::string(pathBuffer); - } + path = FileSystem::AbsoluteToRelative(std::string(pathBuffer)); + ImGui::SameLine(); + if (ImGui::Button("Browse")) - { - path = FileDialog::OpenFile(".map"); - } + path = FileSystem::AbsoluteToRelative(FileDialog::OpenFile(".wren")); component.Script = path; + // Class + std::string module = component.Class; + + char classBuffer[256]; + + memset(classBuffer, 0, sizeof(classBuffer)); + std::strncpy(classBuffer, module.c_str(), sizeof(classBuffer)); + + if (ImGui::InputText("##ScriptModule", classBuffer, sizeof(classBuffer))) + module = std::string(classBuffer); + + component.Class = module; ImGui::Separator(); } - } if (m_SelectedEntity.HasComponent()) { @@ -416,6 +434,18 @@ void EditorInterface::DrawEntityPropreties() } + if (m_SelectedEntity.HasComponent()) + { + if (ImGui::CollapsingHeader("Character controller", ImGuiTreeNodeFlags_DefaultOpen)) + { + auto& c = m_SelectedEntity.GetComponent(); + ImGui::InputFloat("Height", &c.Height); + ImGui::InputFloat("Radius", &c.Radius); + ImGui::InputFloat("Mass", &c.Mass); + ImGui::Separator(); + } + } + if (m_SelectedEntity.HasComponent()) { std::string icon = ICON_FA_TREE; @@ -907,17 +937,26 @@ void OpenProject() Engine::LoadProject(project); // Create new interface named test. - userInterface = UI::UserInterface::New("test"); + //userInterface = UI::UserInterface::New("test"); // Set current interface running. - Engine::GetCurrentScene()->AddInterface(userInterface); - + //Engine::GetCurrentScene()->AddInterface(userInterface); } void OpenScene() { + // Parse the project and load it. + std::string projectPath = FileDialog::OpenFile(".scene"); + Ref scene = Scene::New(); + if (!scene->Deserialize(FileSystem::ReadFile(projectPath, true))) { + Logger::Log("Error failed loading scene: " + projectPath); + return; + } + + scene->Path = FileSystem::AbsoluteToRelative(projectPath); + Engine::LoadScene(scene); } void EditorInterface::DrawInit() @@ -981,6 +1020,10 @@ void EditorInterface::Draw() m_IsEntitySelected = false; } ImGui::Separator(); + if (ImGui::MenuItem("Set current scene as default")) { + Engine::GetProject()->DefaultScene = Engine::GetCurrentScene(); + } + ImGui::Separator(); if (ImGui::MenuItem("Open scene...", "CTRL+O")) { OpenScene(); diff --git a/Nuake/Engine.cpp b/Nuake/Engine.cpp index 23c1ccca..7ac8358b 100644 --- a/Nuake/Engine.cpp +++ b/Nuake/Engine.cpp @@ -24,8 +24,6 @@ void Engine::Init() PhysicsManager::Get()->Init(); Logger::Log("Physics initialized"); - ScriptingEngine::Init(); - Logger::Log("Scripting engine initialized"); CurrentWindow = Window::Get(); Logger::Log("Window initialized"); diff --git a/Nuake/src/Rendering/Camera.h b/Nuake/src/Rendering/Camera.h index 6c6a6699..d0bd67fe 100644 --- a/Nuake/src/Rendering/Camera.h +++ b/Nuake/src/Rendering/Camera.h @@ -16,12 +16,13 @@ class Camera : public ISerializable private: CAMERA_TYPE m_Type; - float AspectRatio = 16.0f / 9.0f; + Vector3 Rotation = { 0.0f, 0.0f, 0.0f }; Vector3 Scale = { 1.0f, 1.0f, 1.0f }; Matrix4 m_Perspective; public: + float AspectRatio = 16.0f / 9.0f; // TODO: remove duplicate direction and have a proper api. Vector3 up = Vector3(0.0f, 1.0f, 0.0f); Vector3 cameraFront = Vector3(0.0f, 0.0f, 1.0f); diff --git a/Nuake/src/Rendering/Framebuffer.cpp b/Nuake/src/Rendering/Framebuffer.cpp index 9ad7c9b9..3bc90757 100644 --- a/Nuake/src/Rendering/Framebuffer.cpp +++ b/Nuake/src/Rendering/Framebuffer.cpp @@ -55,6 +55,9 @@ void FrameBuffer::SetTexture(Ref texture, GLenum attachment) void FrameBuffer::Bind() { + if (ResizeQueued) + UpdateSize(m_Size); + glBindFramebuffer(GL_FRAMEBUFFER, m_FramebufferID); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, m_Size.x, m_Size.y); @@ -65,6 +68,12 @@ void FrameBuffer::Unbind() glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void FrameBuffer::QueueResize(Vector2 size) +{ + ResizeQueued = true; + m_Size = size; +} + void FrameBuffer::UpdateSize(Vector2 size) { m_Size = size; diff --git a/Nuake/src/Rendering/Framebuffer.h b/Nuake/src/Rendering/Framebuffer.h index a4ee0abf..9c058e19 100644 --- a/Nuake/src/Rendering/Framebuffer.h +++ b/Nuake/src/Rendering/Framebuffer.h @@ -11,7 +11,8 @@ private: unsigned int m_RenderBuffer; Vector2 m_Size; - + bool ResizeQueued = false; + std::map> m_Textures; Ref m_Texture; @@ -27,6 +28,7 @@ public: void Bind(); void Unbind(); + void QueueResize(Vector2 size); Vector2 GetSize() const { return m_Size; } void UpdateSize(Vector2 size); diff --git a/Nuake/src/Rendering/Shaders/Shader.cpp b/Nuake/src/Rendering/Shaders/Shader.cpp index 4179b18c..7ccb8c41 100644 --- a/Nuake/src/Rendering/Shaders/Shader.cpp +++ b/Nuake/src/Rendering/Shaders/Shader.cpp @@ -125,7 +125,7 @@ int Shader::FindUniformLocation(std::string uniform) { if (addr == -1) std::cout << "Warning: uniform '" << uniform << "' doesn't exists!" << std::endl; else { - std::cout << "Info: uniform '" << uniform << "' registered." << std::endl; + //std::cout << "Info: uniform '" << uniform << "' registered." << std::endl; UniformCache[uniform] = addr; } diff --git a/Nuake/src/Resource/Project.cpp b/Nuake/src/Resource/Project.cpp index 6a9433d4..5b27f535 100644 --- a/Nuake/src/Resource/Project.cpp +++ b/Nuake/src/Resource/Project.cpp @@ -33,11 +33,8 @@ void Project::Save() void Project::SaveAs(const std::string FullPath) { - // Serialize the scene. - BEGIN_SERIALIZE(); - SERIALIZE_VAL(Name); - SERIALIZE_VAL(Description); + json j = Serialize(); // Dump. std::string serialized_string = j.dump(); diff --git a/Nuake/src/Scene/Entities/Components/InterfaceComponent.h b/Nuake/src/Scene/Entities/Components/InterfaceComponent.h new file mode 100644 index 00000000..00390d5f --- /dev/null +++ b/Nuake/src/Scene/Entities/Components/InterfaceComponent.h @@ -0,0 +1,8 @@ +#pragma once +#include "../Core/Core.h" +#include + +class InterfaceComponent +{ + Ref Interface; +}; \ No newline at end of file diff --git a/Nuake/src/Scene/Entities/Components/WrenScriptComponent.h b/Nuake/src/Scene/Entities/Components/WrenScriptComponent.h new file mode 100644 index 00000000..0dab3666 --- /dev/null +++ b/Nuake/src/Scene/Entities/Components/WrenScriptComponent.h @@ -0,0 +1,31 @@ +#pragma once +#include "../Scripting/WrenScript.h" + +class WrenScriptComponent +{ +public: + std::string Script; + std::string Class; + + Ref WrenScript; + + json Serialize() + { + BEGIN_SERIALIZE(); + SERIALIZE_VAL(Script); + SERIALIZE_VAL(Class); + END_SERIALIZE(); + } + + bool Deserialize(std::string str) + { + BEGIN_DESERIALIZE(); + if (j.contains("Script")) + Script = j["Script"]; + if (j.contains("Class")) + Class = j["Class"]; + + + return true; + } +}; \ No newline at end of file diff --git a/Nuake/src/Scene/Entities/Entity.cpp b/Nuake/src/Scene/Entities/Entity.cpp index 69937b51..895851ba 100644 --- a/Nuake/src/Scene/Entities/Entity.cpp +++ b/Nuake/src/Scene/Entities/Entity.cpp @@ -8,6 +8,7 @@ #include "Components/QuakeMap.h" #include "Components/LightComponent.h" #include "Components/QuakeMap.h" +#include void Entity::AddChild(Entity ent) { if ((int)m_EntityHandle != ent.GetHandle()) @@ -31,6 +32,8 @@ json Entity::Serialize() SERIALIZE_OBJECT_REF_LBL("QuakeMapComponent", GetComponent()); if (HasComponent()) SERIALIZE_OBJECT_REF_LBL("LightComponent", GetComponent()); + if (HasComponent()) + SERIALIZE_OBJECT_REF_LBL("WrenScriptComponent", GetComponent()); END_SERIALIZE(); } @@ -43,6 +46,7 @@ bool Entity::Deserialize(const std::string& str) DESERIALIZE_COMPONENT(CameraComponent); DESERIALIZE_COMPONENT(QuakeMapComponent); DESERIALIZE_COMPONENT(LightComponent); + DESERIALIZE_COMPONENT(WrenScriptComponent); return true; } diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index d1f3a962..1cfacf9d 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -13,7 +13,7 @@ #include "../Scene/Entities/Components/LuaScriptComponent.h" #include #include - +#include "../Scene/Entities/Components/WrenScriptComponent.h" Ref Scene::New() { return CreateRef(); @@ -44,6 +44,8 @@ bool Scene::SetName(std::string& newName) void Scene::OnInit() { + ScriptingEngine::Init(); + // Create physic world. auto view = m_Registry.view(); for (auto e : view) @@ -98,10 +100,19 @@ void Scene::OnInit() // Instanciate scripts. { - m_Registry.view().each([=](auto entity, auto& nsc) + auto entities = m_Registry.view(); + for (auto& e : entities) { + WrenScriptComponent& wren = entities.get(e); + if (wren.Script != "" && wren.Class != "") + wren.WrenScript = CreateRef(wren.Script, wren.Class, true); - }); + if (wren.WrenScript != nullptr) + { + wren.WrenScript->SetScriptableEntityID((int)e); + wren.WrenScript->CallInit(); + } + } } } @@ -110,12 +121,21 @@ void Scene::OnExit() PhysicsManager::Get()->Reset(); // destroy scripts. + auto entities = m_Registry.view(); + for (auto& e : entities) { - m_Registry.view().each([=](auto entity, auto& nsc) + WrenScriptComponent& wren = entities.get(e); + + if (wren.WrenScript != nullptr) { - nsc.Instance->OnDestroy(); - }); + wren.WrenScript->CallExit(); + + + } + } + + ScriptingEngine::Close(); } // update entities and some components. @@ -129,6 +149,16 @@ void Scene::Update(Timestep ts) }); } + // destroy scripts. + auto entities = m_Registry.view(); + for (auto& e : entities) + { + WrenScriptComponent& wren = entities.get(e); + + if (wren.WrenScript != nullptr) + wren.WrenScript->CallUpdate(ts); + } + // Update rigidbodies PhysicsManager::Get()->Step(ts); @@ -618,12 +648,14 @@ bool Scene::SaveAs(const std::string& path) return true; } + void Scene::ReloadInterfaces() { for (auto& i : m_Interfaces) i->Reload(); } + void Scene::AddInterface(Ref interface) { this->m_Interfaces.push_back(interface); @@ -643,7 +675,6 @@ json Scene::Serialize() } - bool Scene::Deserialize(const std::string& str) { if (str == "") @@ -675,5 +706,6 @@ bool Scene::Deserialize(const std::string& str) } } } + return true; } diff --git a/Nuake/src/Scripting/Modules/MathModule.h b/Nuake/src/Scripting/Modules/MathModule.h index f4eff0f1..2cd0d862 100644 --- a/Nuake/src/Scripting/Modules/MathModule.h +++ b/Nuake/src/Scripting/Modules/MathModule.h @@ -27,9 +27,9 @@ namespace ScriptAPI static void Sqrt(WrenVM* vm) { - float x = wrenGetSlotDouble(vm, 0); - float y = wrenGetSlotDouble(vm, 0); - float z = wrenGetSlotDouble(vm, 0); + float x = wrenGetSlotDouble(vm, 1); + float y = wrenGetSlotDouble(vm, 2); + float z = wrenGetSlotDouble(vm, 3); float result = glm::sqrt((x * x) + (y * y) + (z * z)); wrenSetSlotDouble(vm, 0, result); } diff --git a/Nuake/src/Scripting/Modules/SceneModule.h b/Nuake/src/Scripting/Modules/SceneModule.h index a2352946..2832f3d7 100644 --- a/Nuake/src/Scripting/Modules/SceneModule.h +++ b/Nuake/src/Scripting/Modules/SceneModule.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace ScriptAPI { @@ -30,6 +31,10 @@ namespace ScriptAPI RegisterMethod("EntityHasComponent(_,_)", (void*)EntityHasComponent); RegisterMethod("SetLightIntensity_(_,_)", (void*)SetLightIntensity); RegisterMethod("GetLightIntensity_(_)", (void*)GetLightIntensity); + RegisterMethod("SetCameraDirection_(_,_,_,_)", (void*)SetCameraDirection); + RegisterMethod("GetCameraDirection_(_)", (void*)GetCameraDirection); + RegisterMethod("GetCameraRight_(_)", (void*)GetCameraRight); + RegisterMethod("MoveAndSlide_(_,_,_,_)", (void*)MoveAndSlide); } static void GetEntity(WrenVM* vm) @@ -99,7 +104,73 @@ namespace ScriptAPI static void SetCameraDirection(WrenVM* vm) { + int handle = wrenGetSlotDouble(vm, 1); + float x = wrenGetSlotDouble(vm, 2); + float y = wrenGetSlotDouble(vm, 3); + float z = wrenGetSlotDouble(vm, 4); + Entity ent = Entity((entt::entity)handle, Engine::GetCurrentScene().get()); + auto& cam = ent.GetComponent(); + cam.CameraInstance->SetDirection(Vector3(x, y, z)); } + + static void GetCameraDirection(WrenVM* vm) + { + int handle = wrenGetSlotDouble(vm, 1); + Entity ent = Entity((entt::entity)handle, Engine::GetCurrentScene().get()); + + auto& cam = ent.GetComponent(); + + Vector3 dir = cam.CameraInstance->GetDirection(); + + wrenEnsureSlots(vm, 4); + + // set the slots + // Fill the list + wrenSetSlotNewList(vm, 0); + wrenSetSlotDouble(vm, 1, dir.x); + wrenSetSlotDouble(vm, 2, dir.y); + wrenSetSlotDouble(vm, 3, dir.z); + + wrenInsertInList(vm, 0, -1, 1); + wrenInsertInList(vm, 0, -1, 2); + wrenInsertInList(vm, 0, -1, 3); + } + + static void GetCameraRight(WrenVM* vm) + { + int handle = wrenGetSlotDouble(vm, 1); + Entity ent = Entity((entt::entity)handle, Engine::GetCurrentScene().get()); + + auto& cam = ent.GetComponent(); + + Vector3 right = cam.CameraInstance->cameraRight; + + // set the slots + wrenSetSlotDouble(vm, 1, right.x); + wrenSetSlotDouble(vm, 2, right.y); + wrenSetSlotDouble(vm, 3, right.z); + + // Fill the list + wrenSetSlotNewList(vm, 0); + wrenInsertInList(vm, 0, 0, 1); + wrenInsertInList(vm, 0, 1, 2); + wrenInsertInList(vm, 0, 2, 3); + } + + + + static void MoveAndSlide(WrenVM* vm) + { + int handle = wrenGetSlotDouble(vm, 1); + float x = wrenGetSlotDouble(vm, 2); + float y = wrenGetSlotDouble(vm, 3); + float z = wrenGetSlotDouble(vm, 4); + + Entity ent = Entity((entt::entity)handle, Engine::GetCurrentScene().get()); + auto& characterController = ent.GetComponent(); + characterController.CharacterController->MoveAndSlide(Vector3(x, y, z)); + } + }; } \ No newline at end of file diff --git a/Nuake/src/Scripting/ScriptingEngine.cpp b/Nuake/src/Scripting/ScriptingEngine.cpp index 2b38247c..bac7d86d 100644 --- a/Nuake/src/Scripting/ScriptingEngine.cpp +++ b/Nuake/src/Scripting/ScriptingEngine.cpp @@ -40,11 +40,25 @@ void writeFn(WrenVM* vm, const char* text) { printf("%s", text); } +bool hasEnding(std::string const& fullString, std::string const& ending) { + if (fullString.length() >= ending.length()) { + return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending)); + } + else { + return false; + } +} WrenLoadModuleResult myLoadModule(WrenVM* vm, const char* name) { WrenLoadModuleResult result = { 0 }; - std::string str = FileSystem::ReadFile("resources/" + std::string(name) + ".wren", true); + + std::string path = "resources/" + std::string(name); + if(!hasEnding(path, ".wren")) + path += ".wren"; + + std::string str = FileSystem::ReadFile(path, true); char* c = strcpy(new char[str.length() + 1], str.c_str()); + result.source = c; return result; } diff --git a/Nuake/src/Scripting/WrenScript.cpp b/Nuake/src/Scripting/WrenScript.cpp index 27200976..1ddcf480 100644 --- a/Nuake/src/Scripting/WrenScript.cpp +++ b/Nuake/src/Scripting/WrenScript.cpp @@ -1,20 +1,36 @@ #include "WrenScript.h" #include "../Core/FileSystem.h" #include -WrenScript::WrenScript(const std::string& path, const std::string& mod) -{ +WrenScript::WrenScript(const std::string& path, const std::string& mod, bool isEntity) +{ WrenVM* vm = ScriptingEngine::GetWrenVM(); - + // Import statement + std::string source = "import \"" + path + "\" for " + mod; + + // Import file as module + wrenInterpret(vm, "main", source.c_str()); + + // Get handle to class wrenEnsureSlots(vm, 1); wrenGetVariable(vm, "main", mod.c_str(), 0); + WrenHandle* classHandle = wrenGetSlotHandle(vm, 0); + // Call the constructor + WrenHandle* constructHandle = wrenMakeCallHandle(vm, "new()"); + wrenCall(vm, constructHandle); + + // Retreive value of constructor this->m_Instance = wrenGetSlotHandle(vm, 0); + // Create handles to the instance methods. this->m_OnInitHandle = wrenMakeCallHandle(vm, "init()"); this->m_OnUpdateHandle = wrenMakeCallHandle(vm, "update(_)"); this->m_OnExitHandle = wrenMakeCallHandle(vm, "exit()"); + + if (isEntity) + this->m_SetEntityIDHandle = wrenMakeCallHandle(vm, "SetEntityId(_)"); } void WrenScript::CallInit() @@ -26,7 +42,6 @@ void WrenScript::CallInit() void WrenScript::CallUpdate(float timestep) { - WrenVM* vm = ScriptingEngine::GetWrenVM(); wrenEnsureSlots(vm, 2); wrenSetSlotHandle(vm, 0, this->m_Instance); @@ -37,6 +52,7 @@ void WrenScript::CallUpdate(float timestep) void WrenScript::CallExit() { WrenVM* vm = ScriptingEngine::GetWrenVM(); + wrenEnsureSlots(vm, 1); wrenSetSlotHandle(vm, 0, this->m_Instance); WrenInterpretResult result = wrenCall(vm, this->m_OnExitHandle); } @@ -56,7 +72,16 @@ void WrenScript::CallMethod(const std::string& signature) // Not found. maybe try to register it? if (methods.find(signature) == methods.end()) return; + wrenSetSlotHandle(vm, 0, this->m_Instance); WrenHandle* handle = methods[signature]; WrenInterpretResult result = wrenCall(vm, handle); } + +void WrenScript::SetScriptableEntityID(int id) +{ + WrenVM* vm = ScriptingEngine::GetWrenVM(); + wrenSetSlotHandle(vm, 0, this->m_Instance); + wrenSetSlotDouble(vm, 1, id); + WrenInterpretResult result = wrenCall(vm, this->m_SetEntityIDHandle); +} diff --git a/Nuake/src/Scripting/WrenScript.h b/Nuake/src/Scripting/WrenScript.h index 4e5a5987..2ddad9b3 100644 --- a/Nuake/src/Scripting/WrenScript.h +++ b/Nuake/src/Scripting/WrenScript.h @@ -12,8 +12,9 @@ public: WrenHandle* m_OnInitHandle; WrenHandle* m_OnUpdateHandle; WrenHandle* m_OnExitHandle; + WrenHandle* m_SetEntityIDHandle; - WrenScript(const std::string& path, const std::string& mod); + WrenScript(const std::string& path, const std::string& mod, bool isEntity = false); void CallInit(); void CallUpdate(float timestep); @@ -21,4 +22,6 @@ public: void RegisterMethod(const std::string& signature); void CallMethod(const std::string& signature); + + void SetScriptableEntityID(int id); }; \ No newline at end of file diff --git a/Nuake/src/UI/InterfaceParser.cpp b/Nuake/src/UI/InterfaceParser.cpp index 35fa8105..c2ed807f 100644 --- a/Nuake/src/UI/InterfaceParser.cpp +++ b/Nuake/src/UI/InterfaceParser.cpp @@ -1,5 +1,5 @@ #include "InterfaceParser.h" - +#include "Styling/Stylesheet.h" Ref InterfaceParser::Root = CreateRef(); void InterfaceParser::Iterate(const pugi::xml_node& xml_node, Ref node, int depth) @@ -271,6 +271,11 @@ Ref InterfaceParser::CreateCanvas(const pugi::xml_node& xml_node) std::string module = s[1]; node->Script = ScriptingEngine::RegisterScript(path, module); } + if (name == "stylesheet") + { + std::string path = a.value(); + node->StyleSheet = UI::StyleSheet::New(path); + } } return node; diff --git a/Nuake/src/UI/Nodes/Canvas.h b/Nuake/src/UI/Nodes/Canvas.h index ecf43074..9e57c690 100644 --- a/Nuake/src/UI/Nodes/Canvas.h +++ b/Nuake/src/UI/Nodes/Canvas.h @@ -3,6 +3,8 @@ #include "../Core/Core.h" #include "../Scripting/WrenScript.h" #include +#include "../Styling/Stylesheet.h" + // Base container for UI. class Canvas : public Node { @@ -11,5 +13,7 @@ private: public: Ref Script; + Ref StyleSheet; + Canvas(); }; \ No newline at end of file diff --git a/Nuake/src/UI/Styling/Stylesheet.h b/Nuake/src/UI/Styling/Stylesheet.h index 5f6767f0..eee6f17b 100644 --- a/Nuake/src/UI/Styling/Stylesheet.h +++ b/Nuake/src/UI/Styling/Stylesheet.h @@ -1,18 +1,14 @@ #pragma once +#include "katana-parser/katana.h" #include "../Core/FileSystem.h" #include "../Core/Logger.h" #include "../Core/Core.h" -#include "Style.h" - -#include "katana-parser/katana.h" -#include -#include +#include "../Nodes/Node.h" #include #include -#include -#include - +#include +#include namespace UI { class StyleSheet @@ -24,7 +20,20 @@ namespace UI public: std::string Path; static Ref New(const std::string& path); + std::vector Split(std::string const& str, const char delim) + { + std::vector result; + size_t start; + size_t end = 0; + while ((start = str.find_first_not_of(delim, end)) != std::string::npos) + { + end = str.find(delim, start); + result.push_back(str.substr(start, end - start)); + } + + return result; + } void AddStyleGroup(std::string selector, Ref group) { Styles[selector] = group; @@ -90,7 +99,7 @@ namespace UI std::smatch match_value; Layout::LayoutVec4 result; - std::vector splits = InterfaceParser::split(value, ' '); + std::vector splits = Split(value, ' '); int idx = 0; for (auto& s : splits) { diff --git a/Nuake/src/UI/UserInterface.cpp b/Nuake/src/UI/UserInterface.cpp index 7ae18768..44e5ed97 100644 --- a/Nuake/src/UI/UserInterface.cpp +++ b/Nuake/src/UI/UserInterface.cpp @@ -14,11 +14,8 @@ namespace UI m_Name = name; font = FontLoader::LoadFont("resources/Fonts/RobotoMono-Regular.ttf"); - - m_Stylesheet = StyleSheet::New("/Interface\\Testing.css"); - Root = InterfaceParser::Parse("resources/Interface/Testing.interface"); - + if (!Root) { Logger::Log("Failed to generate interface structure"); @@ -38,7 +35,6 @@ namespace UI void UserInterface::Reload() { - m_Stylesheet = StyleSheet::New("/Interface\\Testing.css"); Root = InterfaceParser::Parse("resources/Interface/Testing.interface"); if (!Root) { @@ -67,8 +63,8 @@ namespace UI Root->YogaNode = yoga_root; for (auto& g : Root->GetGroups()) - if (m_Stylesheet->HasStyleGroup(g)) - Root->ApplyStyle(m_Stylesheet->GetStyleGroup(g)); + if (Root->StyleSheet->HasStyleGroup(g)) + Root->ApplyStyle(Root->StyleSheet->GetStyleGroup(g)); Root->SetYogaLayout(); CreateYogaLayoutRecursive(Root, yoga_root); } @@ -85,8 +81,8 @@ namespace UI n->YogaNode = newYogaNode; for (auto& g : n->GetGroups()) - if (m_Stylesheet->HasStyleGroup(g)) - n->ApplyStyle(m_Stylesheet->GetStyleGroup(g)); + if (Root->StyleSheet->HasStyleGroup(g)) + n->ApplyStyle(Root->StyleSheet->GetStyleGroup(g)); n->SetYogaLayout(); YGNodeInsertChild(yoga_node, newYogaNode, index); diff --git a/Nuake/src/UI/UserInterface.h b/Nuake/src/UI/UserInterface.h index f01160f6..e0851f12 100644 --- a/Nuake/src/UI/UserInterface.h +++ b/Nuake/src/UI/UserInterface.h @@ -16,7 +16,6 @@ namespace UI Ref m_Framebuffer; // Texture of the interface. std::string m_Name; Ref Root; - Ref m_Stylesheet; YGConfigRef yoga_config; YGNodeRef yoga_root; public: diff --git a/Nuake/src/Window.cpp b/Nuake/src/Window.cpp index 11aeb4e7..510aee47 100644 --- a/Nuake/src/Window.cpp +++ b/Nuake/src/Window.cpp @@ -232,6 +232,8 @@ void Window::Draw() Ref cam = m_Scene->GetCurrentCamera(); if (!cam) return; + Vector2 size = m_Framebuffer->GetSize(); + cam->AspectRatio = size.x / size.y; Renderer::BeginDraw(cam); {