From cb13df65c163b58f5d3625eb1f2bd2b8d3fbdc9c Mon Sep 17 00:00:00 2001 From: Tokeiburu Date: Sun, 16 Jun 2024 16:46:30 -0400 Subject: [PATCH] - Adding a new effect (974) will display a default one instead of having empty fields (so it will show something). - Editing the texture path of an effect will update it in the editor. - Added a drawing square around the effect particles when it's selected and holding shift. - Fixed a bug when editing multi fields and clicking on another field afterward, resulting in the event stack not being in the correct order. - Added basic support for RSW version 0x207. --- BrowEdit3.vcxproj | 2 + BrowEdit3.vcxproj.filters | 6 ++ browedit/actions/LubChangeTextureAction.cpp | 1 + browedit/actions/LubChangeTextureAction.h | 36 ++++++++++ browedit/components/LubRenderer.cpp | 28 +++++++- browedit/components/LubRenderer.h | 4 ++ browedit/components/Rsw.Effect.cpp | 8 +-- browedit/components/Rsw.Model.cpp | 16 ++++- browedit/components/Rsw.cpp | 25 +++++++ browedit/components/Rsw.h | 1 + browedit/util/Util.cpp | 79 +++++++++++++++++++-- browedit/util/Util.h | 3 + browedit/windows/ObjectSelectWindow.cpp | 24 +++++++ data/shaders/lub.fs | 17 +++-- 14 files changed, 231 insertions(+), 19 deletions(-) create mode 100644 browedit/actions/LubChangeTextureAction.cpp create mode 100644 browedit/actions/LubChangeTextureAction.h diff --git a/BrowEdit3.vcxproj b/BrowEdit3.vcxproj index 0bb820b..a597773 100644 --- a/BrowEdit3.vcxproj +++ b/BrowEdit3.vcxproj @@ -19,6 +19,7 @@ + @@ -144,6 +145,7 @@ + diff --git a/BrowEdit3.vcxproj.filters b/BrowEdit3.vcxproj.filters index d16312a..1e96a1e 100644 --- a/BrowEdit3.vcxproj.filters +++ b/BrowEdit3.vcxproj.filters @@ -427,6 +427,9 @@ browedit\actions + + browedit\actions + @@ -735,6 +738,9 @@ browedit\actions + + browedit\actions + diff --git a/browedit/actions/LubChangeTextureAction.cpp b/browedit/actions/LubChangeTextureAction.cpp new file mode 100644 index 0000000..7bdacfc --- /dev/null +++ b/browedit/actions/LubChangeTextureAction.cpp @@ -0,0 +1 @@ +#include "LubChangeTextureAction.h" diff --git a/browedit/actions/LubChangeTextureAction.h b/browedit/actions/LubChangeTextureAction.h new file mode 100644 index 0000000..48e1b39 --- /dev/null +++ b/browedit/actions/LubChangeTextureAction.h @@ -0,0 +1,36 @@ +#pragma once + +#include "Action.h" +#include +#include +#include +#include + +class LubChangeTextureAction : public Action +{ + std::string oldValue; + std::string newValue; + LubEffect* lubEffect; +public: + LubChangeTextureAction(LubEffect *lubEffect, std::string oldValue, std::string newValue) + { + this->lubEffect = lubEffect; + this->oldValue = oldValue; + this->newValue = newValue; + } + + virtual void perform(Map* map, BrowEdit* browEdit) + { + this->lubEffect->texture = newValue; + this->lubEffect->dirty = true; + } + virtual void undo(Map* map, BrowEdit* browEdit) + { + this->lubEffect->texture = oldValue; + this->lubEffect->dirty = true; + } + virtual std::string str() + { + return "Texture changed to " + newValue; + }; +}; \ No newline at end of file diff --git a/browedit/components/LubRenderer.cpp b/browedit/components/LubRenderer.cpp index c2f6517..d598598 100644 --- a/browedit/components/LubRenderer.cpp +++ b/browedit/components/LubRenderer.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,9 @@ void LubRenderer::render() rswObject = node->getComponent(); if (!gnd) gnd = node->root->getComponent(); - if (!lubEffect || dirty) + if (!billboardRenderer) + billboardRenderer = node->getComponent(); + if (!lubEffect || dirty || lubEffect->dirty) { lubEffect = node->getComponent(); dirty = false; @@ -60,6 +63,9 @@ void LubRenderer::render() } else texture = nullptr; + + if (lubEffect) + lubEffect->dirty = false; } if (!rswObject || !lubEffect || !gnd) return; @@ -164,10 +170,28 @@ void LubRenderer::render() shader->setUniform(LubShader::Uniforms::modelMatrix, modelMatrixSub); glDrawArrays(GL_QUADS, 4 * i, 4); } - + glDepthMask(1); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_DEPTH_TEST); + + if (ImGui::GetIO().KeyShift && billboardRenderer != nullptr && billboardRenderer->selected) { + glLineWidth(2.0f); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + shader->setUniform(LubShader::Uniforms::selection, true); + + for (int i = 0; i < particles.size(); i++) + { + Particle p = particles[i]; + glm::mat4 modelMatrixSub = modelMatrix; + modelMatrixSub[3] += glm::vec4(p.position.x, p.position.y, -p.position.z, 0.0f); + shader->setUniform(LubShader::Uniforms::modelMatrix, modelMatrixSub); + glDrawArrays(GL_QUADS, 4 * i, 4); + } + + shader->setUniform(LubShader::Uniforms::selection, false); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } } diff --git a/browedit/components/LubRenderer.h b/browedit/components/LubRenderer.h index 40503fc..3b58672 100644 --- a/browedit/components/LubRenderer.h +++ b/browedit/components/LubRenderer.h @@ -8,6 +8,7 @@ namespace gl { class Texture; } class RswObject; class Gnd; class LubEffect; +class BillboardRenderer; class LubRenderer : public Renderer { @@ -26,6 +27,7 @@ class LubRenderer : public Renderer s_texture, color, billboard_off, + selection, End }; }; @@ -37,12 +39,14 @@ class LubRenderer : public Renderer bindUniform(Uniforms::modelMatrix, "modelMatrix"); bindUniform(Uniforms::color, "color"); bindUniform(Uniforms::billboard_off, "billboard_off"); + bindUniform(Uniforms::selection, "selection"); } }; private: bool dirty = true; RswObject* rswObject = nullptr; LubEffect* lubEffect = nullptr; + BillboardRenderer* billboardRenderer = nullptr; gl::Texture* texture = nullptr; diff --git a/browedit/components/Rsw.Effect.cpp b/browedit/components/Rsw.Effect.cpp index ed50fa1..3d134c3 100644 --- a/browedit/components/Rsw.Effect.cpp +++ b/browedit/components/Rsw.Effect.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -180,10 +181,9 @@ void LubEffect::buildImGuiMulti(BrowEdit* browEdit, const std::vector& no util::DragFloat2Multi(browEdit, browEdit->activeMapView->map, lubEffects, "rate", [](LubEffect* e) {return &e->rate; }, 0.1f, 0, 0); util::DragFloat2Multi(browEdit, browEdit->activeMapView->map, lubEffects, "size", [](LubEffect* e) {return &e->size; }, 0.1f, 0, 0); util::DragFloat2Multi(browEdit, browEdit->activeMapView->map, lubEffects, "life", [](LubEffect* e) {return &e->life; }, 0.1f, 0, 0); - if (util::InputTextMulti(browEdit, browEdit->activeMapView->map, lubEffects, "texture", [](LubEffect* e) {return &e->texture; })) - { - - } + util::InputTextMulti(browEdit, browEdit->activeMapView->map, lubEffects, "texture", [](LubEffect* e) {return &e->texture;}, [&](Node* node, std::string* ptr, std::string* startValue, const std::string& action) { + browEdit->activeMapView->map->doAction(new LubChangeTextureAction(node->getComponent(), *startValue, *ptr), browEdit); + }); util::DragFloatMulti(browEdit, browEdit->activeMapView->map, lubEffects, "speed", [](LubEffect* e) {return &e->speed; }, 0.1f, 0, 0); util::DragIntMulti(browEdit, browEdit->activeMapView->map, lubEffects, "srcmode", [](LubEffect* e) {return &e->srcmode; }, 1, 0, 0); util::DragIntMulti(browEdit, browEdit->activeMapView->map, lubEffects, "destmode", [](LubEffect* e) {return &e->destmode; }, 1, 0, 20); diff --git a/browedit/components/Rsw.Model.cpp b/browedit/components/Rsw.Model.cpp index fefd20d..59f16d2 100644 --- a/browedit/components/Rsw.Model.cpp +++ b/browedit/components/Rsw.Model.cpp @@ -27,11 +27,18 @@ void RswModel::load(std::istream* is, int version, unsigned char buildNumber, bo is->read(reinterpret_cast(&animSpeed), sizeof(float)); is->read(reinterpret_cast(&blockType), sizeof(int)); } - if (version >= 0x0206 && buildNumber >= 186) + if (version >= 0x206 && buildNumber >= 186) { unsigned char c = is->get(); // unknown, 0? } + if (version >= 0x207) + { + // Tokei: No idea what this is for + int unknown; + is->read(reinterpret_cast(&unknown), sizeof(int)); + } + std::string fileNameRaw = util::FileIO::readString(is, 80); //std::cout << "Model: " << node->name << "\t" << fileNameRaw << std::endl; fileName = util::iso_8859_1_to_utf8(fileNameRaw); @@ -77,6 +84,13 @@ void RswModel::save(std::ofstream& file, int version, int buildNumber) if (version >= 0x206 && buildNumber >= 186) { file.put(0); // ?? } + + if (version >= 0x207) + { + // Tokei: No idea what this is for + int unknown = -1; + file.write(reinterpret_cast(&unknown), sizeof(int)); + } } util::FileIO::writeString(file, util::utf8_to_iso_8859_1(fileName), 80); util::FileIO::writeString(file, util::utf8_to_iso_8859_1(objectName), 80); //unknown diff --git a/browedit/components/Rsw.cpp b/browedit/components/Rsw.cpp index 928bfc0..33ed826 100644 --- a/browedit/components/Rsw.cpp +++ b/browedit/components/Rsw.cpp @@ -348,6 +348,18 @@ void Rsw::load(const std::string& fileName, Map* map, BrowEdit* browEdit, bool l unknown[1] = unknown[3] = 500; } + // Tokei: Not sure what this is meant for + if (version >= 0x207) + { + int unknownCount; + file->read(reinterpret_cast(&unknownCount), sizeof(int)); + + for (int i = 0; i < unknownCount; i++) { + int unknownValue; + file->read(reinterpret_cast(&unknownValue), sizeof(int)); + } + } + int objectCount; file->read(reinterpret_cast(&objectCount), sizeof(int)); std::cout << "RSW: Loading " << objectCount << " objects" << std::endl; @@ -549,6 +561,13 @@ void Rsw::save(const std::string& fileName, BrowEdit* browEdit) file.write(reinterpret_cast(&unknown[3]), sizeof(int)); } + // Tokei: Not sure what this is meant for; fill it with 0 for now + if (version >= 0x207) + { + int unknownCount = 0; + file.write(reinterpret_cast(&unknownCount), sizeof(int)); + } + std::vector objects; node->traverse([&objects](Node* n) { @@ -756,6 +775,12 @@ void Rsw::buildImGui(BrowEdit* browEdit) version = 0x0203; if (ImGui::Selectable("0204", version == 0x0204)) version = 0x0204; + if (ImGui::Selectable("0205", version == 0x0205)) + version = 0x0205; + if (ImGui::Selectable("0206", version == 0x0206)) + version = 0x0206; + if (ImGui::Selectable("0207", version == 0x0207)) + version = 0x0207; ImGui::EndCombo(); } diff --git a/browedit/components/Rsw.h b/browedit/components/Rsw.h index 3849476..89db5fb 100644 --- a/browedit/components/Rsw.h +++ b/browedit/components/Rsw.h @@ -272,6 +272,7 @@ class LubEffect : public Component int zenable; int billboard_off; glm::vec3 rotate_angle; // v3 + bool dirty; void load(const nlohmann::json& data); static void buildImGuiMulti(BrowEdit* browEdit, const std::vector&); diff --git a/browedit/util/Util.cpp b/browedit/util/Util.cpp index 2f01f0e..0116089 100644 --- a/browedit/util/Util.cpp +++ b/browedit/util/Util.cpp @@ -451,6 +451,73 @@ namespace util } + template + bool InputTextMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, const std::function& editAction) + { + static std::vector startValues; + bool differentValues = !std::all_of(data.begin(), data.end(), [&](T* o) { return *getProp(o) == *getProp(data.front()); }); + std::string f = *getProp(data.front()); + if (differentValues) + f = "multiple"; + bool ret = ImGui::InputText(label, &f); + if (ret) + for (auto o : data) + *getProp(o) = f; + if (ImGui::IsItemActivated()) + { + startValues.clear(); + for (auto o : data) + startValues.push_back(*getProp(o)); + } + if (ImGui::IsItemDeactivatedAfterEdit()) + { + auto ga = new GroupAction(); + for (auto i = 0; i < data.size(); i++) + editAction(data[i]->node, getProp(data[i]), &startValues[i], label); + map->doAction(ga, browEdit); + } + if (!differentValues) + { + ImGui::PushID(label); + if (ImGui::BeginPopupContextItem("CopyPaste")) + { + try { + if (ImGui::MenuItem("Copy")) + { + ImGui::SetClipboardText(getProp(data[0])->c_str()); + } + if (ImGui::MenuItem("Paste")) + { + auto cb = ImGui::GetClipboardText(); + if (cb) + { + startValues.clear(); + for (auto o : data) + { + startValues.push_back(*getProp(o)); + *getProp(o) = cb; + } + auto ga = new GroupAction(); + for (auto i = 0; i < data.size(); i++) + editAction(data[i]->node, getProp(data[i]), &startValues[i], label); + ret = true; + } + } + } + catch (...) {} + ImGui::EndPopup(); + } + ImGui::PopID(); + } + return ret; + } + template bool InputTextMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, const std::function& editAction); + template bool InputTextMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, const std::function& editAction); + template bool InputTextMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, const std::function& editAction); + template bool InputTextMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, const std::function& editAction); + template bool InputTextMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, const std::function& editAction); + template bool InputTextMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, const std::function& editAction); + template bool InputTextMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp) { @@ -774,12 +841,6 @@ namespace util else if ((*f)[0] == (*f)[2]) (*f)[2] = (*f)[0] = (*f)[1]; } - if (ImGui::IsItemActivated()) - { - startValues.clear(); - for (auto o : data) - startValues.push_back(*getProp(o)); - } if (ret) { for (auto o : data) @@ -799,6 +860,12 @@ namespace util ga->addAction(new ObjectChangeAction(data[i]->node, getProp(data[i]), startValues[i], label)); map->doAction(ga, browEdit); } + if (ImGui::IsItemActivated()) + { + startValues.clear(); + for (auto o : data) + startValues.push_back(*getProp(o)); + } if (!differentValues) { ImGui::PushID(label); diff --git a/browedit/util/Util.h b/browedit/util/Util.h index 9506b6e..b726bed 100644 --- a/browedit/util/Util.h +++ b/browedit/util/Util.h @@ -52,6 +52,9 @@ namespace util bool InputText(BrowEdit* browEdit, Map* map, Node* node, const char* label, std::string* ptr, ImGuiInputTextFlags flags = 0, const std::string& action = ""); bool Checkbox(BrowEdit* browEdit, Map* map, Node* node, const char* label, bool* ptr, const std::string& action = ""); + template + bool InputTextMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp, const std::function& editAction); + template bool InputTextMulti(BrowEdit* browEdit, Map* map, const std::vector& data, const char* label, const std::function& getProp); diff --git a/browedit/windows/ObjectSelectWindow.cpp b/browedit/windows/ObjectSelectWindow.cpp index 6cd99ba..5c1752d 100644 --- a/browedit/windows/ObjectSelectWindow.cpp +++ b/browedit/windows/ObjectSelectWindow.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -356,6 +357,29 @@ void BrowEdit::showObjectWindow() newNode->addComponent(e); newNode->addComponent(new BillboardRenderer("data\\effect.png", "data\\effect_selected.png")); newNode->addComponent(new CubeCollider(5)); + + // Tokei: Effect 974 needs to have an LubEffect component attached + // This could be made in the json directly, but it will break if the lub effect + // properties are changed (which is somewhat often), so it's done in the source instead. + if (e->id == 974) { + auto lubEffect = new LubEffect(); + newNode->addComponent(lubEffect); + // Add dummy data to show something + lubEffect->texture = "smoke2.bmp"; + lubEffect->gravity = glm::vec3(0, -5, 0); + lubEffect->color = glm::vec4(1); + lubEffect->rate = glm::vec2(5, 15); + lubEffect->size = glm::vec2(3, 8); + lubEffect->life = glm::vec2(1, 5); + lubEffect->speed = 0.5f; + lubEffect->srcmode = 10; + lubEffect->destmode = 2; + lubEffect->maxcount = 30; + lubEffect->zenable = 1; + + newNode->addComponent(new LubRenderer()); + } + newNodes.push_back(std::pair(newNode, glm::vec3(0, 0, 0))); newNodesCenter = glm::vec3(0, 0, 0); newNodeHeight = false; diff --git a/data/shaders/lub.fs b/data/shaders/lub.fs index 888168b..6e11345 100644 --- a/data/shaders/lub.fs +++ b/data/shaders/lub.fs @@ -5,13 +5,18 @@ uniform vec4 color = vec4(1,1,1,1); in vec2 texCoord; in float alpha; out vec4 fragColor; - - +uniform bool selection; +uniform vec4 selectionColor = vec4(1,1,0.5,0.8f); void main() { - vec4 outColor = texture2D(s_texture, texCoord); - outColor *= color; - outColor.a *= alpha; - fragColor = outColor; + if (selection) { + fragColor = selectionColor; + } + else { + vec4 outColor = texture2D(s_texture, texCoord); + outColor *= color; + outColor.a *= alpha; + fragColor = outColor; + } } \ No newline at end of file