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