mirror of
https://github.com/Llennpie/Saturn.git
synced 2025-01-22 15:43:05 -05:00
Add (new) expression subfolders
This commit is contained in:
parent
bd757178e9
commit
867d1cfd80
7 changed files with 96 additions and 56 deletions
|
@ -261,8 +261,6 @@ void sdynos_imgui_init() {
|
|||
model_list = GetModelList("dynos/packs");
|
||||
RefreshColorCodeList();
|
||||
|
||||
LoadEyesFolder();
|
||||
|
||||
//model_details = "" + std::to_string(sDynosPacks.Count()) + " model pack";
|
||||
//if (sDynosPacks.Count() != 1) model_details += "s";
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ void ShowExpressionContextMenu(Expression* expression, int id) {
|
|||
// Refresh Textures
|
||||
if (ImGui::Button(ICON_FK_REFRESH " Refresh Textures###refresh_textures")) {
|
||||
expression->Textures = LoadExpressionTextures(*expression);
|
||||
expression->Folders = LoadExpressionFolders(*expression);
|
||||
// We attempt to keep each currently-selected texture
|
||||
// If our index is out of bounds (e.g. PNG was deleted) reset it
|
||||
for (int i = 0; i < expression->Textures.size(); i++) {
|
||||
|
@ -65,6 +66,30 @@ void ShowExpressionContextMenu(Expression* expression, int id) {
|
|||
}
|
||||
}
|
||||
|
||||
void RecursiveSelector(Expression* expression, int recurse_index, std::string parent_path) {
|
||||
// Folders
|
||||
for (int n = recurse_index; n < expression->Folders.size(); n++) {
|
||||
TexturePath folder = expression->Folders[n];
|
||||
if (folder.ParentPath() != parent_path &&
|
||||
folder.ParentPath() != parent_path + "/") continue;
|
||||
|
||||
if (ImGui::TreeNode(folder.FileName.c_str())) {
|
||||
RecursiveSelector(expression, recurse_index + 1, folder.FilePath);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
// Textures
|
||||
for (int i = 0; i < expression->Textures.size(); i++) {
|
||||
TexturePath texture = expression->Textures[i];
|
||||
if (texture.ParentPath() != parent_path &&
|
||||
texture.ParentPath() != parent_path + "/") continue;
|
||||
|
||||
if (ImGui::Selectable(texture.FileName.c_str(), expression->CurrentIndex == i)) {
|
||||
expression->CurrentIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* A selection menu for a single Expression; A larger, one-click child window */
|
||||
void OpenEyeSelector(Expression* expression) {
|
||||
if (expression->Textures.size() <= 0) {
|
||||
|
@ -72,16 +97,8 @@ void OpenEyeSelector(Expression* expression) {
|
|||
return;
|
||||
};
|
||||
|
||||
ImGui::BeginChild(("###menu_eye_%s", expression->Name.c_str()), ImVec2(200, 75), true);
|
||||
for (int n = 0; n < expression->Textures.size(); n++) {
|
||||
bool is_selected = (expression->CurrentIndex == n);
|
||||
std::string entry_name = expression->Textures[n].FileName;
|
||||
|
||||
if (ImGui::Selectable(entry_name.c_str(), is_selected)) {
|
||||
//gfx_precache_textures();
|
||||
expression->CurrentIndex = n;
|
||||
}
|
||||
}
|
||||
ImGui::BeginChild(("###menu_eye_%s", expression->Name.c_str()), ImVec2(200, 125), true);
|
||||
RecursiveSelector(expression, 0, expression->FolderPath);
|
||||
ImGui::EndChild();
|
||||
ShowExpressionContextMenu(expression, 0);
|
||||
}
|
||||
|
@ -89,16 +106,12 @@ void OpenEyeSelector(Expression* expression) {
|
|||
/* Creates a nested expression selection menu for a model; Contains dropdown OR checkbox widgets */
|
||||
void OpenExpressionSelector() {
|
||||
if (custom_eyes_enabled) {
|
||||
// Vanilla Eye Selector
|
||||
if (current_model.UsingVanillaEyes())
|
||||
OpenEyeSelector(&VanillaEyes);
|
||||
else {
|
||||
// Model Eye Selector
|
||||
if (current_model.Expressions[0].Name == "eyes")
|
||||
OpenEyeSelector(¤t_model.Expressions[0]);
|
||||
}
|
||||
if (current_model.Expressions.size() > 0 && current_model.CustomEyeSupport)
|
||||
// Model Eye Selector
|
||||
OpenEyeSelector(¤t_model.Expressions[0]);
|
||||
}
|
||||
|
||||
if (!current_model.Active) return;
|
||||
if (current_model.Expressions.size() > 1) {
|
||||
// Other Expressions
|
||||
if (current_model.Expressions.size() > 8) ImGui::BeginChild(("###menu_exp_model"), ImVec2(200, 190), false, ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_AlwaysAutoResize);
|
||||
|
@ -128,15 +141,7 @@ void OpenExpressionSelector() {
|
|||
} else {
|
||||
// Use dropdown
|
||||
if (ImGui::BeginCombo(label_name.c_str(), current_model.Expressions[i].Textures[current_model.Expressions[i].CurrentIndex].FileName.c_str(), ImGuiComboFlags_None)) {
|
||||
for (int n = 0; n < current_model.Expressions[i].Textures.size(); n++) {
|
||||
bool is_selected = (current_model.Expressions[i].CurrentIndex == n);
|
||||
std::string entry_name = current_model.Expressions[i].Textures[n].FileName;
|
||||
|
||||
if (ImGui::Selectable(entry_name.c_str(), is_selected)) {
|
||||
//gfx_precache_textures();
|
||||
current_model.Expressions[i].CurrentIndex = n;
|
||||
}
|
||||
}
|
||||
RecursiveSelector(¤t_model.Expressions[i], 0, current_model.Expressions[i].FolderPath);
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ShowExpressionContextMenu(¤t_model.Expressions[i], i);
|
||||
|
|
|
@ -6171,7 +6171,7 @@ void ImGui::TreePop()
|
|||
}
|
||||
window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1;
|
||||
|
||||
IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much.
|
||||
//IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much.
|
||||
PopID();
|
||||
}
|
||||
|
||||
|
|
|
@ -129,7 +129,9 @@ Model LoadModelData(std::string folderPath) {
|
|||
// Enabled by default, but authors can optionally disable the feature
|
||||
// If disabled, the "Custom Eyes" checkbox will be hidden from the menu
|
||||
if (root.isMember("eye_support"))
|
||||
model.CustomEyeSupport = root["eye_support"].asBool();
|
||||
model.CustomEyeSupport = root["eye_support"].asBool() && fs::is_directory(folderPath + "/expressions");
|
||||
if (!model.CustomEyeSupport) custom_eyes_enabled = false;
|
||||
|
||||
// EXPERIMENTAL: Custom Blink Cycle (optional)
|
||||
if (root.isMember("custom_blink_cycle"))
|
||||
model.CustomBlinkCycle = root["custom_blink_cycle"].asBool();
|
||||
|
|
|
@ -33,8 +33,9 @@ class Model {
|
|||
// Always enabled for non-model Mario
|
||||
if (this->DynOSId == -1) return (true);
|
||||
else {
|
||||
if (!std::filesystem::is_directory(this->FolderPath + "/expressions/eyes"))
|
||||
return (this->Active && this->CustomEyeSupport);
|
||||
if (!std::filesystem::is_directory(this->FolderPath + "/expressions/eyes") &&
|
||||
!std::filesystem::is_directory(this->FolderPath + "/expressions/eye"))
|
||||
return (this->Active && this->CustomEyeSupport);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -78,6 +79,10 @@ class Model {
|
|||
|
||||
return this->FolderName;
|
||||
}
|
||||
|
||||
Model() {
|
||||
LoadEyesFolder();
|
||||
}
|
||||
};
|
||||
|
||||
extern int current_model_id;
|
||||
|
|
|
@ -42,39 +42,35 @@ namespace fs = std::filesystem;
|
|||
bool custom_eyes_enabled;
|
||||
bool show_vmario_emblem;
|
||||
|
||||
Expression VanillaEyes;
|
||||
/* Loads textures from dynos/eyes/ into a global Expression */
|
||||
void LoadEyesFolder() {
|
||||
// Check if the dynos/eyes/ folder exists
|
||||
if (fs::is_directory("dynos/eyes")) {
|
||||
/* Loads subfolders into an expression */
|
||||
std::vector<TexturePath> LoadExpressionFolders(Expression expression) {
|
||||
std::vector<TexturePath> folders;
|
||||
|
||||
VanillaEyes.Name = "eyes";
|
||||
VanillaEyes.FolderPath = "dynos/eyes";
|
||||
|
||||
// Load Textures
|
||||
for (const auto & entry : fs::directory_iterator("dynos/eyes")) {
|
||||
// Only allow PNG files
|
||||
if (entry.path().extension() == ".png") {
|
||||
TexturePath texture;
|
||||
texture.FileName = entry.path().filename().generic_u8string();
|
||||
texture.FilePath = entry.path().generic_u8string();
|
||||
VanillaEyes.Textures.push_back(texture);
|
||||
// Check if the expression's folder exists
|
||||
if (fs::is_directory(fs::path(expression.FolderPath))) {
|
||||
for (const auto & entry : fs::recursive_directory_iterator(expression.FolderPath)) {
|
||||
if (fs::is_directory(entry.path())) {
|
||||
// Only allow PNG files
|
||||
TexturePath folder;
|
||||
folder.FileName = entry.path().filename().generic_u8string();
|
||||
folder.FilePath = entry.path().generic_u8string();
|
||||
folders.push_back(folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
return folders;
|
||||
}
|
||||
|
||||
|
||||
/* Loads textures into an expression */
|
||||
std::vector<TexturePath> LoadExpressionTextures(Expression expression) {
|
||||
std::vector<TexturePath> textures;
|
||||
|
||||
// Check if the expression's folder exists
|
||||
if (fs::is_directory(fs::path(expression.FolderPath))) {
|
||||
for (const auto & entry : fs::directory_iterator(expression.FolderPath)) {
|
||||
for (const auto & entry : fs::recursive_directory_iterator(expression.FolderPath)) {
|
||||
if (!fs::is_directory(entry.path())) {
|
||||
// Only allow PNG files
|
||||
if (entry.path().extension() == ".png") {
|
||||
// Only allow PNG files
|
||||
TexturePath texture;
|
||||
texture.FileName = entry.path().filename().generic_u8string();
|
||||
texture.FilePath = entry.path().generic_u8string();
|
||||
|
@ -95,15 +91,15 @@ std::vector<Expression> LoadExpressions(std::string modelFolderPath) {
|
|||
for (const auto & entry : fs::directory_iterator(modelFolderPath + "/expressions")) {
|
||||
// Load individual expression folders
|
||||
if (fs::is_directory(entry.path())) {
|
||||
|
||||
Expression expression;
|
||||
expression.FolderPath = entry.path().generic_u8string();
|
||||
expression.Name = entry.path().filename().generic_u8string();
|
||||
if (expression.Name == "eye")
|
||||
expression.Name = "eyes";
|
||||
|
||||
expression.FolderPath = entry.path().generic_u8string();
|
||||
// Load all PNG files
|
||||
expression.Textures = LoadExpressionTextures(expression);
|
||||
expression.Folders = LoadExpressionFolders(expression);
|
||||
|
||||
// Eyes will always appear first
|
||||
if (expression.Name == "eyes") {
|
||||
|
@ -113,11 +109,28 @@ std::vector<Expression> LoadExpressions(std::string modelFolderPath) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no eyes folder was loaded, load from vanilla eyes
|
||||
if (current_model.UsingVanillaEyes())
|
||||
expressions_list.insert(expressions_list.begin(), VanillaEyes);
|
||||
}
|
||||
|
||||
return expressions_list;
|
||||
}
|
||||
|
||||
Expression VanillaEyes;
|
||||
/* Loads textures from dynos/eyes/ into a global Expression */
|
||||
void LoadEyesFolder() {
|
||||
// Check if the dynos/eyes/ folder exists
|
||||
if (fs::is_directory("dynos/eyes")) {
|
||||
VanillaEyes.Name = "eyes";
|
||||
VanillaEyes.FolderPath = "dynos/eyes";
|
||||
VanillaEyes.Textures = LoadExpressionTextures(VanillaEyes);
|
||||
VanillaEyes.Folders = LoadExpressionFolders(VanillaEyes);
|
||||
}
|
||||
current_model.Expressions.insert(current_model.Expressions.begin(), VanillaEyes);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string*> heap_strs = {};
|
||||
std::string* stack_to_heap(std::string str) {
|
||||
if (heap_strs.find(str) == heap_strs.end()) heap_strs.insert({ str, new std::string(str) });
|
||||
|
@ -151,14 +164,14 @@ const void* saturn_bind_texture(const void* input) {
|
|||
}
|
||||
|
||||
// Vanilla eye textures
|
||||
if (custom_eyes_enabled && current_model.UsingVanillaEyes() && VanillaEyes.Textures.size() > 0) {
|
||||
if (custom_eyes_enabled && current_model.UsingVanillaEyes() && current_model.Expressions[0].Textures.size() > 0) {
|
||||
if (texName.find("saturn_eye") != string::npos ||
|
||||
// Unused vanilla textures
|
||||
texName == "actors/mario/mario_eyes_left_unused.rgba16.png" ||
|
||||
texName == "actors/mario/mario_eyes_right_unused.rgba16.png" ||
|
||||
texName == "actors/mario/mario_eyes_up_unused.rgba16.png" ||
|
||||
texName == "actors/mario/mario_eyes_down_unused.rgba16.png") {
|
||||
outputTexture = stack_to_heap(VanillaEyes.Textures[VanillaEyes.CurrentIndex].GetRelativePath())->c_str();
|
||||
outputTexture = stack_to_heap(current_model.Expressions[0].Textures[current_model.Expressions[0].CurrentIndex].GetRelativePath())->c_str();
|
||||
const void* output = static_cast<const void*>(outputTexture);
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,21 @@ public:
|
|||
std::string GetRelativePath() {
|
||||
return "../../" + this->FilePath;//.substr(0, this->FilePath.size() - 4);
|
||||
}
|
||||
|
||||
/* Returns true if the entry is a subfolder */
|
||||
bool IsFolder() {
|
||||
return this->FileName.find(".png") == std::string::npos;
|
||||
}
|
||||
/* Returns a subfolder file count, or texture length */
|
||||
int Size() {
|
||||
if (this->IsFolder())
|
||||
return std::distance(std::filesystem::directory_iterator(this->FilePath), std::filesystem::directory_iterator{}) - 1;
|
||||
else
|
||||
return FilePath.length();
|
||||
}
|
||||
std::string ParentPath() {
|
||||
return FilePath.substr(0, this->FilePath.length() - this->FileName.length());
|
||||
}
|
||||
};
|
||||
|
||||
class Expression {
|
||||
|
@ -30,6 +45,7 @@ public:
|
|||
std::string Name;
|
||||
std::string FolderPath;
|
||||
std::vector<TexturePath> Textures;
|
||||
std::vector<TexturePath> Folders;
|
||||
/* The index of the current selected texture */
|
||||
int CurrentIndex = 0;
|
||||
|
||||
|
@ -49,6 +65,7 @@ extern Expression VanillaEyes;
|
|||
extern void LoadEyesFolder();
|
||||
|
||||
std::vector<TexturePath> LoadExpressionTextures(Expression);
|
||||
std::vector<TexturePath> LoadExpressionFolders(Expression);
|
||||
std::vector<Expression> LoadExpressions(std::string);
|
||||
|
||||
void saturn_copy_file(std::string from, std::string to);
|
||||
|
|
Loading…
Reference in a new issue