feat: added toast support to scripting
Some checks failed
CI / build-and-test (push) Has been cancelled

This commit is contained in:
2025-11-14 15:04:00 +13:00
parent 34304fcb2c
commit f352b432d9
11 changed files with 386 additions and 64 deletions

View File

@@ -9,8 +9,8 @@ Size=400,400
Collapsed=0 Collapsed=0
[Window][Game Window] [Window][Game Window]
Pos=8,27 Pos=8,25
Size=1264,685 Size=1264,581
Collapsed=0 Collapsed=0
DockId=0x00000001,0 DockId=0x00000001,0
@@ -20,8 +20,18 @@ Size=1264,104
Collapsed=0 Collapsed=0
DockId=0x00000002,0 DockId=0x00000002,0
[Window][##TOAST0]
Pos=1062,643
Size=198,57
Collapsed=0
[Window][##TOAST1]
Pos=1062,576
Size=198,57
Collapsed=0
[Docking][Data] [Docking][Data]
DockSpace ID=0x9076BACA Window=0x34F970D7 Pos=8,27 Size=1264,685 Split=Y Selected=0x27A02DAA DockSpace ID=0x9076BACA Window=0x34F970D7 Pos=8,25 Size=1264,687 Split=Y Selected=0x27A02DAA
DockNode ID=0x00000001 Parent=0x9076BACA SizeRef=1264,579 CentralNode=1 Selected=0x27A02DAA DockNode ID=0x00000001 Parent=0x9076BACA SizeRef=1264,579 CentralNode=1 Selected=0x27A02DAA
DockNode ID=0x00000002 Parent=0x9076BACA SizeRef=1264,104 Selected=0xBEDDA0C1 DockNode ID=0x00000002 Parent=0x9076BACA SizeRef=1264,104 Selected=0xBEDDA0C1

View File

@@ -13,6 +13,9 @@ public:
void Run(); void Run();
void Shutdown(); void Shutdown();
bool IsEditorEnabled() const { return enableEditor; }
bool HasScriptCompilationError() const { return scriptCompilationError; }
private: private:
ScriptEngine scriptEngine; ScriptEngine scriptEngine;
HotReload* hotReload; HotReload* hotReload;
@@ -20,7 +23,7 @@ private:
FILE* logFile; FILE* logFile;
GuiManager guiManager; GuiManager guiManager;
bool enableEditor; bool enableEditor;
RenderTexture2D renderTexture; // Declare renderTexture for Raylib rendering RenderTexture2D renderTexture; // renderTexture for Raylib rendering
static const int WINDOW_WIDTH = 1280; static const int WINDOW_WIDTH = 1280;
static const int WINDOW_HEIGHT = 720; static const int WINDOW_HEIGHT = 720;

View File

@@ -5,18 +5,23 @@
#include "gui/fa-solid-900.h" #include "gui/fa-solid-900.h"
#include "gui/ImGuiNotify.hpp" #include "gui/ImGuiNotify.hpp"
class Application;
class GuiManager { class GuiManager {
public: public:
GuiManager(); GuiManager();
~GuiManager(); ~GuiManager();
void Initialize(); void Initialize(Application* application);
void Render(RenderTexture2D& renderTexture); void Render(RenderTexture2D& renderTexture);
void Shutdown(); void Shutdown();
private: private:
void SetupDockspace(RenderTexture2D& renderTexture); void SetupDockspace(RenderTexture2D& renderTexture);
void RenderNotifications(); void RenderNotifications();
void RenderErrorBanner();
void SetTheme();
bool showLogWindow = true; bool showLogWindow = true;
Application *app;
}; };

57
include/gui/Toast.h Normal file
View File

@@ -0,0 +1,57 @@
#pragma once
#include "gui/ImGuiNotify.hpp"
#include <string>
#include <string_view>
#include <vector>
#include <cstdio>
#include <utility>
class Toast
{
public:
template <typename... Args>
static void Info(std::string_view fmt, Args&&... args)
{
ImGui::InsertNotification({ImGuiToastType::Info, 3000, Format(fmt, std::forward<Args>(args)...).c_str()});
}
template <typename... Args>
static void Warning(std::string_view fmt, Args&&... args)
{
ImGui::InsertNotification({ImGuiToastType::Warning, 4000, Format(fmt, std::forward<Args>(args)...).c_str()});
}
template <typename... Args>
static void Error(std::string_view fmt, Args&&... args)
{
ImGui::InsertNotification({ImGuiToastType::Error, 5000, Format(fmt, std::forward<Args>(args)...).c_str()});
}
template <typename... Args>
static void Success(std::string_view fmt, Args&&... args)
{
ImGui::InsertNotification({ImGuiToastType::Success, 2500, Format(fmt, std::forward<Args>(args)...).c_str()});
}
private:
template <typename... Args>
static std::string Format(std::string_view fmt, Args&&... args)
{
if constexpr (sizeof...(Args) == 0)
{
return std::string(fmt);
}
else
{
std::string format(fmt);
int size = std::snprintf(nullptr, 0, format.c_str(), std::forward<Args>(args)...) + 1;
if (size <= 0)
return std::string(fmt);
std::vector<char> buffer(static_cast<size_t>(size));
std::snprintf(buffer.data(), static_cast<size_t>(size), format.c_str(), std::forward<Args>(args)...);
return std::string(buffer.data());
}
}
};

View File

@@ -1,11 +1,15 @@
typedef void string; typedef void string;
void Print(const string &in); void Print(const string&in);
void Log(int level, const string &in); void Log(int level, const string&in);
void DrawText(const string &in, int x, int y, int fontSize, int color); void DrawText(const string&in, int x, int y, int fontSize, int color);
int LOG_TRACE; int LOG_TRACE;
int LOG_DEBUG; int LOG_DEBUG;
int LOG_INFO; int LOG_INFO;
int LOG_WARN; int LOG_WARNING;
int LOG_ERROR; int LOG_ERROR;
int LOG_FATAL; int LOG_FATAL;
namespace Toast {
void Info(const string&in);
void Info(const string&in, const ?&in ...);
}

View File

@@ -2,10 +2,11 @@ float x = 50;
float y = 100; float y = 100;
void Update(float dt) { void Update(float dt) {
x += 50 * dt; x += 500 * dt;
if (x > 800) { if (x > 800) {
x = 0; x = 0;
Print("X position reset!"); Print("X position reset!");
Log(LOG_INFO, "Log INFO: reset happened"); Log(LOG_INFO, "Log INFO: reset happened");
Toast::Info("X position has been reset.");
} }
} }

View File

@@ -11,6 +11,7 @@
#include "extras/IconsFontAwesome6.h" #include "extras/IconsFontAwesome6.h"
#include "gui/ImGuiNotify.hpp" #include "gui/ImGuiNotify.hpp"
#include "GuiManager.h" #include "GuiManager.h"
#include "gui/Toast.h"
#ifdef _WIN32 #ifdef _WIN32
// On Windows, fopen_s is already available, so no need to define it. // On Windows, fopen_s is already available, so no need to define it.
@@ -19,7 +20,7 @@
#define fopen_s(pFile, filename, mode) ((*(pFile) = fopen((filename), (mode))) == NULL) #define fopen_s(pFile, filename, mode) ((*(pFile) = fopen((filename), (mode))) == NULL)
#endif #endif
const char *Application::WINDOW_TITLE = "Simian"; const char *Application::WINDOW_TITLE = "Simian";
const char *Application::SCRIPT_FILE = "scripts/test.as"; const char *Application::SCRIPT_FILE = "scripts/game.as";
Application::Application() : hotReload(nullptr), scriptCompilationError(false), logFile(nullptr), renderTexture{} // Initialize renderTexture Application::Application() : hotReload(nullptr), scriptCompilationError(false), logFile(nullptr), renderTexture{} // Initialize renderTexture
{ {
@@ -27,7 +28,7 @@ Application::Application() : hotReload(nullptr), scriptCompilationError(false),
Application::~Application() Application::~Application()
{ {
// Reminder in case the change main.cpp, but we do not want to close the // Reminder in case we change main.cpp, but we do not want to close the
// window more than once // window more than once
// Shutdown(); // Shutdown();
} }
@@ -68,7 +69,7 @@ bool Application::Initialize(int argc, char *argv[])
} }
// Initialize hot reload to watch the scripts directory so any script change // Initialize hot reload to watch the scripts directory so any script change
// (not just the main file) triggers a reload. // triggers a reload.
{ {
std::filesystem::path p(SCRIPT_FILE); std::filesystem::path p(SCRIPT_FILE);
std::string watchPath = p.parent_path().string(); std::string watchPath = p.parent_path().string();
@@ -83,7 +84,7 @@ bool Application::Initialize(int argc, char *argv[])
if (enableEditor) if (enableEditor)
{ {
guiManager.Initialize(); guiManager.Initialize(this);
renderTexture = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT); renderTexture = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT);
} }
@@ -116,6 +117,9 @@ void Application::Update(float deltaTime)
if (!success) if (!success)
{ {
log_warn("Script compilation failed - keeping previous version"); log_warn("Script compilation failed - keeping previous version");
Toast::Warning("Script compilation failed - check console for details.");
} else {
Toast::Success("Script reloaded successfully.");
} }
} }
@@ -144,12 +148,6 @@ void Application::Draw()
BeginTextureMode(renderTexture); BeginTextureMode(renderTexture);
ClearBackground(RAYWHITE); ClearBackground(RAYWHITE);
// Show script error status in top left if there's an error, otherwise show normal message
if (scriptCompilationError)
{
DrawText("SCRIPT ERROR - Check console for details", 10, 10, 16, RED);
}
// Call script Draw function // Call script Draw function
scriptEngine.CallScriptFunction(scriptEngine.GetDrawFunction()); scriptEngine.CallScriptFunction(scriptEngine.GetDrawFunction());

