Porting all Pannels to Angel Script to make a super modulable Game Enginegit add .!

This commit is contained in:
Arnau Alier Torres 2025-04-28 03:13:39 +02:00
parent b1215c2563
commit af877c42ed
29 changed files with 863 additions and 87 deletions

View File

@ -7,6 +7,7 @@
#define DEER_SCENE_PATH "scenes"
#define DEER_SCRIPT_PATH "scripts"
#define DEER_UI_SCRIPT_PATH "ui_scripts"
#define DEER_SHADER_PATH "shaders"
#define DEER_VOXEL_PATH "voxels"
#define DEER_VOXEL_DATA_PATH "voxels/data"
@ -20,8 +21,19 @@
#define DEER_NULL_PATH "null"
namespace Deer {
struct DirectoryData {
std::vector<Path> subDirs;
std::vector<Path> elements;
};
// Namespace to manage memory interactions
namespace DataStore {
// Clears the cache of dir data
void clearCache();
// Rerturns a directory data with the elements relative to the id
const DirectoryData& getDirData(const Path& id, const Path& subDir, const char* extension);
void createFolder(const Path& path);
void saveFile(const Path&, uint8_t* data, uint32_t size);

View File

@ -26,11 +26,15 @@ namespace Deer {
static inline Ref<spdlog::logger>& getScriptLogger() {
return scriptLogger;
}
static inline Ref<spdlog::logger>& getUiEngineLogger() {
return uiEngineLogger;
}
private:
static Ref<spdlog::logger> coreLogger;
static Ref<spdlog::logger> clientLogger;
static Ref<spdlog::logger> scriptLogger;
static Ref<spdlog::logger> uiEngineLogger;
};
} // namespace Deer
@ -44,6 +48,12 @@ namespace Deer {
#define DEER_SCRIPT_WARN(...) Deer::Log::getScriptLogger()->warn(__VA_ARGS__)
#define DEER_SCRIPT_ERROR(...) Deer::Log::getScriptLogger()->error(__VA_ARGS__)
#define DEER_UI_ENGINE_TRACE(...) Deer::Log::getUiEngineLogger()->trace(__VA_ARGS__)
#define DEER_UI_ENGINE_INFO(...) Deer::Log::getUiEngineLogger()->info(__VA_ARGS__)
#define DEER_UI_ENGINE_WARN(...) Deer::Log::getUiEngineLogger()->warn(__VA_ARGS__)
#define DEER_UI_ENGINE_ERROR(...) Deer::Log::getUiEngineLogger()->error(__VA_ARGS__)
#ifdef LINUX
#define DEER_CORE_ASSERT(condition, ...) \
if (!(condition)) { \

View File

@ -0,0 +1,11 @@
#pragma once
namespace Deer {
// This namespace implements all interface ported from c++ ImGui to an easier lua aproach with simplifications
namespace UIEngine {
void initialize();
void deinitialize();
void execute();
}
}

View File

@ -4,6 +4,7 @@ namespace Deer {
std::shared_ptr<spdlog::logger> Log::coreLogger;
std::shared_ptr<spdlog::logger> Log::clientLogger;
std::shared_ptr<spdlog::logger> Log::scriptLogger;
std::shared_ptr<spdlog::logger> Log::uiEngineLogger;
void Log::init()
{
@ -12,16 +13,19 @@ namespace Deer {
coreLogger = spdlog::stdout_color_mt("Core");
clientLogger = spdlog::stdout_color_mt("Client");
scriptLogger = spdlog::stdout_color_mt("Script");
uiEngineLogger = spdlog::stdout_color_mt("UI Engine");
coreLogger->set_level(spdlog::level::level_enum::trace);
clientLogger->set_level(spdlog::level::level_enum::trace);
scriptLogger->set_level(spdlog::level::level_enum::trace);
uiEngineLogger->set_level(spdlog::level::level_enum::trace);
}
void Log::shutdown() {
coreLogger.reset();
clientLogger.reset();
scriptLogger.reset();
uiEngineLogger.reset();
spdlog::drop_all();
}

View File

@ -14,9 +14,37 @@
#include <unordered_map>
#include <ostream>
#include <streambuf>
#include <unordered_map>
namespace Deer {
Path DataStore::rootPath;
namespace DataStore {
Path rootPath;
std::unordered_map<std::string ,DirectoryData> dirData_cache;
}
const DirectoryData& DataStore::getDirData(const Path& id, const Path& subDir, const char* extension) {
std::string dirId = std::string(id) + "&" + std::string(subDir) + "&" + std::string(extension);
if (dirData_cache.contains(dirId)) {
return dirData_cache[dirId];
}
Path idPath = rootPath;
if (id != "")
idPath /= id;
Path searchPath = idPath;
if (subDir != "")
searchPath /= subDir;
DirectoryData& dirData = dirData_cache[dirId];
for (const auto& entry : std::filesystem::directory_iterator(searchPath)) {
if (entry.is_directory())
dirData.subDirs.push_back(entry.path().lexically_relative(idPath));
else if (entry.path().extension() == extension)
dirData.elements.push_back(entry.path().lexically_relative(idPath));
}
return dirData;
}
void DataStore::deleteFile(const Path& path) {
Path filePath = rootPath / toLowerCasePath(path);

View File

@ -0,0 +1,106 @@
#include "DeerRender/UIEngine/DockPanelObject.h"
#include "DeerRender/UIEngine/UIEngine.h"
#include "DeerRender/UIEngine/ErrorHandle.h"
#include "angelscript.h"
#include <string>
#include "imgui.h"
namespace Deer {
UIEngine::DockPanelObject::DockPanelObject(asITypeInfo* _type)
: type (_type), isValid(false) {
// Constructor
// "type@ type()"
std::string callString(type->GetName());
callString += " @";
callString += type->GetName();
callString += "()";
asIScriptFunction* factory = type->GetFactoryByDecl(callString.c_str());
AS_CHECK_ADDITIONAL_INFO(
scriptContext->Prepare(factory),
type->GetName()
);
AS_CHECK_ADDITIONAL_INFO(
scriptContext->Execute(),
type->GetName()
);
// Return value contains the ref to a asIScriptObject in the location provided
object = *(asIScriptObject**)scriptContext->GetAddressOfReturnValue();
if (!object){
DEER_UI_ENGINE_ERROR("Could not create object", _type->GetName());
return;
}
object->AddRef();
renderFunction = type->GetMethodByDecl("void onRender()");
if (!renderFunction) {
DEER_UI_ENGINE_ERROR("Could not load void onRender() from {0}", _type->GetName());
return;
}
isValid = true;
}
UIEngine::DockPanelObject::~DockPanelObject() {
if (object)
object->Release();
}
void UIEngine::DockPanelObject::executeRender() {
ImGui::Begin(type->GetName());
if (!isValid) {
ImGui::TextColored(ImVec4(1, 0.3f, 0.3f, 1), "There was an error, please check the logs or reload the interface");
ImGui::End();
return;
}
AS_CHECK_ADDITIONAL_INFO(
scriptContext->Prepare(renderFunction),
type->GetName()
);
AS_CHECK_ADDITIONAL_INFO(
scriptContext->SetObject(object),
type->GetName()
);
AS_CHECK_ADDITIONAL_INFO(
scriptContext->Execute(),
type->GetName()
);
ImGui::End();
}
UIEngine::DockPanelObject::DockPanelObject(DockPanelObject&& other) noexcept
: isValid(other.isValid), renderFunction(other.renderFunction), type(other.type), object(other.object) {
other.isValid = false;
other.renderFunction = nullptr;
other.type = nullptr;
other.object = nullptr;
}
UIEngine::DockPanelObject& UIEngine::DockPanelObject::operator=(UIEngine::DockPanelObject&& other) noexcept {
if (this != &other) {
isValid = other.isValid;
renderFunction = other.renderFunction;
type = other.type;
object = other.object;
other.isValid = false;
other.renderFunction = nullptr;
other.type = nullptr;
other.object = nullptr;
}
return *this;
}
}

View File

@ -0,0 +1,30 @@
#pragma once
class asITypeInfo;
class asIScriptObject;
class asIScriptFunction;
namespace Deer {
namespace UIEngine {
struct DockPanelObject {
private:
asITypeInfo* type = nullptr;
asIScriptObject* object = nullptr;
asIScriptFunction* renderFunction = nullptr;
bool isValid = false;
public:
DockPanelObject(asITypeInfo*);
~DockPanelObject();
// Delete copy constructor
DockPanelObject(const DockPanelObject&) = delete;
DockPanelObject& operator=(const DockPanelObject&) = delete;
DockPanelObject(DockPanelObject&& other) noexcept;
DockPanelObject& operator=(DockPanelObject&& other) noexcept;
void executeRender();
inline void invalidate() { isValid = false; }
};
}
}

View File

@ -0,0 +1,36 @@
#include "DeerRender/UIEngine/ErrorHandle.h"
#include "angelscript.h"
namespace Deer {
namespace UIEngine {
const char* getAngelScriptReturnCodeString(int code)
{
switch (code)
{
case asSUCCESS: return "SUCCESS (The operation was successful)";
case asERROR: return "ERROR (A generic error occurred)";
case asCONTEXT_ACTIVE: return "CONTEXT_ACTIVE (A context was active during an invalid operation)";
case asCONTEXT_NOT_FINISHED: return "CONTEXT_NOT_FINISHED (Context has not finished execution)";
case asCONTEXT_NOT_PREPARED: return "CONTEXT_NOT_PREPARED (Context is not prepared)";
case asINVALID_ARG: return "INVALID_ARG (An invalid argument was provided)";
case asNO_FUNCTION: return "NO_FUNCTION (Function not found)";
case asNOT_SUPPORTED: return "NOT_SUPPORTED (Feature not supported by build configuration)";
case asINVALID_NAME: return "INVALID_NAME (Name is not allowed or invalid)";
case asNAME_TAKEN: return "NAME_TAKEN (Name is already taken by another entity)";
case asINVALID_DECLARATION: return "INVALID_DECLARATION (The declaration is invalid)";
case asINVALID_OBJECT: return "INVALID_OBJECT (Invalid object handle or object type)";
case asINVALID_TYPE: return "INVALID_TYPE (Invalid type provided)";
case asALREADY_REGISTERED: return "ALREADY_REGISTERED (Item is already registered)";
case asMULTIPLE_FUNCTIONS: return "MULTIPLE_FUNCTIONS (More than one matching function found)";
case asNO_MODULE: return "NO_MODULE (Module was not found)";
case asNO_GLOBAL_VAR: return "NO_GLOBAL_VAR (Global variable was not found)";
case asINVALID_CONFIGURATION: return "INVALID_CONFIGURATION (Invalid configuration, likely during registration)";
case asINVALID_INTERFACE: return "INVALID_INTERFACE (Invalid interface registration)";
case asCANT_BIND_ALL_FUNCTIONS: return "CANT_BIND_ALL_FUNCTIONS (Couldn't bind all functions for a virtual interface)";
case asLOWER_ARRAY_DIMENSION_NOT_REGISTERED: return "LOWER_ARRAY_DIMENSION_NOT_REGISTERED (Lower dimension type for array not registered)";
default: return "Unknown AngelScript error code";
}
}
}
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "Deer/Log.h"
#include <angelscript.h>
namespace Deer {
namespace UIEngine {
const char* getAngelScriptReturnCodeString(int code);
}
}
#define AS_CHECK(f) { \
int __r = f; \
if (__r < 0) { \
DEER_UI_ENGINE_ERROR("Error at line: {0}:{1} -> {2}", __FILE__, __LINE__, Deer::UIEngine::getAngelScriptReturnCodeString(__r)); \
} \
}
#define AS_CHECK_ADDITIONAL_INFO(f, i) { \
int __r = f; \
if (__r < 0) { \
DEER_UI_ENGINE_ERROR("Error at line: {0}:{1} -> {2} \n {3}", __FILE__, __LINE__, Deer::UIEngine::getAngelScriptReturnCodeString(__r), i); \
} \
}
#define AS_RET_CHECK(f) { \
int __r = f; \
if (__r < 0) { \
DEER_UI_ENGINE_ERROR("Error at line: {0}:{1} -> {2}", __FILE__, __LINE__, Deer::UIEngine::getAngelScriptReturnCodeString(__r)); \
return; \
} \
}

View File

@ -0,0 +1,32 @@
#include "angelscript.h"
#include "DeerRender/UIEngine/UIEngine.h"
#include "DeerRender/UIEngine/DockPanelObject.h"
#include "DeerRender/UIEngine/ErrorHandle.h"
namespace Deer {
void UIEngine::registerDockPanel() {
AS_RET_CHECK(scriptEngine->RegisterInterface("DockPanel"));
AS_RET_CHECK(scriptEngine->RegisterInterfaceMethod("DockPanel", "void onRender()"));
}
void UIEngine::extractDockPanels() {
size_t nScripts = scriptModule->GetObjectTypeCount();
asITypeInfo* dockPanelType = scriptEngine->GetTypeInfoByName("DockPanel");
if (!dockPanelType) {
DEER_UI_ENGINE_ERROR("Could not load DockPanel interface type");
return;
}
for (size_t i = 0; i < nScripts; i++) {
asITypeInfo* info = scriptModule->GetObjectTypeByIndex(i);
// If it does not implement dock panel we are not interested int it
if (!info->Implements(dockPanelType))
continue;
dockPanels.push_back({info});
}
}
}

View File

@ -0,0 +1,38 @@
#include "DeerRender/UIEngine/UIEngine.h"
#include "DeerRender/UIEngine/ErrorHandle.h"
#include "Deer/Path.h"
#include "Deer/DataStore.h"
#include "angelscript.h"
#include "scriptbuilder.h"
#include <iostream>
#include <filesystem>
#include <vector>
#include <string>
namespace fs = std::filesystem;
namespace Deer {
void UIEngine::loadScripts() {
Path path = DataStore::rootPath / DEER_UI_SCRIPT_PATH;
CScriptBuilder builder;
AS_RET_CHECK(builder.StartNewModule(scriptEngine, "DeerModule"));
DEER_UI_ENGINE_INFO("=== Extracting UI Engine Scripts ===");
for (const auto& entry : fs::recursive_directory_iterator(path)) {
if (entry.is_regular_file() && entry.path().extension() == ".as") {
DEER_UI_ENGINE_TRACE("\t{0}", entry.path().stem().string().c_str());
// We add aditional info to check who caused the error
AS_CHECK_ADDITIONAL_INFO(
builder.AddSectionFromFile(entry.path().string().c_str());,
entry.path().string().c_str()
);
}
}
AS_RET_CHECK(builder.BuildModule());
}
}

View File

@ -0,0 +1,120 @@
#include "DeerRender/UIEngine/UIEngineFunctions.h"
#include "DeerRender/UIEngine/UIEngine.h"
#include "DeerRender/UIEngine/ErrorHandle.h"
namespace Deer {
void UIEngine::registerUIEngineFunctions() {
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"void coloredText(float, float, float, const string& in)",
asFUNCTION(
Deer::UIEngine::coloredText
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"void text(const string& in)",
asFUNCTION(
text
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"bool isMouseClicked(int)",
asFUNCTION(
isMouseClicked
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"bool isMouseDoubleClicked(int)",
asFUNCTION(
isMouseDoubleClicked
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"void setupAutomaticColumns(int)",
asFUNCTION(
setupAutomaticColumns
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"void endColumns()",
asFUNCTION(
endColumns
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"void nextColumn()",
asFUNCTION(
nextColumn
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"void print(const string& in)",
asFUNCTION (
Deer::UIEngine::print
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"int getMeshCount(const string& in)",
asFUNCTION(
Deer::UIEngine::getMeshCount
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"string getMeshPath(const string& in, int)",
asFUNCTION(
Deer::UIEngine::getMeshPath
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"string getMeshName(const string& in, int)",
asFUNCTION(
Deer::UIEngine::getMeshName
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"int getMeshDirCount(const string& in)",
asFUNCTION(
Deer::UIEngine::getMeshDirCount
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"string getMeshDirPath(const string& in, int)",
asFUNCTION(
Deer::UIEngine::getMeshDirPath
),
asCALL_CDECL
));
AS_CHECK(scriptEngine->RegisterGlobalFunction(
"string getMeshDirName(const string& in, int)",
asFUNCTION(
Deer::UIEngine::getMeshDirName
),
asCALL_CDECL
));
}
}

View File

@ -0,0 +1,74 @@
#include "DeerRender/UIEngine.h"
#include "DeerRender/UIEngine/ErrorHandle.h"
#include "DeerRender/UIEngine/UIEngineFunctions.h"
#include "DeerRender/UIEngine/UIEngine.h"
#include "DeerRender/UIEngine/DockPanelObject.h"
#include "Deer/Log.h"
#include <vector>
#include "angelscript.h"
#include "scriptbuilder.h"
#include "scriptstdstring.h"
namespace Deer {
namespace UIEngine {
asIScriptEngine* scriptEngine = nullptr;
asIScriptModule* scriptModule = nullptr;
asIScriptContext* scriptContext = nullptr;
std::vector<DockPanelObject> dockPanels;
DockPanelObject* currentDockPanelExecution = nullptr;
bool active = false;
}
void UIEngine::initialize() {
int err = 0;
// If it exist we will reload it
deinitialize();
scriptEngine = asCreateScriptEngine();
RegisterStdString(scriptEngine);
AS_RET_CHECK(scriptEngine->SetMessageCallback(asFUNCTION(Deer::UIEngine::errorCallback), 0, asCALL_CDECL));
registerUIEngineFunctions();
registerDockPanel();
loadScripts();
scriptModule = scriptEngine->GetModule("DeerModule");
scriptContext = scriptEngine->CreateContext();
extractDockPanels();
active = true;
}
void UIEngine::deinitialize() {
dockPanels.clear();
if (scriptContext)
scriptContext->Release();
if (scriptEngine)
scriptEngine->ShutDownAndRelease();
scriptEngine = nullptr;
scriptModule = nullptr;
scriptContext = nullptr;
active = false;
}
void UIEngine::execute() {
if (!active)
return;
for (auto& panel : dockPanels) {
currentDockPanelExecution = &panel;
panel.executeRender();
}
currentDockPanelExecution = nullptr;
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <vector>
class asIScriptEngine;
class asIScriptObject;
class asIScriptModule;
class asIScriptContext;
namespace Deer {
namespace UIEngine {
struct DockPanelObject;
extern asIScriptEngine* scriptEngine;
extern asIScriptModule* scriptModule;
extern asIScriptContext* scriptContext;
extern std::vector<DockPanelObject> dockPanels;
extern DockPanelObject* currentDockPanelExecution;
void loadScripts();
void registerUIEngineFunctions();
void registerDockPanel();
void extractDockPanels();
}
}

View File

@ -0,0 +1,118 @@
#include "DeerRender/UIEngine/UIEngineFunctions.h"
#include "DeerRender/UIEngine/UIEngine.h"
#include "DeerRender/UIEngine/DockPanelObject.h"
#include "Deer/Log.h"
#include "Deer/DataStore.h"
#include "angelscript.h"
#include "imgui.h"
namespace Deer {
namespace UIEngine {
int getMeshCount(std::string& dir) {
return DataStore::getDirData(DEER_MESH_PATH, dir, ".dmesh").elements.size();
}
std::string getMeshPath(std::string& dir, int i) {
const DirectoryData& dirData = DataStore::getDirData(DEER_MESH_PATH, dir, ".dmesh");
if (i < 0 || i >= dirData.elements.size()){
DEER_UI_ENGINE_ERROR("Invalid id {0} calling getMeshPath(..), mas size {1}", i, dirData.subDirs.size());
if (currentDockPanelExecution) {
currentDockPanelExecution->invalidate();
}
return "";
}
return dirData.elements[i].string();
}
std::string getMeshName(std::string& dir, int i) {
const DirectoryData& dirData = DataStore::getDirData(DEER_MESH_PATH, dir, ".dmesh");
if (i < 0 || i >= dirData.elements.size()){
DEER_UI_ENGINE_ERROR("Invalid id {0} calling getMeshName(..), mas size {1}", i, dirData.subDirs.size());
if (currentDockPanelExecution) {
currentDockPanelExecution->invalidate();
}
return "";
}
return dirData.elements[i].stem().string();
}
int getMeshDirCount(std::string& dir) {
return DataStore::getDirData(DEER_MESH_PATH, dir, ".dmesh").subDirs.size();
}
std::string getMeshDirPath(std::string& dir, int i) {
const DirectoryData& dirData = DataStore::getDirData(DEER_MESH_PATH, dir, ".dmesh");
if (i < 0 || i >= dirData.subDirs.size()){
DEER_UI_ENGINE_ERROR("Invalid id {0} calling getMeshDirPath(..), mas size {1}", i, dirData.subDirs.size());
if (currentDockPanelExecution) {
currentDockPanelExecution->invalidate();
}
return "";
}
return dirData.subDirs[i].string();
}
std::string getMeshDirName(std::string& dir, int i) {
const DirectoryData& dirData = DataStore::getDirData(DEER_MESH_PATH, dir, ".dmesh");
if (i < 0 || i >= dirData.subDirs.size()){
DEER_UI_ENGINE_ERROR("Invalid id {0} calling getMeshDirName(..), mas size {1}", i, dirData.subDirs.size());
if (currentDockPanelExecution) {
currentDockPanelExecution->invalidate();
}
return "";
}
return dirData.subDirs[i].filename().string();
}
void coloredText(float r, float g, float b, std::string& msg) {
ImGui::TextColored(ImVec4(r, g, b, 1.0f), "%s", msg.c_str());
}
void text(std::string& msg) {
ImGui::Text("%s", msg.c_str());
}
void drawIcon(std::string& , int size) {
// TODO
}
// Interaction
bool isMouseClicked(int mouse) {
return ImGui::IsItemClicked(mouse);
}
bool isMouseDoubleClicked(int mouse) {
return ImGui::IsMouseDoubleClicked(mouse);
}
void setupAutomaticColumns(int pixelSize) {
float width = ImGui::GetWindowContentRegionWidth();
if (width < pixelSize) {
ImGui::Columns();
return;
}
int cols = (int)(width / (pixelSize));
float componentWidth = width / (float)cols;
ImGui::Columns(cols, 0, false);
}
void endColumns() {
ImGui::Columns();
}
void nextColumn() {
ImGui::NextColumn();
}
void errorCallback(const asSMessageInfo *msg, void *param) {
if (msg->type == asMSGTYPE_WARNING) {
DEER_UI_ENGINE_WARN("{0} : ({1}, {2}) : {3}", msg->section, msg->row, msg->col, msg->message);
} else if( msg->type == asMSGTYPE_INFORMATION ) {
DEER_UI_ENGINE_ERROR("{0} : ({1}, {2}) : {3}", msg->section, msg->row, msg->col, msg->message);
}
}
void print(std::string& msg) {
DEER_UI_ENGINE_INFO("{0}", msg.c_str());
}
}
}

View File

@ -0,0 +1,54 @@
#pragma once
#include <string>
class asSMessageInfo;
namespace Deer {
namespace UIEngine {
// TODO: Detect if it has menu bar
// TODO: Make icon an enum
// --- Mesh Data Store ---
// Returns the count of meshes in the dir relative to the mesh root dir
int getMeshCount(std::string& dir);
// Returns the path to the mesh with id i
std::string getMeshPath(std::string& dir, int i);
// Returns the name of the mesh with id i
std::string getMeshName(std::string& dir, int i);
// Returns the count of sub dirs in the dir relative to the mesh root dir
int getMeshDirCount(std::string& dir);
// Returns the path to the subDir in the dir relative to the mesh root dir
std::string getMeshDirPath(std::string& dir, int i);
// Returns the name of the subDir in the dir relative to the mesh root dir
std::string getMeshDirName(std::string& dir, int i);
// --- RENDERING ---
// TEXT
// Renders a text with the defined rgb values from range [0.0, 1.0]
void coloredText(float r, float g, float b, std::string& msg);
// Renders a text
void text(std::string& msg);
// Images
// TODO: Implement
void drawIcon(std::string& iconId, int size);
// Returns if the specified mouse button is clicked
bool isMouseClicked(int mouse);
// Returns if the specified mouse button is double clicked
bool isMouseDoubleClicked(int mouse);
// Set up the colums to fit the pixelSize elements
void setupAutomaticColumns(int pixelSize);
// Iterates to the next column
void nextColumn();
// Ends the columns made with setupColumns
void endColumns();
void errorCallback(const asSMessageInfo *msg, void *param);
// Prints in console a mesage
void print(std::string& msg);
}
}

View File

@ -8,14 +8,16 @@
#include "Deer/Voxel.h"
#include "Deer/VoxelWorld.h"
#include "DeerRender/Mesh.h"
#include "DeerRender/UIEngine.h"
#include "DeerStudio/Editor/Fonts.h"
#include "DeerStudio/Editor/GamePannel.h"
#include "DeerStudio/Editor/GamePanel.h"
#include "DeerStudio/Editor/Icons.h"
#include "DeerStudio/Editor/MeshExplorer/MeshExplorer.h"
#include "DeerStudio/Editor/PropertiesPannel.h"
#include "DeerStudio/Editor/PropertiesPanel.h"
#include "DeerStudio/Editor/SceneExplorer.h"
#include "DeerStudio/Editor/Terrain/TerrainEditor.h"
#include "DeerStudio/Editor/TreePannel.h"
#include "DeerStudio/Editor/TreePanel.h"
#include "DeerStudio/Editor/Viewport.h"
#include "DeerStudio/Project.h"
#include "Style.h"
@ -26,10 +28,10 @@ namespace Deer {
if (projectPath.empty()) return 1;
DataStore::rootPath = projectPath;
DataStore::createExampleVoxelData();
DataStore::createExampleVoxelAspect();
DataStore::loadVoxelsData();
DataStore::loadVoxelsAspect();
UIEngine::initialize();
return 0;
}
@ -53,8 +55,8 @@ namespace Deer {
setNatureStyle();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20, 20));
auto m_gamePannel = Ref<GamePannel>(new GamePannel());
pannels.push_back(m_gamePannel);
auto m_gamePanel = Ref<GamePanel>(new GamePanel());
Panels.push_back(m_gamePanel);
Environment& env = Project::m_scene.getMainEnviroment();
@ -75,12 +77,13 @@ namespace Deer {
Project::m_scene.endExecution();
ScriptEngine::shutdownScriptEngine();
pannels.clear();
Panels.clear();
UIEngine::deinitialize();
}
void DeerStudioApplication::onRender(Timestep delta) {
for (auto pannel : pannels) {
pannel->onRender(delta);
for (auto Panel : Panels) {
Panel->onRender(delta);
}
int windowWidth = Application::s_application->m_window->getWitdth();
@ -95,7 +98,7 @@ namespace Deer {
}
void DeerStudioApplication::onEvent(Event& e) {
for (auto& pannel : pannels) pannel->onEventCallback(e);
for (auto& Panel : Panels) Panel->onEventCallback(e);
viewport_onEvent(e);
}
@ -137,18 +140,19 @@ namespace Deer {
ImGui::EndMenuBar();
}
for (auto pannel : pannels) {
pannel->onImGui();
for (auto Panel : Panels) {
Panel->onImGui();
}
// ---- PANNELS -----
// ---- PanelS -----
// sceneExplorer_onImGUI();
TreePannel::onImgui();
PropertiesPannel::onImgui();
UIEngine::execute();
TreePanel::onImgui();
PropertiesPanel::onImgui();
MeshExplorer::onImGui();
TerrainEditor::onImGui();
viewport_onImGui();
// ---- PANNELS -----
// ---- PanelS -----
Project::m_scene.getMainGizmoRenderer().refresh();
ImGui::End();
@ -215,13 +219,20 @@ namespace Deer {
}
if (ImGui::BeginMenu("Voxel")) {
if (ImGui::MenuItem("Voxel Pannel")) {
if (ImGui::MenuItem("Voxel Panel")) {
// TODO
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Interface")) {
if (ImGui::MenuItem("Reload interface")) {
UIEngine::initialize();
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Scripts")) {
if (ImGui::MenuItem("Reload scripts") &&
!Project::m_scene.getExecutingState()) {

View File

@ -5,7 +5,7 @@
#include "DeerRender/Events/Event.h"
#include "DeerStudio/Editor/ActiveEntity.h"
#include "DeerStudio/Editor/EditorPannel.h"
#include "DeerStudio/Editor/EditorPanel.h"
namespace Deer {
class DeerStudioApplication : public Deer::Application {
@ -27,7 +27,7 @@ namespace Deer {
void drawMenuBar();
void onChangeScene();
std::vector<Ref<EditorPannel>> pannels;
std::vector<Ref<EditorPanel>> Panels;
};
}

View File

@ -1,4 +1,4 @@
#include "AssetManagerPannel.h"
#include "AssetManagerPanel.h"
#include "DeerStudio/Project.h"
#include "Deer/Log.h"
@ -32,7 +32,7 @@ namespace Deer {
namespace fs = std::filesystem;
AssetManagerPannel::AssetManagerPannel()
AssetManagerPanel::AssetManagerPanel()
: m_currentPath(DataStore::rootPath / "assets"){
m_folderIcon = Texture2D::create("editor/icons/folder.png");
@ -42,7 +42,7 @@ namespace Deer {
m_shaderIcon = Texture2D::create("editor/icons/shader.png");
}
void AssetManagerPannel::onImGui() {
void AssetManagerPanel::onImGui() {
m_clickHandled = false;
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(30, 30));
ImGui::Begin("Assets");
@ -103,7 +103,7 @@ namespace Deer {
ImGui::End();
}
void AssetManagerPannel::drawFolder(const std::filesystem::path& path) {
void AssetManagerPanel::drawFolder(const std::filesystem::path& path) {
ImGui::Image((void*)(uint64_t)m_folderIcon->getTextureID(), ImVec2(m_iconMinSize , m_iconMinSize), ImVec2(0, 1), ImVec2(1, 0));
if (ImGui::IsItemClicked(0) && ImGui::IsMouseDoubleClicked(0)) {
@ -111,7 +111,7 @@ namespace Deer {
}
}
void AssetManagerPannel::updateContextMenu() {
void AssetManagerPanel::updateContextMenu() {
if (ImGui::BeginPopup("AssetManagerPopUp")) {
if (ImGui::MenuItem("New Folder")) {
@ -125,7 +125,7 @@ namespace Deer {
}
void AssetManagerPannel::drawFile(const std::filesystem::path& path) {
void AssetManagerPanel::drawFile(const std::filesystem::path& path) {
std::string extension = path.filename().extension().string();
if (extension == ".dscn") {

View File

@ -1,5 +1,5 @@
#pragma once
#include "DeerStudio/Editor/EditorPannel.h"
#include "DeerStudio/Editor/EditorPanel.h"
#include "Deer/Memory.h"
@ -10,9 +10,9 @@ namespace Deer {
class DeerStudioLayer;
class SceneSerializer;
class AssetManagerPannel : public EditorPannel{
class AssetManagerPanel : public EditorPanel{
public:
AssetManagerPannel();
AssetManagerPanel();
void onImGui() override;
private:
void drawFolder(const std::filesystem::path&);

View File

@ -4,9 +4,9 @@
namespace Deer {
class Event;
class EditorPannel {
class EditorPanel {
public:
virtual ~EditorPannel() = default;
virtual ~EditorPanel() = default;
virtual void onRender(Timestep timestep) { }
virtual void onEventCallback(Event& e) { }
virtual void onImGui() { }

View File

@ -1,4 +1,4 @@
#include "GamePannel.h"
#include "GamePanel.h"
#include <filesystem>
@ -9,13 +9,13 @@
#include "imgui.h"
namespace Deer {
GamePannel::GamePannel() {
GamePanel::GamePanel() {
FrameBufferSpecification fbSpecs = FrameBufferSpecification(
100, 100, {TextureBufferType::RGBA8}, 1, false);
m_frameBuffer = FrameBuffer::create(fbSpecs);
}
void GamePannel::onImGui() {
void GamePanel::onImGui() {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::Begin("Game Window");
ImGui::PopStyleVar();

View File

@ -1,7 +1,7 @@
#pragma once
#include "Deer/Memory.h"
#include "DeerStudio/Editor/EditorPannel.h"
#include "DeerStudio/Editor/EditorPanel.h"
#include "DeerStudio/Editor/ActiveEntity.h"
#include "glm/glm.hpp"
@ -10,9 +10,9 @@ namespace Deer {
class Scene;
class FrameBuffer;
class GamePannel : public EditorPannel {
class GamePanel : public EditorPanel {
public:
GamePannel();
GamePanel();
void onImGui() override;
private:

View File

@ -1,4 +1,4 @@
#include "PropertiesPannel.h"
#include "PropertiesPanel.h"
#include "Deer/Asset.h"
#include "Deer/ScriptEngine.h"
@ -9,7 +9,7 @@
#include "imgui.h"
namespace Deer {
namespace PropertiesPannel {
namespace PropertiesPanel {
void addComponentContext();
template <typename T>
@ -24,7 +24,7 @@ namespace Deer {
void drawMagicSlider(const std::string& text, float* value);
void drawMagicSlider3f(const std::string& text, float* value,
float defaultValue = 0);
} // namespace PropertiesPannel
} // namespace PropertiesPanel
bool* getIsEditingState(ImGuiID id) {
ImGuiStorage* storage = ImGui::GetStateStorage();
@ -37,7 +37,7 @@ namespace Deer {
return state;
}
void PropertiesPannel::onImgui() {
void PropertiesPanel::onImgui() {
ImGui::Begin("Properties");
if (ActiveEntity::count() == 0) {
@ -262,7 +262,7 @@ namespace Deer {
ImGui::End();
}
void PropertiesPannel::drawMagicSlider(const std::string& text,
void PropertiesPanel::drawMagicSlider(const std::string& text,
float* value) {
ImGuiID id = ImGui::GetID(text.c_str());
@ -286,7 +286,7 @@ namespace Deer {
*isEditing = true;
}
void PropertiesPannel::drawMagicSlider3f(const std::string& text,
void PropertiesPanel::drawMagicSlider3f(const std::string& text,
float* value, float defaultValue) {
ImGui::Columns(4, 0, false);
@ -353,7 +353,7 @@ namespace Deer {
ImGui::PopStyleVar(2);
}
void PropertiesPannel::addComponentContext() {
void PropertiesPanel::addComponentContext() {
float buttonWidth =
ImGui::CalcTextSize(" + add Component ").x; // Example button width
float windowWidth = ImGui::GetWindowSize().x;
@ -392,7 +392,7 @@ namespace Deer {
}
template <typename T>
inline bool PropertiesPannel::collapsingComponentHeader(
inline bool PropertiesPanel::collapsingComponentHeader(
const std::string& componentName, bool canDelete) {
if (!ActiveEntity::shareComponent<T>()) return false;
@ -433,7 +433,7 @@ namespace Deer {
return collapsingHeader;
}
void PropertiesPannel::addScriptButton(const std::string& scriptID) {
void PropertiesPanel::addScriptButton(const std::string& scriptID) {
ImGuiSelectableFlags selectableFlag =
(ActiveEntity::shareComponent<ScriptComponent>())
? ImGuiSelectableFlags_Disabled
@ -449,7 +449,7 @@ namespace Deer {
}
template <typename T>
void PropertiesPannel::addComponentButton(
void PropertiesPanel::addComponentButton(
const std::string& componentName) {
ImGuiSelectableFlags selectableFlag =
(ActiveEntity::shareComponent<T>()) ? ImGuiSelectableFlags_Disabled

View File

@ -1,10 +1,10 @@
#pragma once
#include "Deer/Memory.h"
#include "DeerStudio/Editor/ActiveEntity.h"
#include "DeerStudio/Editor/EditorPannel.h"
#include "DeerStudio/Editor/EditorPanel.h"
namespace Deer {
namespace PropertiesPannel {
namespace PropertiesPanel {
void onImgui();
} // namespace PropertiesPannel
} // namespace PropertiesPanel
} // namespace Deer

View File

@ -1,4 +1,4 @@
#include "TreePannel.h"
#include "TreePanel.h"
#include "Deer/Enviroment.h"
#include "Deer/Scene.h"
@ -8,7 +8,7 @@
#include "imgui.h"
namespace Deer {
namespace TreePannel {
namespace TreePanel {
void updateEntity(Entity& entity);
void updateReciveDragPayload(Entity& entity);
bool updateDragPayload(Entity* entity, const std::string& name);
@ -17,10 +17,10 @@ namespace Deer {
bool m_isRightClickHandled;
Entity* m_contextMenuEntity = nullptr;
} // namespace TreePannel
} // namespace TreePanel
void TreePannel::onImgui() {
ImGui::Begin("Tree Pannel", (bool*)0, ImGuiWindowFlags_MenuBar);
void TreePanel::onImgui() {
ImGui::Begin("Tree Panel", (bool*)0, ImGuiWindowFlags_MenuBar);
m_isRightClickHandled = false;
Entity& root = Project::m_scene.getMainEnviroment().getRoot();
@ -83,7 +83,7 @@ namespace Deer {
ImGui::End();
}
void TreePannel::updateEntity(Entity& entity) {
void TreePanel::updateEntity(Entity& entity) {
auto& tag = entity.getComponent<TagComponent>();
auto& relationship = entity.getComponent<RelationshipComponent>();
@ -162,7 +162,7 @@ namespace Deer {
}
}
void TreePannel::updateReciveDragPayload(Entity& entity) {
void TreePanel::updateReciveDragPayload(Entity& entity) {
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload =
ImGui::AcceptDragDropPayload("_ENTITY")) {
@ -176,7 +176,7 @@ namespace Deer {
}
}
bool TreePannel::updateDragPayload(Entity* entity,
bool TreePanel::updateDragPayload(Entity* entity,
const std::string& name) {
if (!ImGui::BeginDragDropSource()) return false;
@ -187,7 +187,7 @@ namespace Deer {
return true;
}
void TreePannel::clickEntity(Entity& entity) {
void TreePanel::clickEntity(Entity& entity) {
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
if (!(Input::isKeyPressed(DEER_KEY_LEFT_CONTROL) ||
Input::isKeyPressed(DEER_KEY_LEFT_ALT)))
@ -200,7 +200,7 @@ namespace Deer {
}
}
void TreePannel::updateContextMenu() {
void TreePanel::updateContextMenu() {
bool callRename = false;
if (ImGui::BeginPopup("Entity Context Menu")) {

View File

@ -1,7 +1,7 @@
#pragma once
namespace Deer {
namespace TreePannel {
namespace TreePanel {
void onImgui();
}
}

View File

@ -1,6 +1,6 @@
[Window][DockSpace Demo]
Pos=0,0
Size=2560,1371
Size=1280,720
Collapsed=0
[Window][Debug##Default]
@ -9,32 +9,32 @@ Size=400,400
Collapsed=0
[Window][Properties]
Pos=2191,24
Size=369,531
Pos=968,24
Size=312,214
Collapsed=0
DockId=0x00000009,0
[Window][Game Window]
Pos=368,24
Size=1821,1093
Pos=304,24
Size=662,368
Collapsed=0
DockId=0x00000006,1
[Window][Tree Pannel]
[Window][Tree Panel]
Pos=0,24
Size=366,1093
Size=302,368
Collapsed=0
DockId=0x00000005,0
[Window][Terrain Editor]
Pos=2191,557
Size=369,560
Pos=968,240
Size=312,152
Collapsed=0
DockId=0x0000000A,0
[Window][Viewport]
Pos=368,24
Size=1821,1093
Pos=304,24
Size=662,368
Collapsed=0
DockId=0x00000006,0
@ -45,21 +45,33 @@ Collapsed=0
DockId=0x00000002,0
[Window][Mesh Explorer]
Pos=0,1119
Size=2560,252
Pos=0,394
Size=1280,326
Collapsed=0
DockId=0x00000008,0
[Docking][Data]
DockSpace ID=0xA1672E74 Window=0x4647B76E Pos=0,24 Size=2560,1347 Split=Y
DockNode ID=0x00000007 Parent=0xA1672E74 SizeRef=1280,442 Split=Y
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=2560,363 Split=X Selected=0x13926F0B
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=909,779 Split=X Selected=0x13926F0B
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=366,779 Selected=0xBD1B42A3
DockNode ID=0x00000006 Parent=0x00000003 SizeRef=541,779 CentralNode=1 Selected=0x13926F0B
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=369,779 Split=Y Selected=0x199AB496
DockNode ID=0x00000009 Parent=0x00000004 SizeRef=392,214 Selected=0x199AB496
DockNode ID=0x0000000A Parent=0x00000004 SizeRef=392,226 Selected=0x2A2C795E
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=2560,331 Selected=0xCF339702
DockNode ID=0x00000008 Parent=0xA1672E74 SizeRef=1280,252 Selected=0x7F7E0F9C
[Window][MeshSearcher]
Pos=0,493
Size=1280,227
Collapsed=0
DockId=0x00000008,1
[Window][MeshExplorer]
Pos=0,394
Size=1280,326
Collapsed=0
DockId=0x00000008,1
[Docking][Data]
DockSpace ID=0xA1672E74 Window=0x4647B76E Pos=0,24 Size=1280,696 Split=Y
DockNode ID=0x00000007 Parent=0xA1672E74 SizeRef=1280,368 Split=Y
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=2560,363 Split=X Selected=0x13926F0B
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=966,779 Split=X Selected=0x13926F0B
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=302,779 Selected=0xF278DC36
DockNode ID=0x00000006 Parent=0x00000003 SizeRef=662,779 CentralNode=1 Selected=0x13926F0B
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=312,779 Split=Y Selected=0x199AB496
DockNode ID=0x00000009 Parent=0x00000004 SizeRef=392,214 Selected=0x199AB496
DockNode ID=0x0000000A Parent=0x00000004 SizeRef=392,152 Selected=0x2A2C795E
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=2560,331 Selected=0xCF339702
DockNode ID=0x00000008 Parent=0xA1672E74 SizeRef=1280,326 Selected=0x7F7E0F9C

View File

@ -0,0 +1,25 @@
class MeshExplorer : DockPanel {
string currentPath = "";
void onRender() {
coloredText(0.5, 0.5, 0.5, currentPath);
setupAutomaticColumns(180);
int dirCount = getMeshDirCount(currentPath);
for (int i = 0; i < dirCount; i++) {
text(getMeshDirName(currentPath, i));
nextColumn();
}
int meshCount = getMeshCount(currentPath);
for (int i = 0; i < meshCount; i++) {
text(getMeshName(currentPath, i));
nextColumn();
}
endColumns();
}
}