Editor asset importing seems to work - tested on tile sets.

Gui_Panel_Refactor
Joeyrp 4 years ago
parent 6aef59c7e3
commit 6d85356368

@ -6,22 +6,31 @@ Editor:
☐ Reference raw asset files in a "content" folder@high
✔ Platform independant file browsing @done (2/8/2022, 4:05:29 PM)
☐ Scan script files to make sure they don't overwrite globals
☐ Figure out how to make game asset types integrate with editor asset types @critical
Panel System:
☐ Allow for saving custom panel layouts @low
Raw Asset Importers:
- Need classes to import raw resource files for the editor
☐ Raw Resource importer interface class
✔ Raw Resource importer interface class (EditorAsset) @done (2/24/2022, 3:14:04 PM)
☐ Raw Image importer class
☐ Raw Sound importer class
☐ Raw font file importer class
☐ Tile Set
☐ Tile Map
Project (Class for loading and tracking project data):
✔ Generate new project at given location @done (11/9/2021, 3:26:03 PM)
☐ Save project data
✔ Open existing project @done (2/8/2022, 4:05:42 PM)
Content Manager:
✔ Design interface @done (2/24/2022, 3:15:39 PM)
✔ Generate new content file @done (2/24/2022, 3:16:00 PM)
☐ Load existing contents
☐ Save/Update contents file
GUI Panels:
Project Overview (Tree view):
@ -35,7 +44,7 @@ Editor:
Tools:
Tile Map Editor:
☐ Tile map canvas
☐ Tile map pallete
✔ Tile map pallete @done (2/24/2022, 3:15:26 PM)
☐ Hideable grid
☐ Stamp creater
☐ Flood Fill