View File

@@ -4,12 +4,15 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
#include "log.h" #include "log.h"
#include "Application.h"
GuiManager::GuiManager() {} GuiManager::GuiManager() {}
GuiManager::~GuiManager() {} GuiManager::~GuiManager() {}
void GuiManager::Initialize() void GuiManager::Initialize(Application *application)
{ {
app = application;
rlImGuiSetup(true); rlImGuiSetup(true);
ImGuiIO &io = ImGui::GetIO(); ImGuiIO &io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
@@ -25,6 +28,7 @@ void GuiManager::Initialize()
iconsConfig.PixelSnapH = true; iconsConfig.PixelSnapH = true;
iconsConfig.GlyphMinAdvanceX = iconFontSize; iconsConfig.GlyphMinAdvanceX = iconFontSize;
io.Fonts->AddFontFromMemoryCompressedTTF(fa_solid_900_compressed_data, fa_solid_900_compressed_size, iconFontSize, &iconsConfig, iconsRanges); io.Fonts->AddFontFromMemoryCompressedTTF(fa_solid_900_compressed_data, fa_solid_900_compressed_size, iconFontSize, &iconsConfig, iconsRanges);
SetTheme();
log_trace("GuiManager::Initialize - Started"); log_trace("GuiManager::Initialize - Started");
} }
@@ -32,6 +36,8 @@ void GuiManager::Render(RenderTexture2D &renderTexture)
{ {
rlImGuiBegin(); rlImGuiBegin();
SetupDockspace(renderTexture); // Pass the renderTexture parameter SetupDockspace(renderTexture); // Pass the renderTexture parameter
RenderErrorBanner();
RenderNotifications(); RenderNotifications();
rlImGuiEnd(); rlImGuiEnd();
@@ -124,6 +130,21 @@ void GuiManager::SetupDockspace(RenderTexture2D &renderTexture)
ImGui::End(); ImGui::End();
} }
void GuiManager::RenderErrorBanner()
{
if (!app || !app->HasScriptCompilationError())
return;
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f));
ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x, 0.0f));
ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings;
ImGui::Begin("PersistentBanner", nullptr, flags);
ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), ICON_FA_TRIANGLE_EXCLAMATION " Script Compilation Error - running last working version");
ImGui::End();
}
void GuiManager::RenderNotifications() void GuiManager::RenderNotifications()
{ {
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.f);
@@ -134,4 +155,90 @@ void GuiManager::RenderNotifications()
ImGui::PopStyleVar(2); ImGui::PopStyleVar(2);
ImGui::PopStyleColor(1); ImGui::PopStyleColor(1);
} }
void GuiManager::SetTheme()
{
ImVec4 *colors = ImGui::GetStyle().Colors;
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
colors[ImGuiCol_WindowBg] = ImVec4(0.10f, 0.10f, 0.10f, 1.00f);
colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.19f, 0.19f, 0.19f, 0.92f);
colors[ImGuiCol_Border] = ImVec4(0.19f, 0.19f, 0.19f, 0.29f);
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.24f);
colors[ImGuiCol_FrameBg] = ImVec4(0.05f, 0.05f, 0.05f, 0.54f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.19f, 0.19f, 0.19f, 0.54f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f);
colors[ImGuiCol_TitleBg] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_TitleBgActive] = ImVec4(0.06f, 0.06f, 0.06f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.05f, 0.05f, 0.05f, 0.54f);
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.34f, 0.34f, 0.34f, 0.54f);
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.40f, 0.54f);
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.56f, 0.56f, 0.56f, 0.54f);
colors[ImGuiCol_CheckMark] = ImVec4(0.33f, 0.67f, 0.86f, 1.00f);
colors[ImGuiCol_SliderGrab] = ImVec4(0.34f, 0.34f, 0.34f, 0.54f);
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.56f, 0.56f, 0.56f, 0.54f);
colors[ImGuiCol_Button] = ImVec4(0.05f, 0.05f, 0.05f, 0.54f);
colors[ImGuiCol_ButtonHovered] = ImVec4(0.19f, 0.19f, 0.19f, 0.54f);
colors[ImGuiCol_ButtonActive] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f);
colors[ImGuiCol_Header] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.00f, 0.00f, 0.00f, 0.36f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.20f, 0.22f, 0.23f, 0.33f);
colors[ImGuiCol_Separator] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.29f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.40f, 0.44f, 0.47f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.29f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.40f, 0.44f, 0.47f, 1.00f);
colors[ImGuiCol_Tab] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f);
colors[ImGuiCol_TabHovered] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
colors[ImGuiCol_TabActive] = ImVec4(0.20f, 0.20f, 0.20f, 0.36f);
colors[ImGuiCol_TabUnfocused] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f);
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
// colors[ImGuiCol_DockingPreview] = ImVec4(0.33f, 0.67f, 0.86f, 1.00f);
// colors[ImGuiCol_DockingEmptyBg] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_TableHeaderBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f);
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.00f, 0.00f, 0.00f, 0.52f);
colors[ImGuiCol_TableBorderLight] = ImVec4(0.28f, 0.28f, 0.28f, 0.29f);
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.20f, 0.22f, 0.23f, 1.00f);
colors[ImGuiCol_DragDropTarget] = ImVec4(0.33f, 0.67f, 0.86f, 1.00f);
colors[ImGuiCol_NavHighlight] = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 0.00f, 0.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(1.00f, 0.00f, 0.00f, 0.20f);
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(1.00f, 0.00f, 0.00f, 0.35f);
colors[ImGuiCol_CheckMark] = ImVec4(0.33f, 0.67f, 0.86f, 1.00f);
ImGuiStyle &style = ImGui::GetStyle();
style.WindowPadding = ImVec2(8.00f, 8.00f);
style.FramePadding = ImVec2(5.00f, 2.00f);
style.CellPadding = ImVec2(6.00f, 6.00f);
style.ItemSpacing = ImVec2(6.00f, 6.00f);
style.ItemInnerSpacing = ImVec2(6.00f, 6.00f);
style.TouchExtraPadding = ImVec2(0.00f, 0.00f);
style.IndentSpacing = 25;
style.ScrollbarSize = 15;
style.GrabMinSize = 10;
style.WindowBorderSize = 1;
style.ChildBorderSize = 1;
style.PopupBorderSize = 1;
style.FrameBorderSize = 1;
style.TabBorderSize = 1;
style.WindowRounding = 7;
style.ChildRounding = 4;
style.FrameRounding = 3;
style.PopupRounding = 4;
style.ScrollbarRounding = 9;
style.GrabRounding = 3;
style.LogSliderDeadzone = 4;
style.TabRounding = 4;
}

View File

@@ -3,6 +3,7 @@
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
#include "log/log.h" #include "log/log.h"
#include "gui/Toast.h"
// Expose log level constants to AngelScript // Expose log level constants to AngelScript
static int AS_LOG_TRACE = 1; static int AS_LOG_TRACE = 1;
@@ -12,76 +13,195 @@ static int AS_LOG_WARNING = 4;
static int AS_LOG_ERROR = 5; static int AS_LOG_ERROR = 5;
static int AS_LOG_FATAL = 6; static int AS_LOG_FATAL = 6;
void ScriptBindings::RegisterAll(asIScriptEngine* engine) { void ToastInfo_Generic(asIScriptGeneric* gen)
{
// First argument is the format string
std::string fmt = *reinterpret_cast<std::string*>(gen->GetArgAddress(0));
// Handle variadic arguments
int argCount = gen->GetArgCount();
std::vector<std::string> args;
for (int i = 1; i < argCount; ++i)
{
// For simplicity, assume all extra args are strings
std::string arg = *reinterpret_cast<std::string*>(gen->GetArgAddress(i));
args.push_back(arg);
}
// Simple formatting: replace %s sequentially
std::string result = fmt;
size_t pos = 0;
for (const auto& a : args)
{
pos = result.find("%s", pos);
if (pos == std::string::npos) break;
result.replace(pos, 2, a);
pos += a.size();
}
Toast::Info(result);
}
void ToastWarning_Generic(asIScriptGeneric* gen)
{
std::string fmt = *reinterpret_cast<std::string*>(gen->GetArgAddress(0));
int argCount = gen->GetArgCount();
std::vector<std::string> args;
for (int i = 1; i < argCount; ++i)
args.push_back(*reinterpret_cast<std::string*>(gen->GetArgAddress(i)));
std::string result = fmt;
size_t pos = 0;
for (const auto& a : args)
{
pos = result.find("%s", pos);
if (pos == std::string::npos) break;
result.replace(pos, 2, a);
pos += a.size();
}
Toast::Warning(result);
}
void ToastError_Generic(asIScriptGeneric* gen)
{
std::string fmt = *reinterpret_cast<std::string*>(gen->GetArgAddress(0));
int argCount = gen->GetArgCount();
std::vector<std::string> args;
for (int i = 1; i < argCount; ++i)
args.push_back(*reinterpret_cast<std::string*>(gen->GetArgAddress(i)));
std::string result = fmt;
size_t pos = 0;
for (const auto& a : args)
{
pos = result.find("%s", pos);
if (pos == std::string::npos) break;
result.replace(pos, 2, a);
pos += a.size();
}
Toast::Error(result);
}
void ToastSuccess_Generic(asIScriptGeneric* gen)
{
std::string fmt = *reinterpret_cast<std::string*>(gen->GetArgAddress(0));
int argCount = gen->GetArgCount();
std::vector<std::string> args;
for (int i = 1; i < argCount; ++i)
args.push_back(*reinterpret_cast<std::string*>(gen->GetArgAddress(i)));
std::string result = fmt;
size_t pos = 0;
for (const auto& a : args)
{
pos = result.find("%s", pos);
if (pos == std::string::npos) break;
result.replace(pos, 2, a);
pos += a.size();
}
Toast::Success(result);
}
void ScriptBindings::RegisterAll(asIScriptEngine *engine)
{
// Register Print function with generic calling convention to access context // Register Print function with generic calling convention to access context
int r = engine->RegisterGlobalFunction("void Print(const string &in)", int r = engine->RegisterGlobalFunction("void Print(const string &in)",
asFUNCTION(Print), asCALL_GENERIC); asFUNCTION(Print), asCALL_GENERIC);
assert(r >= 0); assert(r >= 0);
// Register log level constants so scripts can refer to LOG_INFO, LOG_ERROR, etc. // Register log level constants so scripts can refer to LOG_INFO, LOG_ERROR, etc.
r = engine->RegisterGlobalProperty("int LOG_TRACE", (void*)&AS_LOG_TRACE); r = engine->RegisterGlobalProperty("int LOG_TRACE", (void *)&AS_LOG_TRACE);
assert(r >= 0); assert(r >= 0);
r = engine->RegisterGlobalProperty("int LOG_DEBUG", (void*)&AS_LOG_DEBUG); r = engine->RegisterGlobalProperty("int LOG_DEBUG", (void *)&AS_LOG_DEBUG);
assert(r >= 0); assert(r >= 0);
r = engine->RegisterGlobalProperty("int LOG_INFO", (void*)&AS_LOG_INFO); r = engine->RegisterGlobalProperty("int LOG_INFO", (void *)&AS_LOG_INFO);
assert(r >= 0); assert(r >= 0);
r = engine->RegisterGlobalProperty("int LOG_WARNING", (void*)&AS_LOG_WARNING); r = engine->RegisterGlobalProperty("int LOG_WARNING", (void *)&AS_LOG_WARNING);
assert(r >= 0); assert(r >= 0);
r = engine->RegisterGlobalProperty("int LOG_ERROR", (void*)&AS_LOG_ERROR); r = engine->RegisterGlobalProperty("int LOG_ERROR", (void *)&AS_LOG_ERROR);
assert(r >= 0); assert(r >= 0);
r = engine->RegisterGlobalProperty("int LOG_FATAL", (void*)&AS_LOG_FATAL); r = engine->RegisterGlobalProperty("int LOG_FATAL", (void *)&AS_LOG_FATAL);
assert(r >= 0); assert(r >= 0);
// Register Log(level, message) to allow scripts to log at different levels // Register Log(level, message) to allow scripts to log at different levels
r = engine->RegisterGlobalFunction("void Log(int, const string &in)", r = engine->RegisterGlobalFunction("void Log(int, const string &in)",
asFUNCTION(Log), asCALL_GENERIC); asFUNCTION(Log), asCALL_GENERIC);
assert(r >= 0); assert(r >= 0);
// Toast functions
engine->SetDefaultNamespace("Toast");
r = engine->RegisterGlobalFunction("void Info(const string &in, const ?&in ...)",
asFUNCTION(ToastInfo_Generic), asCALL_GENERIC);
assert(r >= 0);
r = engine->RegisterGlobalFunction("void Info(const string &in)",
asFUNCTION(ToastInfo_Generic), asCALL_GENERIC);
assert(r >= 0);
engine->SetDefaultNamespace("");
// Register DrawText function // Register DrawText function
r = engine->RegisterGlobalFunction("void DrawText(const string &in, int, int, int, uint)", r = engine->RegisterGlobalFunction("void DrawText(const string &in, int, int, int, uint)",
asFUNCTION(AS_DrawText), asCALL_CDECL); asFUNCTION(AS_DrawText), asCALL_CDECL);
assert(r >= 0); assert(r >= 0);
} }
void ScriptBindings::Print(asIScriptGeneric* gen) { void ScriptBindings::Print(asIScriptGeneric *gen)
{
// Get the message parameter // Get the message parameter
std::string* msg = static_cast<std::string*>(gen->GetArgObject(0)); std::string *msg = static_cast<std::string *>(gen->GetArgObject(0));
// Get the active context to retrieve script file and line number // Get the active context to retrieve script file and line number
asIScriptContext* ctx = asGetActiveContext(); asIScriptContext *ctx = asGetActiveContext();
if (ctx) { if (ctx)
const char* section = nullptr; {
const char *section = nullptr;
int line = 0; int line = 0;
// Get the current line number and script section // Get the current line number and script section
line = ctx->GetLineNumber(0, nullptr, &section); line = ctx->GetLineNumber(0, nullptr, &section);
if (section && line > 0) { if (section && line > 0)
{
// Log with script file and line number // Log with script file and line number
log_log(LOG_INFO, section, line, "%s", msg->c_str()); log_log(LOG_INFO, section, line, "%s", msg->c_str());
} else { }
else
{
// Fallback if we can't get the info // Fallback if we can't get the info
log_info("%s", msg->c_str()); log_info("%s", msg->c_str());
} }
} else { }
else
{
// No context available, just log normally // No context available, just log normally
log_info("%s", msg->c_str()); log_info("%s", msg->c_str());
} }
} }
void ScriptBindings::Log(asIScriptGeneric* gen) { void ScriptBindings::Log(asIScriptGeneric *gen)
{
// arg0: int level, arg1: string message // arg0: int level, arg1: string message
int level = gen->GetArgDWord(0); int level = gen->GetArgDWord(0);
std::string* msg = static_cast<std::string*>(gen->GetArgObject(1)); std::string *msg = static_cast<std::string *>(gen->GetArgObject(1));
// Obtain script context to fetch file/line // Obtain script context to fetch file/line
asIScriptContext* ctx = asGetActiveContext(); asIScriptContext *ctx = asGetActiveContext();
if (ctx) { if (ctx)
const char* section = nullptr; {
const char *section = nullptr;
int line = 0; int line = 0;
line = ctx->GetLineNumber(0, nullptr, &section); line = ctx->GetLineNumber(0, nullptr, &section);
if (section && line > 0) { if (section && line > 0)
{
// Use the library's log_log to preserve filename/line info // Use the library's log_log to preserve filename/line info
log_log(level, section, line, "%s", msg ? msg->c_str() : ""); log_log(level, section, line, "%s", msg ? msg->c_str() : "");
return; return;
@@ -89,20 +209,32 @@ void ScriptBindings::Log(asIScriptGeneric* gen) {
} }
// Fallback: log without script location // Fallback: log without script location
switch (level) { switch (level)
case LOG_TRACE: log_trace("%s", msg ? msg->c_str() : ""); break; {
case LOG_DEBUG: log_debug("%s", msg ? msg->c_str() : ""); break; case LOG_TRACE:
case LOG_WARNING: log_warn("%s", msg ? msg->c_str() : ""); break; log_trace("%s", msg ? msg->c_str() : "");
case LOG_ERROR: log_error("%s", msg ? msg->c_str() : ""); break; break;
case LOG_FATAL: log_fatal("%s", msg ? msg->c_str() : ""); break; case LOG_DEBUG:
case LOG_INFO: log_debug("%s", msg ? msg->c_str() : "");
default: break;
log_info("%s", msg ? msg->c_str() : ""); case LOG_WARNING:
break; log_warn("%s", msg ? msg->c_str() : "");
break;
case LOG_ERROR:
log_error("%s", msg ? msg->c_str() : "");
break;
case LOG_FATAL:
log_fatal("%s", msg ? msg->c_str() : "");
break;
case LOG_INFO:
default:
log_info("%s", msg ? msg->c_str() : "");
break;
} }
} }
Color ColorFromUInt(unsigned int c) { Color ColorFromUInt(unsigned int c)
{
Color col; Color col;
col.r = (c >> 24) & 0xFF; col.r = (c >> 24) & 0xFF;
col.g = (c >> 16) & 0xFF; col.g = (c >> 16) & 0xFF;
@@ -111,6 +243,7 @@ Color ColorFromUInt(unsigned int c) {
return col; return col;
} }
void ScriptBindings::AS_DrawText(const std::string &text, int x, int y, int fontSize, unsigned int color) { void ScriptBindings::AS_DrawText(const std::string &text, int x, int y, int fontSize, unsigned int color)
{
DrawText(text.c_str(), x, y, fontSize, ColorFromUInt(color)); DrawText(text.c_str(), x, y, fontSize, ColorFromUInt(color));
} }

View File

@@ -17,6 +17,9 @@ target_include_directories(unit_tests PRIVATE
${CMAKE_SOURCE_DIR}/external/angelscript/sdk/add_on/scriptstdstring ${CMAKE_SOURCE_DIR}/external/angelscript/sdk/add_on/scriptstdstring
${CMAKE_SOURCE_DIR}/external/angelscript/sdk/add_on/scriptbuilder ${CMAKE_SOURCE_DIR}/external/angelscript/sdk/add_on/scriptbuilder
${CMAKE_SOURCE_DIR}/external/raylib/src ${CMAKE_SOURCE_DIR}/external/raylib/src
${CMAKE_SOURCE_DIR}/external/imgui
${CMAKE_SOURCE_DIR}/external/rlImGui
) )
# Link AngelScript and its add-ons needed by ScriptEngine # Link AngelScript and its add-ons needed by ScriptEngine
@@ -25,6 +28,7 @@ target_link_libraries(unit_tests PRIVATE
scriptstdstring scriptstdstring
scriptbuilder scriptbuilder
raylib raylib
imgui
) )
add_test(NAME unit_tests COMMAND unit_tests) add_test(NAME unit_tests COMMAND unit_tests)