@ -2,6 +2,7 @@
# Source Files
set(EDITOR_SRC
"editor.cpp"
"editor_helpers.cpp"
"panel_manager.cpp"
"project/project.cpp"
"panels/about.cpp"

@ -145,6 +145,11 @@ namespace editor
// HELPER METHODS
////////////////////////////////////////////////////////////
std::filesystem::path Editor::GetAssetBrowserLocation()
{
return mProject.GetAssetDirectory() / ((AssetBrowser*)mPanelManager.GetPanel(gui::PanelType::PT_ASSET_BROWSER))->GetSelectedDirectory();
}
void Editor::RenderWindow()
{
ImGuiViewport* Viewport = ImGui::GetWindowViewport();
@ -210,7 +215,7 @@ namespace editor
if (mFileBrowser.GetResult() == FileBrowser::Result::OK)
{
mpPath = mFileBrowser.GetSelectedItem();
Logger::Log(LogCat, LogLevel::INFO, "Generating new project at %s", mpPath->string().c_str());
Logger::Log(LogCat, LogLevel::INFO, "Opening project: %s", mpPath->string().c_str());
// Open project at mpPath
OpRes result = mProject.LoadProject(*mpPath);
@ -218,7 +223,7 @@ namespace editor
{
Logger::Log(LogCat, LogLevel::ERROR, "Could not open project: %s -- reason: %s", mpPath->string().c_str(), result.Description);
}
((AssetBrowser*)mPanelManager.GetPanel(PanelType::PT_ASSET_BROWSER))->SetAssetDirectory(*mpPath / std::filesystem::path("contents/assets"));
((AssetBrowser*)mPanelManager.GetPanel(PanelType::PT_ASSET_BROWSER))->SetAssetDirectory(mpPath->parent_path() / std::filesystem::path("contents/assets"));
mDoOpenProject = false;
}
else if (mFileBrowser.GetResult() == FileBrowser::Result::CANCEL)

@ -52,6 +52,8 @@ namespace lunarium { namespace editor
unsigned int GetNextWindowID();
bool IsToolOpen(ToolType type) const;
std::filesystem::path GetAssetBrowserLocation();
private:
Editor(const Editor&) = delete;
const Editor& operator=(const Editor&) = delete;

@ -0,0 +1,44 @@
/******************************************************************************
* File - editor_helpers.cpp
* Author - Joey Pollack
* Date - 2022/03/02 (y/m/d)
* Mod Date - 2022/03/02 (y/m/d)
* Description - Helper methods for the editor
******************************************************************************/
#include "editor_helpers.h"
#include <core/core.h>
#include <graphics/graphics.h>
#include <assets/types/image.h>
#include <utils/stb/stb_image.h>
namespace lunarium { namespace editor
{
lunarium::Image* FileLoaders::LoadImage(std::filesystem::path file)
{
int w, h, n;
stbi_set_flip_vertically_on_load(1);
unsigned char* buffer = stbi_load(file.string().c_str(), &w, &h, &n, 0);
if (!buffer)
{
return nullptr;
}
Image* i = new Image();
i->SetData(buffer);
i->SetFormat(ImageFormat::RGBA);
if (n == 3)
{
i->SetFormat(ImageFormat::RGB);
}
i->SetWidth(w);
i->SetHeight(h);
Core::Graphics().RegisterImage(*i);
return i;
}
}}

@ -0,0 +1,29 @@
/******************************************************************************
* File - editor_helpers.h
* Author - Joey Pollack
* Date - 2022/03/02 (y/m/d)
* Mod Date - 2022/03/02 (y/m/d)
* Description - Helper methods for the editor
******************************************************************************/
#ifndef EDITOR_HELPERS_H_
#define EDITOR_HELPERS_H_
#include <filesystem>
namespace lunarium
{
class Image;
}
namespace lunarium { namespace editor
{
class FileLoaders
{
public:
static lunarium::Image* LoadImage(std::filesystem::path file);
};
}}
#endif // EDITOR_HELPERS_H_

@ -27,6 +27,12 @@ namespace editor
mAssetDirectory = dir;
}
std::filesystem::path AssetBrowser::GetSelectedDirectory()
{
return mSelectedDir;
}
bool AssetBrowser::DoFrame()
{
if (!mIsOpen)

@ -27,6 +27,8 @@ namespace editor
bool DoFrame();
std::filesystem::path GetSelectedDirectory();
private:
struct Node
{

@ -9,15 +9,20 @@
******************************************************************************/
#include "content_manager.h"
#include <editor/editor.h>
#include "../project.h"
#include <pugixml.hpp>
#include "editor_asset.h"
// Asset types
#include "tile_set.h"
namespace lunarium { namespace editor
{
ContentManager* ContentManager::mpInstance = nullptr;
ContentManager::ContentManager()
: mpProject(nullptr)
: mpProject(nullptr), mNextID(0)
{
}
@ -43,49 +48,265 @@ namespace lunarium { namespace editor
OpRes ContentManager::Load(Project* project)
{
Unload();
mpProject = project;
std::filesystem::path root = mpProject->GetRootDirectory();
mContentFile = root / "contents/content_meta.xml";
// If this is a new project being generated just create a base contents file
if (!std::filesystem::exists(mContentFile))
{
// pugi::xml_node proj_node = doc.append_child("Project");
// proj_node.append_attribute("Name").set_value(mpProject->GetName().c_str());
// mNextID = 0;
// proj_node.append_child("NextID").append_attribute("ID").set_value(mNextID);
// // pugi::xml_node proj_node = doc.append_child("Contents");
// proj_node.append_child("Contents");
// if (!doc.save_file(mContentFile.string().c_str()))
// {
// return OpRes::Fail("ContentManager could not save file: %s", mContentFile.string().c_str());
// }
return Save();
}
// Load the file
pugi::xml_document doc;
pugi::xml_node proj_node = doc.append_child("Contents");
if (!doc.save_file(mContentFile.string().c_str()))
pugi::xml_parse_result result = doc.load_file(mContentFile.string().c_str());
if (result.status != pugi::xml_parse_status::status_ok)
{
return OpRes::Fail("ContentManager could not save file: %s", mContentFile.string().c_str());
return OpRes::Fail("Could not open contents file: %s, %s", mContentFile.string().c_str(), result.description());
}
return OpRes::OK();
pugi::xml_node proj_node = doc.child("Project");
if (!proj_node)
{
return OpRes::Fail("content_meta.xml missing Project root node");
}
// Get ID
pugi::xml_node ID = proj_node.child("NextID");
if (!ID)
{
return OpRes::Fail("content_meta.xml missing NextID node");
}
return OpRes::Fail("ContentManager::Load not implemented");
mNextID = ID.attribute("ID").as_ullong();
pugi::xml_node content = proj_node.child("Content");
if (!content)
{
return OpRes::Fail("content_meta.xml missing Content node");
}
// Iterate through content
for (pugi::xml_node asset = content.child("Asset"); asset; asset = asset.next_sibling("Asset"))
{
if (!IsValidAsset(asset))
{
return OpRes::Fail("Invalid asset node in content_meta.xml");
}
// Load Type
AssetType type = (AssetType)asset.attribute("Type").as_int();
EditorAsset* pAsset = CreateAsset(type);
if (!pAsset)
{
return OpRes::Fail("Could not create Editor Asset. Unknown type: %n", (int)type);
}
// Load ID
pAsset->mID = (uint64_t)asset.attribute("ID").as_ullong();
// Load Location
pAsset->mLocation = std::filesystem::path(asset.attribute("Location").as_string());
// Load type specific data
if (Failed(pAsset->LoadFromXML(asset).LogIfFailed(Editor::LogCat)))
{
return OpRes::Fail("Could not load asset type specific data for asset with ID: %llu, File: %s",
pAsset->GetID(), pAsset->GetFileLocation().filename().string().c_str());
}
// Store asset
if (mAssets.find(pAsset->mID) == mAssets.end())
{
return OpRes::Fail("Asset ID collision, ID: %llu, File: %s",
pAsset->GetID(), pAsset->GetFileLocation().filename().string().c_str());
}
mAssets[pAsset->mID] = pAsset;
}
return OpRes::OK();
}
OpRes ContentManager::Save()
{
return OpRes::Fail("ContentManager::Save not implemented");
if (!mpProject)
{
return OpRes::Fail("ConentManager::Save failed: no project set");
}
// Save header info
pugi::xml_document doc;
pugi::xml_node proj_node = doc.append_child("Project");
proj_node.append_attribute("Name").set_value(mpProject->GetName().c_str());
proj_node.append_child("NextID").append_attribute("ID").set_value(mNextID);
// pugi::xml_node proj_node = doc.append_child("Contents");
// Save all assets
pugi::xml_node contents = proj_node.append_child("Contents");
for (auto iter = mAssets.begin(); iter != mAssets.end(); iter++)
{
EditorAsset* pAsset = iter->second;
pugi::xml_node asset = contents.append_child("Asset");
asset.append_attribute("Type").set_value((int)pAsset->GetType());
asset.append_attribute("ID").set_value(pAsset->GetID());
asset.append_attribute("Location").set_value(pAsset->GetFileLocation().string().c_str());
if (Failed(pAsset->SaveToXML(asset).LogIfFailed(Editor::LogCat)))
{
return OpRes::Fail("Could not save asset meta data for file: %s", pAsset->GetFileLocation().string().c_str());
}
}
if (!doc.save_file(mContentFile.string().c_str()))
{
return OpRes::Fail("ContentManager could not save file: %s", mContentFile.string().c_str());
}
return OpRes::OK();
}
void ContentManager::Unload()
{
mpProject = nullptr;
mAssets.clear();
FreeAssets();
mContentFile = "";
mNextID = 0;
}
void ContentManager::GetAllAssetIDs(std::vector<uint64_t>& container) const
{
container.clear();
for (auto iter = mAssets.begin(); iter != mAssets.end(); iter++)
{
container.push_back(iter->first);
}
}
void ContentManager::GetAllAssetsByType(std::vector<EditorAsset*>& container, AssetType type) const
{
container.clear();
for (auto iter = mAssets.begin(); iter != mAssets.end(); iter++)
{
if (iter->second->GetType() == type)
{
container.push_back(iter->second);
}
}
}
OpRes ContentManager::ImportFile(std::filesystem::path file, AssetType type)
EditorAsset* ContentManager::GetAsset(uint64_t id)
{
return OpRes::Fail("ContentManager::ImportFile not implemented");
auto iter = mAssets.find(id);
if (iter == mAssets.end())
{
return nullptr;
}
return iter->second;
}
void ContentManager::MoveAsset(EditorAsset* asset, std::filesystem::path to)
OpRes ContentManager::AddGeneratedAsset(EditorAsset* asset, uint64_t& id)
{
if (mAssets.find(mNextID) != mAssets.end())
{
return OpRes::Fail("Could not import asset, ID collision. ID: %llu", mNextID);
}
asset->mID = mNextID;
mNextID++;
mAssets[asset->mID] = asset;
id = asset->mID;
return OpRes::OK();
}
void ContentManager::RenameAsset(EditorAsset* asset, std::string name)
OpRes ContentManager::ImportFile(std::filesystem::path file, std::filesystem::path to_location, AssetType type, uint64_t& id)
{
if (mAssets.find(mNextID) != mAssets.end())
{
return OpRes::Fail("Could not import asset, ID collision. ID: %llu", mNextID);
}
if (!std::filesystem::copy_file(file, to_location))
{
return OpRes::Fail("Could not copy asset file from: %s to: %s", file.string().c_str(), to_location.string().c_str());
}
EditorAsset* pAsset = CreateAsset(type);
pAsset->mID = mNextID;
mNextID++;
pAsset->mLocation = to_location;
if (Failed(pAsset->LoadRawFile().LogIfFailed(Editor::LogCat)))
{
delete pAsset;
return OpRes::Fail("Could not load asset data from raw file: %s", file.string().c_str());
}
mAssets[pAsset->mID] = pAsset;
id = pAsset->mID;
return OpRes::OK();
}
void ContentManager::RemoveAsset(uint64_t asset_id)
{
auto iter = mAssets.find(asset_id);
if (iter == mAssets.end())
{
return;
}
delete iter->second;
mAssets.erase(iter);
}
bool ContentManager::IsValidAsset(pugi::xml_node& node)
{
if (!node.child("ID")) { return false; }
if (!node.child("Type")) { return false; }
if (!node.child("Location")) { return false; }
return true;
}
EditorAsset* ContentManager::CreateAsset(AssetType type)
{
switch (type)
{
case AssetType::EATYPE_TILE_SET: return new TileSet();
default: return nullptr;
}
}
void ContentManager::FreeAssets()
{
for (auto iter = mAssets.begin(); iter != mAssets.end(); iter++)
{
delete iter->second;
}
mAssets.clear();
}
}}

@ -16,6 +16,9 @@
#include <string>
#include <utils/opRes.h>
#include <map>
#include <vector>
namespace pugi { class xml_node; }
namespace lunarium { namespace editor
{
@ -34,21 +37,35 @@ namespace lunarium { namespace editor
[[nodiscard]] OpRes Save();
void Unload();
[[nodiscard]] OpRes ImportFile(std::filesystem::path file, AssetType type);
void MoveAsset(EditorAsset* asset, std::filesystem::path to);
void RenameAsset(EditorAsset* asset, std::string name);
void GetAllAssetIDs(std::vector<uint64_t>& container) const;
void GetAllAssetsByType(std::vector<EditorAsset*>& container, AssetType type) const;
EditorAsset* GetAsset(uint64_t id);
/// Add an asset that was generated by the editor (like tile maps or scripts)
[[nodiscard]] OpRes AddGeneratedAsset(EditorAsset* asset, uint64_t& id);
/// Import a raw asset file from outside of the project (like image or sound files)
[[nodiscard]] OpRes ImportFile(std::filesystem::path file, std::filesystem::path to_location, AssetType type, uint64_t& id);
void RemoveAsset(uint64_t asset_id);
private:
static ContentManager* mpInstance;
Project* mpProject;
std::filesystem::path mContentFile;
std::map<uint64_t, EditorAsset*> mAssets;
uint64_t mNextID;
private:
ContentManager();
ContentManager(ContentManager&) = delete;
ContentManager& operator=(const ContentManager&) = delete;
private: // Helpers
[[nodiscard]] bool IsValidAsset(pugi::xml_node& node);
[[nodiscord]] EditorAsset* CreateAsset(AssetType type);
void FreeAssets();
};
}}

@ -13,6 +13,7 @@
#include "content_manager.h"
#include <filesystem>
#include <string>
#include <utils\opRes.h>
namespace lunarium { namespace editor
{
@ -26,6 +27,10 @@ namespace lunarium { namespace editor
uint64_t GetID();
std::filesystem::path GetFileLocation();
[[nodiscard]] virtual OpRes LoadRawFile() = 0;
[[nodiscard]] virtual OpRes LoadFromXML(pugi::xml_node& node) = 0;
[[nodiscard]] virtual OpRes SaveToXML(pugi::xml_node& node) = 0;
private:
friend class ContentManager;

@ -8,9 +8,11 @@
#include "tile_set.h"
#include <editor/editor.h>
#include <editor/editor_helpers.h>
#include <graphics/graphics.h>
#include <assets/types/image.h>
#include <utils/logger.h>
#include <pugixml.hpp>
namespace lunarium { namespace editor
{
@ -20,6 +22,48 @@ namespace lunarium { namespace editor
}
OpRes TileSet::LoadRawFile()
{
mSetImage = FileLoaders::LoadImage(GetFileLocation());
if (!mSetImage)
{
return OpRes::Fail("Could not load image file: %s", GetFileLocation().string().c_str());
}
// Set some default values
mTileSize = { 16, 16 };
mNumTiles = { mSetImage->GetWidth() / 16, mSetImage->GetHeight() / 16 };
return OpRes::OK();
}
OpRes TileSet::LoadFromXML(pugi::xml_node& node)
{
// Load Image
mSetImage = FileLoaders::LoadImage(GetFileLocation());
if (!mSetImage)
{
return OpRes::Fail("Could not load image file: %s", GetFileLocation().string().c_str());
}
mTileSize.Width = node.attribute("TileSizeWidth").as_int();
mTileSize.Height = node.attribute("TileSizeHeight").as_int();
mNumTiles.Width = node.attribute("NumTilesCol").as_int();
mNumTiles.Height = node.attribute("NumTilesRow").as_int();
return OpRes::OK();
}
OpRes TileSet::SaveToXML(pugi::xml_node& node)
{
node.append_attribute("TileSizeWidth").set_value(mTileSize.Width);
node.append_attribute("TileSizeHeight").set_value(mTileSize.Height);
node.append_attribute("NumTilesCol").set_value(mNumTiles.Width);
node.append_attribute("NumTilesRow").set_value(mNumTiles.Height);
return OpRes::OK();
}
void TileSet::SetImage(Image* image)
{
mSetImage = image;

@ -22,6 +22,11 @@ namespace lunarium { namespace editor
public:
TileSet();
// Load the raw asset file from the internal location
OpRes LoadRawFile();
OpRes LoadFromXML(pugi::xml_node& node);
OpRes SaveToXML(pugi::xml_node& node);
void SetImage(Image* image);
void SetTileSize(Sizei size);

@ -72,7 +72,7 @@ namespace lunarium { namespace editor
return OpRes::Fail("Project file does not exist");
}
mLocation = location;
mLocation = location.parent_path();
mName = location.filename().string();
mIsLoaded = true;
@ -101,4 +101,15 @@ namespace lunarium { namespace editor
{
return mLocation;
}
std::filesystem::path Project::GetContentDirectory() const
{
return mLocation / "contents";
}
std::filesystem::path Project::GetAssetDirectory() const
{
return GetContentDirectory() / "assets";
}
}}

@ -36,6 +36,8 @@ namespace lunarium { namespace editor
bool IsLoaded() const;
const std::string& GetName() const;
std::filesystem::path GetRootDirectory() const;
std::filesystem::path GetContentDirectory() const;
std::filesystem::path GetAssetDirectory() const;
private:
bool mIsLoaded;

@ -10,6 +10,7 @@
#include <core/core.h>
#include <graphics/graphics.h>
#include <editor/project/contents/content_manager.h>
#include <assets/types/image.h>
#include <editor/editor.h>
#include <gui/panel.h>
@ -214,28 +215,33 @@ namespace lunarium { namespace editor
auto path = mFileBrowser.GetSelectedItem();
Logger::Log(Editor::LogCat, LogLevel::INFO, "Importing tile set: %s", path->string().c_str());
uint64_t id = 0;
ContentManager::GetInstance().ImportFile(*path, mpEditor->GetAssetBrowserLocation() / path->filename(), AssetType::EATYPE_TILE_SET, id).LogIfFailed(Editor::LogCat);
// For now just directly load the file and make a tileset out of it
int w, h, n;
stbi_set_flip_vertically_on_load(1);
unsigned char* buffer = stbi_load(path->string().c_str(), &w, &h, &n, 0);
// int w, h, n;
// stbi_set_flip_vertically_on_load(1);
// unsigned char* buffer = stbi_load(path->string().c_str(), &w, &h, &n, 0);
Image* i = new Image();
i->SetData(buffer);
i->SetFormat(ImageFormat::RGBA);
// Image* i = new Image();
// i->SetData(buffer);
// i->SetFormat(ImageFormat::RGBA);
if (n == 3)
{
i->SetFormat(ImageFormat::RGB);
}
// if (n == 3)
// {
// i->SetFormat(ImageFormat::RGB);
// }
// i->SetWidth(w);
// i->SetHeight(h);
i->SetWidth(w);
i->SetHeight(h);
// Core::Graphics().RegisterImage(*i);
Core::Graphics().RegisterImage(*i);
// TileSet* ts = new TileSet();
// // ts->SetFileLocation(*path);
// ts->SetImage(i);
TileSet* ts = new TileSet();
// ts->SetFileLocation(*path);
ts->SetImage(i);
TileSet* ts = (TileSet*)ContentManager::GetInstance().GetAsset(id);
ts->SetTileSize({16, 16}); // NOTE: Hardcoding the tile size for testing
mTileSets[mTileSetNextID] = ts;

Loading…
Cancel
Save