982 lines
38 KiB
C++
982 lines
38 KiB
C++
#include "ElementDrawer.hpp"
|
|
#include "BehaviourScriptRegistry.hpp"
|
|
#include "elements/ShaderRegistry.hpp"
|
|
#include "BehaviourScripts/Camera.hpp"
|
|
#include <algorithm>
|
|
|
|
namespace TSE::EDITOR
|
|
{
|
|
#pragma region helper
|
|
bool InputText(const char* label, std::string& str, size_t bufferSize = 256) {
|
|
std::vector<char> buffer(bufferSize);
|
|
strncpy(buffer.data(), str.c_str(), bufferSize);
|
|
buffer[bufferSize - 1] = '\0';
|
|
|
|
bool changed = ImGui::InputText(label, buffer.data(), bufferSize);
|
|
if (changed) {
|
|
str = std::string(buffer.data());
|
|
}
|
|
return changed;
|
|
}
|
|
void BeginList(std::string listName)
|
|
{
|
|
ImGui::BeginChild(listName.c_str(), {0,150}, ImGuiChildFlags_Borders);
|
|
}
|
|
bool ListAddBtn(std::string label = "Add")
|
|
{
|
|
float available_width = ImGui::GetContentRegionAvail().x;
|
|
return ImGui::Button(label.c_str(),{available_width, 0});
|
|
}
|
|
void BeginListItem(std::string name, float customHeight = 20)
|
|
{
|
|
float available_width = ImGui::GetContentRegionAvail().x;
|
|
ImGui::BeginChild(name.c_str(),{available_width - 30, customHeight});
|
|
}
|
|
void EndListItem()
|
|
{
|
|
ImGui::EndChild();
|
|
}
|
|
bool ListItemXBotton(std::string id)
|
|
{
|
|
ImGui::SameLine();
|
|
return ImGui::Button(id.c_str(), {20,0});
|
|
}
|
|
void EndList()
|
|
{
|
|
ImGui::EndChild();
|
|
}
|
|
#pragma endregion
|
|
|
|
void ElementDrawer::DrawAddDropdown(const std::vector<string>& options, string& selectedOption)
|
|
{
|
|
ImGuiStyle& style = ImGui::GetStyle();
|
|
float availableWidth = ImGui::GetContentRegionAvail().x;
|
|
|
|
// Add Button
|
|
if (ImGui::Button("Add", ImVec2(availableWidth, 0))) {
|
|
addDropdownOpen = !addDropdownOpen;
|
|
}
|
|
|
|
if (addDropdownOpen)
|
|
{
|
|
// Begin Popup
|
|
ImGui::BeginChild("##AddDropdownChild", ImVec2(availableWidth, 300), true);
|
|
|
|
// Suchfeld mit X Button
|
|
ImGui::PushItemWidth(-style.FramePadding.x * 4 - 24); // Platz für Clear Button
|
|
ImGui::InputTextWithHint("##SearchField", "Suchfeld", searchBuffer, IM_ARRAYSIZE(searchBuffer));
|
|
ImGui::PopItemWidth();
|
|
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("X")) {
|
|
searchBuffer[0] = '\0';
|
|
}
|
|
|
|
ImGui::Separator();
|
|
|
|
// Scrollbare Liste mit Filter
|
|
ImGui::BeginChild("##OptionsList", ImVec2(0, 250), false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
|
|
|
|
int count = 0;
|
|
for (const auto& option : options)
|
|
{
|
|
if (strlen(searchBuffer) == 0 || option.find(searchBuffer) != std::string::npos)
|
|
{
|
|
if (ImGui::Selectable(option.c_str()))
|
|
{
|
|
selectedOption = option;
|
|
addDropdownOpen = false;
|
|
break;
|
|
}
|
|
count++;
|
|
if (count >= 50) break; // Begrenze maximal gezeichnete Elemente zur Performance
|
|
}
|
|
}
|
|
|
|
ImGui::EndChild();
|
|
ImGui::EndChild();
|
|
}
|
|
}
|
|
void ElementDrawer::Draw(Transformable* element,const bool& debug) {
|
|
ImGui::SeparatorText("Transform");
|
|
ImGui::Checkbox("##checkbox", &element->_enabled);
|
|
ImGui::SameLine();
|
|
InputText("<-- Name##", element->name);
|
|
ImGui::DragFloat3("<-- Position", &element->position.x, 0.1f);
|
|
ImGui::DragFloat3("<--Scale", &element->scale.x, 0.1f);
|
|
Vector3 euler = element->GetEuler();
|
|
ImGui::DragFloat3("<-- Rotation", &(euler.x), 0.1f);
|
|
element->SetEuler(euler);
|
|
ImGui::Spacing();
|
|
if(debug)
|
|
{
|
|
|
|
ImGui::BeginDisabled();
|
|
ImGui::Text(("ID: " + to_string(element->id)).c_str());
|
|
ImGui::Text(("Child Count: " + std::to_string(element->GetChildren().size())).c_str());
|
|
ImGui::Text(("Component Count: " + std::to_string(element->GetComponentCount())).c_str());
|
|
ImGui::EndDisabled();
|
|
ImGui::Spacing();
|
|
}
|
|
if(element->GetComponentCount() > 0)
|
|
ImGui::SeparatorText("Components");
|
|
for (int i = 0; i < element->GetComponentCount(); i++)
|
|
{
|
|
Draw(element->GetBehaviourScriptAt(i), debug, i);
|
|
}
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
std::vector<std::string> behaviourScripts;
|
|
for (const auto& [name, _] : BehaviourScriptRegistry::GetRegistry())
|
|
{
|
|
behaviourScripts.push_back(name);
|
|
}
|
|
|
|
std::string selectedScript = "";
|
|
|
|
DrawAddDropdown(behaviourScripts, selectedScript);
|
|
|
|
if (!selectedScript.empty())
|
|
{
|
|
// Erzeuge das Script:
|
|
BehaviourScript* script = BehaviourScriptRegistry::CreateBehaviourScript(selectedScript);
|
|
if (script)
|
|
{
|
|
if(element->HasBehaviourScript(typeid(*script).name()))
|
|
{
|
|
delete script;
|
|
}
|
|
else
|
|
element->AddBehaviourScript(script);
|
|
}
|
|
selectedScript = ""; // Reset nach Hinzufügen
|
|
}
|
|
|
|
}
|
|
void ElementDrawer::Draw(Scene* element,const bool& debug) {
|
|
ImGui::Text("Scene Name: %s", element->GetName().c_str());
|
|
ImGui::Text("Layer Count: %d", element->GetLayerCount());
|
|
}
|
|
void ElementDrawer::Draw(Layer* element,const bool& debug) {
|
|
ImGui::Text("Layer Name: %s", element->GetName().c_str());
|
|
}
|
|
void ElementDrawer::Draw(BehaviourScript *element, const bool &debug, const int& id)
|
|
{
|
|
ImGui::PushID(("Script##" + std::to_string(id)).c_str());
|
|
std::string name = element->GetName();
|
|
if(ImGui::CollapsingHeader(name.c_str()))
|
|
{
|
|
bool enabled = element->IsEnabled();
|
|
ImGui::Checkbox("enabled", &enabled);
|
|
element->SetEnabled(enabled);
|
|
if(name == "Renderable")
|
|
{
|
|
Draw((Renderable*)element, debug);
|
|
}
|
|
else if (name == "Mesh Container")
|
|
{
|
|
Draw((MeshContainer*)element, debug);
|
|
}
|
|
else if (name == "Image")
|
|
{
|
|
Draw((Image*)element, debug);
|
|
}
|
|
else if (name == "Image Animation")
|
|
{
|
|
Draw((ImageAnimation*)element, debug);
|
|
}
|
|
else if (name == "Rect Base")
|
|
{
|
|
Draw((RectBase*)element, debug);
|
|
}
|
|
else if (name == "Camera")
|
|
{
|
|
Draw((Camera*)element, debug);
|
|
}
|
|
else if (name == "Particle System")
|
|
{
|
|
Draw((ParticleSystem*)element, debug);
|
|
}
|
|
else
|
|
{
|
|
element->CustomDraw(debug);
|
|
}
|
|
}
|
|
ImGui::PopID();
|
|
}
|
|
void ElementDrawer::Draw(Renderable *element, const bool &debug)
|
|
{
|
|
ImGui::SeparatorText("Material");
|
|
int height = 100;
|
|
if(element->GetMaterial() == nullptr)
|
|
{
|
|
height = 35;
|
|
}
|
|
ImVec2 size(0, height);
|
|
ImGui::BeginChild("MaterialViewer", size, ImGuiChildFlags_Borders);
|
|
Draw(element->GetMaterial(), debug);
|
|
ImGui::EndChild();
|
|
}
|
|
void ElementDrawer::Draw(MeshContainer *element, const bool &debug)
|
|
{
|
|
int height = ImGui::GetContentRegionAvail().x;
|
|
if(element->GetMesh() == nullptr)
|
|
{
|
|
height = 35;
|
|
}
|
|
ImVec2 size(0, height);
|
|
Draw(element->GetMesh(), debug, "Mesh", true);
|
|
}
|
|
void ElementDrawer::Draw(Image *element, const bool &debug)
|
|
{
|
|
int height = ImGui::GetContentRegionAvail().x + 50;
|
|
if(element->GetSpritePtr() == nullptr)
|
|
{
|
|
height = 35;
|
|
}
|
|
ImVec2 size(0, height);
|
|
ImGui::SeparatorText("Sprite");
|
|
Draw(element->GetSpritePtr(), debug, "Sprite", true);
|
|
}
|
|
void ElementDrawer::Draw(ImageAnimation *element, const bool &debug)
|
|
{
|
|
int currentSelection = -1;
|
|
int itemCount = element->GetImageAnimationSetCount();
|
|
std::vector<std::string> items;
|
|
for (int i = 0; i < itemCount; i++)
|
|
{
|
|
if(element->GetImageAnimationAt(i) == nullptr) continue;
|
|
items.push_back(element->GetImageAnimationAt(i)->Name);
|
|
if(element->GetImageAnimationAt(i)->Name == element->GetCurrentAnimation())
|
|
{
|
|
currentSelection = i;
|
|
}
|
|
}
|
|
auto getter = [](void* vec, int idx, const char** out_text) {
|
|
auto& vector = *static_cast<std::vector<std::string>*>(vec);
|
|
if (idx < 0 || idx >= static_cast<int>(vector.size())) return false;
|
|
*out_text = vector.at(idx).c_str();
|
|
return true;
|
|
};
|
|
if(ImGui::Combo("Active animation", ¤tSelection, getter, static_cast<void*>(&items), items.size()))
|
|
{
|
|
element->StartAnimation(items[currentSelection]);
|
|
}
|
|
items.clear();
|
|
for (int i = 0; i < itemCount; i++)
|
|
{
|
|
if(element->GetImageAnimationAt(i) == nullptr)
|
|
{
|
|
items.push_back("NULL");
|
|
continue;
|
|
}
|
|
items.push_back(element->GetImageAnimationAt(i)->Name);
|
|
}
|
|
ImGui::Text(("Frame: " + std::to_string(element->GetCurrentFrame())).c_str());
|
|
if(debug)
|
|
{
|
|
ImGui::TextDisabled(("DeltaTime: " + std::to_string(element->GetDeltaTime())).c_str());
|
|
}
|
|
ImGui::SeparatorText("Animation Sets");
|
|
BeginList("ImageAnimationSetList");
|
|
if(ListAddBtn() && (itemCount == 0 || items[itemCount - 1] != "NULL"))
|
|
{
|
|
element->SetAnimationSet("NULL", nullptr);
|
|
itemCount++;
|
|
items.push_back("NULL");
|
|
}
|
|
for (int i = 0; i < itemCount; i++)
|
|
{
|
|
BeginListItem("subcomponent##" + std::to_string(i));
|
|
Draw(element->GetImageAnimationAt(i),debug, items[i], true);
|
|
EndListItem();
|
|
if(ListItemXBotton("x##" + std::to_string(i)))
|
|
{
|
|
element->RemoveAnimationSet(items[i]);
|
|
itemCount--;
|
|
i--;
|
|
}
|
|
}
|
|
EndList();
|
|
}
|
|
void ElementDrawer::Draw(RectBase *element, const bool &debug)
|
|
{
|
|
ImGui::DragFloat2("Size", &element->size.x);
|
|
ImGui::Separator();
|
|
|
|
if (ImGui::TreeNode("Anchors"))
|
|
{
|
|
ImGui::Text("Min");
|
|
ImGui::DragFloat("X##anchor_min_x", &element->anchors.p1.x,0.2f);
|
|
ImGui::DragFloat("Y##anchor_min_y", &element->anchors.p1.y,0.2f);
|
|
|
|
ImGui::Text("Max");
|
|
ImGui::DragFloat("X##anchor_max_x", &element->anchors.p2.x,0.2f);
|
|
ImGui::DragFloat("Y##anchor_max_y", &element->anchors.p2.y,0.2f);
|
|
|
|
ImGui::TreePop();
|
|
}
|
|
|
|
ImGui::Text("Pivot");
|
|
ImGui::DragFloat("X##pivot_x", &element->pivit.x,0.2f);
|
|
ImGui::DragFloat("Y##pivot_y", &element->pivit.y,0.2f);
|
|
|
|
}
|
|
void ElementDrawer::Draw(Material *element, const bool &debug)
|
|
{
|
|
if(element == nullptr)
|
|
{
|
|
ImGui::TextDisabled("No material");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
InputText("Name", element->GetName());
|
|
|
|
int currentSelection = -1;
|
|
int itemCount = ShaderRegistry::GetShaderCount();
|
|
std::vector<std::string> items;
|
|
for (int i = 0; i < itemCount; i++)
|
|
{
|
|
if(ShaderRegistry::GetShaderAt(i) == nullptr) continue;
|
|
items.push_back(ShaderRegistry::GetNameAt(i));
|
|
if(ShaderRegistry::GetShaderAt(i) == element->GetShader())
|
|
{
|
|
currentSelection = i;
|
|
}
|
|
}
|
|
auto getter = [](void* vec, int idx, const char** out_text) {
|
|
auto& vector = *static_cast<std::vector<std::string>*>(vec);
|
|
if (idx < 0 || idx >= static_cast<int>(vector.size())) return false;
|
|
*out_text = vector.at(idx).c_str();
|
|
return true;
|
|
};
|
|
if(ImGui::Combo("Shader", ¤tSelection, getter, static_cast<void*>(&items), items.size()))
|
|
{
|
|
element->SetShader(ShaderRegistry::GetShader(items[currentSelection]));
|
|
}
|
|
if(debug)
|
|
ImGui::TextDisabled(to_string(element->GetID()).c_str());
|
|
ImGui::Separator();
|
|
int count = element->GetValueCount();
|
|
for(int i = 0; i < count; i++)
|
|
{
|
|
std::tuple<std::any, std::string, std::string> tupel = element->GetValueAt(i);
|
|
auto[ptr, type, name] = tupel;
|
|
if (type == typeid(int).name())
|
|
{
|
|
int value = element->GetValue<int>(name);
|
|
if(ImGui::InputInt(name.c_str(), &value))
|
|
{
|
|
element->SetValue(name, value);
|
|
}
|
|
}
|
|
else if (type == typeid(float).name())
|
|
{
|
|
float value = element->GetValue<float>(name);
|
|
if(ImGui::InputFloat(name.c_str(), &value))
|
|
{
|
|
element->SetValue(name, value);
|
|
}
|
|
}
|
|
else if (type == typeid(Vector2).name())
|
|
{
|
|
Vector2 value = element->GetValue<Vector2>(name);
|
|
if(ImGui::InputFloat2(name.c_str(), &value.x))
|
|
{
|
|
element->SetValue(name, value);
|
|
}
|
|
}
|
|
else if (type == typeid(Vector3).name())
|
|
{
|
|
Vector3 value = element->GetValue<Vector3>(name);
|
|
if(ImGui::InputFloat3(name.c_str(), &value.x))
|
|
{
|
|
element->SetValue(name, value);
|
|
}
|
|
}
|
|
else if (type == typeid(Vector4).name())
|
|
{
|
|
Vector4 value = element->GetValue<Vector4>(name);
|
|
if(ImGui::InputFloat4(name.c_str(), &value.x))
|
|
{
|
|
element->SetValue(name, value);
|
|
}
|
|
}
|
|
else if (type == typeid(Matrix4x4).name())
|
|
{
|
|
Matrix4x4 value = element->GetValue<Matrix4x4>(name);
|
|
//TODO: need to implement;
|
|
}
|
|
else if (type == typeid(Color).name())
|
|
{
|
|
Color value = element->GetValue<Color>(name);
|
|
if(ImGui::ColorEdit4(name.c_str(), &value.r))
|
|
{
|
|
element->SetValue(name, value);
|
|
}
|
|
}
|
|
else if (type == typeid(std::string).name())
|
|
{
|
|
Vector4 value = element->GetValue<Vector4>(name);
|
|
if(ImGui::InputFloat4(name.c_str(), &value.x))
|
|
{
|
|
element->SetValue(name, value);
|
|
}
|
|
}
|
|
else if (type == typeid(Texture*).name())
|
|
{
|
|
Texture* value = element->GetValue<Texture*>(name);
|
|
Draw(value, debug, name , true);
|
|
}
|
|
else
|
|
{
|
|
ImGui::TextDisabled(("Not Implemented: " + type).c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void ElementDrawer::Draw(Texture *element, const bool &debug, const std::string& label, const bool small)
|
|
{
|
|
if(element == nullptr)
|
|
{
|
|
ImGui::Text("No Texture Set");
|
|
return;
|
|
}
|
|
if(small) DrawTextureCompact(element, debug, label);
|
|
else DrawTextureNormal(element, debug, label);
|
|
}
|
|
void ElementDrawer::Draw(Sprite *element, const bool &debug, const std::string &label, const bool small)
|
|
{
|
|
if(element == nullptr)
|
|
{
|
|
ImGui::Text("No Sprite Set");
|
|
return;
|
|
}
|
|
if(small) DrawSpriteCompact(element, debug, label);
|
|
else DrawSpriteNormal(element, debug, label);
|
|
}
|
|
void ElementDrawer::Draw(Mesh *element, const bool &debug, const std::string &label, const bool small)
|
|
{
|
|
if(element == nullptr)
|
|
{
|
|
ImGui::Text("No Mesh Set");
|
|
return;
|
|
}
|
|
if(small) DrawMeshCompact(element, debug, label);
|
|
else DrawMeshNormal(element, debug, label);
|
|
}
|
|
void ElementDrawer::Draw(ImageAnimationSet *element, const bool &debug, const std::string &label, const bool small)
|
|
{
|
|
if(element == nullptr)
|
|
{
|
|
ImGui::Text("No Animation Set Asigned");
|
|
return;
|
|
}
|
|
if(small) DrawImageAnimationSetCompact(element, debug, label);
|
|
else DrawImageAnimationSetNormal(element, debug, label);
|
|
}
|
|
void ElementDrawer::Draw(Camera *element, const bool &debug)
|
|
{
|
|
const bool isMain = (Camera::mainCamera == element);
|
|
if (!isMain && element->baseObject->name != ".EditorCamera") {
|
|
if (ImGui::Button("Make Main Camera")) {
|
|
Camera::mainCamera = element;
|
|
}
|
|
} else if(element->baseObject->name != ".EditorCamera") {
|
|
ImGui::Text("This is the Main Camera");
|
|
}
|
|
else
|
|
{
|
|
ImGui::Text("Editor Camera can't be main camera");
|
|
}
|
|
|
|
ImGui::Separator();
|
|
// Render Scale
|
|
float renderScale = element->GetRenderScale();
|
|
if (ImGui::DragFloat("Render Scale", &renderScale, 0.1f))
|
|
element->SetRenderScale(renderScale);
|
|
|
|
ImGui::Separator();
|
|
|
|
// Projection
|
|
int projIndex = (element->GetProjection() == ProjectionType::Orthographic) ? 0 : 1;
|
|
const char* projItems[] = { "Orthographic", "Perspective" };
|
|
if (ImGui::Combo("Projection", &projIndex, projItems, IM_ARRAYSIZE(projItems)))
|
|
element->SetProjection(projIndex == 0 ? ProjectionType::Orthographic
|
|
: ProjectionType::Perspective);
|
|
|
|
// Clipping Planes
|
|
float nearCP = element->GetNearClippingPlane();
|
|
if (ImGui::DragFloat("Near Clipping Plane", &nearCP, 0.1f))
|
|
element->SetNearClippingPlane(nearCP);
|
|
|
|
float farCP = element->GetFarClippingPlane();
|
|
if (ImGui::DragFloat("Far Clipping Plane", &farCP, 0.1f))
|
|
element->SetFarClippingPlane(farCP);
|
|
|
|
// Field of View (only relevant for Perspective)
|
|
const bool isPerspective = (element->GetProjection() == ProjectionType::Perspective);
|
|
if (!isPerspective) ImGui::BeginDisabled();
|
|
float fov = element->GetFov();
|
|
if (ImGui::DragFloat("Field of View (deg)", &fov, 0.1f))
|
|
element->SetFov(fov);
|
|
if (!isPerspective) ImGui::EndDisabled();
|
|
}
|
|
void ElementDrawer::Draw(ParticleSystem *element, const bool &debug)
|
|
{
|
|
float indent = 15.0f;
|
|
auto OpeningAngleDeg = [](float conePlane) -> float {
|
|
float cosA = std::clamp(conePlane * 2.0f - 1.0f, -1.0f, 1.0f);
|
|
return std::acos(cosA) * (180.0f / TSE_PI);
|
|
};
|
|
auto ClampPositive = [](float& v, float minv = 0.0f) { if (v < minv) v = minv; };
|
|
|
|
// =========================
|
|
// MISC
|
|
// =========================
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + indent);
|
|
if (ImGui::CollapsingHeader("Misc", ImGuiTreeNodeFlags_DefaultOpen))
|
|
{
|
|
ImGui::Indent(20.0f);
|
|
|
|
int pc = static_cast<int>(element->particleCount);
|
|
if (ImGui::DragInt("Max Particles", &pc, 1.0f, 0, 100000)) {
|
|
if (pc < 0) pc = 0;
|
|
element->particleCount = static_cast<uint>(pc);
|
|
}
|
|
|
|
ImGui::Checkbox("Start with Simulated Particles", &element->startWithSimulatedParicles);
|
|
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Wenn aktiv, wird beim Start bereits ein gefüllter Partikelpuffer simuliert.");
|
|
|
|
ImGui::Unindent(20.0f);
|
|
ImGui::Separator();
|
|
}
|
|
|
|
// =========================
|
|
// START CONDITIONS
|
|
// =========================
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + indent);
|
|
if (ImGui::CollapsingHeader("Start Conditions", ImGuiTreeNodeFlags_DefaultOpen))
|
|
{
|
|
ImGui::Indent(20.0f);
|
|
|
|
if (ImGui::TreeNodeEx("Rotation (Start)", ImGuiTreeNodeFlags_DefaultOpen))
|
|
{
|
|
ImGui::Indent(16.0f);
|
|
|
|
ImGui::Checkbox("Random Rotation Direction", &element->startWithRandomRotationDirection);
|
|
if (!element->startWithRandomRotationDirection) {
|
|
int dirIdx = (element->rotationDirection >= 0.0f) ? 1 : 0;
|
|
const char* dirItems[] = { "-1 (CCW)", "+1 (CW)" };
|
|
if (ImGui::Combo("Rotation Direction", &dirIdx, dirItems, IM_ARRAYSIZE(dirItems))) {
|
|
element->rotationDirection = (dirIdx == 1) ? 1.0f : -1.0f;
|
|
}
|
|
} else {
|
|
ImGui::BeginDisabled();
|
|
float dummy = element->rotationDirection;
|
|
ImGui::InputFloat("Rotation Direction", &dummy);
|
|
ImGui::EndDisabled();
|
|
}
|
|
|
|
ImGui::Checkbox("Random Start Rotation", &element->startWithRandomRotation);
|
|
if (element->startWithRandomRotation) {
|
|
ImGui::DragFloat("Min Rotation (rad)", &element->minRotationRad, 0.01f);
|
|
ImGui::DragFloat("Max Rotation (rad)", &element->maxrotationRad, 0.01f);
|
|
if (element->maxrotationRad < element->minRotationRad) std::swap(element->minRotationRad, element->maxrotationRad);
|
|
} else {
|
|
ImGui::DragFloat("Start Rotation (rad)", &element->maxrotationRad, 0.01f);
|
|
ImGui::BeginDisabled(); ImGui::DragFloat("Min Rotation (rad)", &element->minRotationRad, 0.01f); ImGui::EndDisabled();
|
|
}
|
|
|
|
ImGui::Unindent(16.0f);
|
|
ImGui::TreePop();
|
|
}
|
|
|
|
if (ImGui::TreeNode("Size (Start)"))
|
|
{
|
|
ImGui::Indent(16.0f);
|
|
|
|
ImGui::Checkbox("Random Start Size", &element->startWithRandomSize);
|
|
if (element->startWithRandomSize) {
|
|
if (ImGui::DragFloat("Min Size", &element->minSize, 0.01f)) { ClampPositive(element->minSize, 0.0f); }
|
|
if (ImGui::DragFloat("Max Size", &element->maxSize, 0.01f)) { ClampPositive(element->maxSize, 0.0f); }
|
|
if (element->maxSize < element->minSize) std::swap(element->minSize, element->maxSize);
|
|
} else {
|
|
if (ImGui::DragFloat("Start Size", &element->maxSize, 0.01f)) { ClampPositive(element->maxSize, 0.0f); }
|
|
ImGui::BeginDisabled(); ImGui::DragFloat("Min Size", &element->minSize, 0.01f); ImGui::EndDisabled();
|
|
}
|
|
|
|
ImGui::Unindent(16.0f);
|
|
ImGui::TreePop();
|
|
}
|
|
|
|
if (ImGui::TreeNode("Lifetime (Start)"))
|
|
{
|
|
ImGui::Indent(16.0f);
|
|
|
|
ImGui::Checkbox("Random Start Lifetime", &element->startWithRandomLifetime);
|
|
if (element->startWithRandomLifetime) {
|
|
if (ImGui::DragFloat("Min Lifetime (s)", &element->minLifetime, 0.01f)) { ClampPositive(element->minLifetime, 0.0f); }
|
|
if (ImGui::DragFloat("Max Lifetime (s)", &element->maxLifetime, 0.01f)) { ClampPositive(element->maxLifetime, 0.0f); }
|
|
if (element->maxLifetime < element->minLifetime) std::swap(element->minLifetime, element->maxLifetime);
|
|
} else {
|
|
if (ImGui::DragFloat("Lifetime (s)", &element->maxLifetime, 0.01f)) { ClampPositive(element->maxLifetime, 0.0f); }
|
|
ImGui::BeginDisabled(); ImGui::DragFloat("Min Lifetime (s)", &element->minLifetime, 0.01f); ImGui::EndDisabled();
|
|
}
|
|
|
|
ImGui::Unindent(16.0f);
|
|
ImGui::TreePop();
|
|
}
|
|
|
|
ImGui::Unindent(20.0f);
|
|
ImGui::Separator();
|
|
}
|
|
|
|
// =========================
|
|
// LIFETIME CONDITIONS
|
|
// =========================
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + indent);
|
|
if (ImGui::CollapsingHeader("Lifetime Conditions", ImGuiTreeNodeFlags_DefaultOpen))
|
|
{
|
|
ImGui::Indent(20.0f);
|
|
|
|
if (ImGui::TreeNode("Color over Lifetime"))
|
|
{
|
|
ImGui::Indent(16.0f);
|
|
|
|
ImGui::Checkbox("Enable Color over Lifetime", &element->changeColorOverLifetime);
|
|
// Start immer editierbar
|
|
ImGui::ColorEdit4("Start Color", &element->startColor.r, ImGuiColorEditFlags_Float);
|
|
// End nur wenn aktiviert
|
|
if (!element->changeColorOverLifetime) ImGui::BeginDisabled();
|
|
ImGui::ColorEdit4("End Color", &element->endColor.r, ImGuiColorEditFlags_Float);
|
|
if (!element->changeColorOverLifetime) ImGui::EndDisabled();
|
|
|
|
ImGui::Unindent(16.0f);
|
|
ImGui::TreePop();
|
|
}
|
|
|
|
if (ImGui::TreeNode("Speed over Lifetime"))
|
|
{
|
|
ImGui::Indent(16.0f);
|
|
|
|
ImGui::Checkbox("Enable Speed over Lifetime", &element->changeSpeedOverLifetime);
|
|
// Start immer frei
|
|
ImGui::DragFloat("Start Speed", &element->startSpeed, 0.01f);
|
|
// End nur bei aktiv
|
|
if (!element->changeSpeedOverLifetime) ImGui::BeginDisabled();
|
|
ImGui::DragFloat("End Speed", &element->endSpeed, 0.01f);
|
|
if (!element->changeSpeedOverLifetime) ImGui::EndDisabled();
|
|
|
|
ImGui::Unindent(16.0f);
|
|
ImGui::TreePop();
|
|
}
|
|
|
|
if (ImGui::TreeNode("Rotation Speed over Lifetime"))
|
|
{
|
|
ImGui::Indent(16.0f);
|
|
|
|
ImGui::Checkbox("Enable RotationSpeed over Lifetime", &element->changeRotationspeedOverLifetime);
|
|
// Start immer frei
|
|
ImGui::DragFloat("Start RotSpeed", &element->startRotationSpeed, 0.01f);
|
|
// End nur bei aktiv
|
|
if (!element->changeRotationspeedOverLifetime) ImGui::BeginDisabled();
|
|
ImGui::DragFloat("End RotSpeed", &element->endRotationSpeed, 0.01f);
|
|
if (!element->changeRotationspeedOverLifetime) ImGui::EndDisabled();
|
|
|
|
ImGui::Unindent(16.0f);
|
|
ImGui::TreePop();
|
|
}
|
|
|
|
ImGui::Unindent(20.0f);
|
|
ImGui::Separator();
|
|
}
|
|
|
|
// =========================
|
|
// SPAWN AREA
|
|
// =========================
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + indent);
|
|
if (ImGui::CollapsingHeader("Spawn Area", ImGuiTreeNodeFlags_DefaultOpen))
|
|
{
|
|
ImGui::Indent(20.0f);
|
|
|
|
ImGui::DragFloat3("Offset (world)", &element->offset.x, 0.01f);
|
|
|
|
ImGui::DragFloat3("Forward", &element->forward.x, 0.01f);
|
|
ImGui::SameLine();
|
|
if (ImGui::SmallButton("Normalize##fwd")) {
|
|
element->forward.NormalizeSafe(Vector3::forward);
|
|
}
|
|
|
|
if (ImGui::DragFloat("Radius", &element->radius, 0.01f)) {
|
|
if (element->radius < 0.0f) element->radius = 0.0f;
|
|
}
|
|
|
|
if (ImGui::SliderFloat("Cone Plane", &element->conePlane, 0.0f, 1.0f, "%.3f")) {
|
|
element->conePlane = std::clamp(element->conePlane, 0.0f, 1.0f);
|
|
}
|
|
|
|
float angle = OpeningAngleDeg(element->conePlane);
|
|
ImGui::Text("Opening Angle: %.2f deg", angle);
|
|
|
|
const char* mode = "Forward Cone";
|
|
if (element->conePlane == 1.0f) mode = "Full Sphere";
|
|
else if (element->conePlane <= 0.5f) mode = "Forward Cone";
|
|
else mode = "Inverse Cone";
|
|
ImGui::Text("Mode (derived): %s", mode);
|
|
|
|
if (debug) {
|
|
ImGui::Separator();
|
|
ImGui::TextDisabled("Debug:");
|
|
ImGui::BulletText("Forward len^2: %.6f", element->forward.LengthSqr());
|
|
}
|
|
|
|
ImGui::Unindent(20.0f);
|
|
}
|
|
}
|
|
void ElementDrawer::DrawImageAnimationSetCompact(ImageAnimationSet *element, const bool &debug, const std::string &label)
|
|
{
|
|
float item_spacing = ImGui::GetStyle().ItemSpacing.x;
|
|
ImVec2 label_size = ImGui::CalcTextSize(label.c_str());
|
|
|
|
float available_width = ImGui::GetContentRegionAvail().x;
|
|
float field_width = available_width - label_size.x - item_spacing;
|
|
|
|
ImVec2 field_size = ImVec2(field_width, label_size.y + 4);
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_FrameBg)); // gleiche Farbe wie InputText
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, ImGui::GetStyle().FrameRounding);
|
|
|
|
ImGui::BeginChild("##FakeInput", field_size, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
|
|
|
ImGui::SetCursorPos(ImVec2(2, 2));
|
|
ImGui::TextUnformatted(element->Name.c_str());
|
|
|
|
ImGui::EndChild();
|
|
|
|
ImGui::PopStyleVar();
|
|
ImGui::PopStyleColor();
|
|
|
|
ImGui::SameLine();
|
|
ImVec2 cursorCurrent = ImGui::GetCursorPos();
|
|
cursorCurrent.y += 2;
|
|
ImGui::SetCursorPos(cursorCurrent);
|
|
ImGui::TextUnformatted(label.c_str());
|
|
}
|
|
void ElementDrawer::DrawImageAnimationSetNormal(ImageAnimationSet *element, const bool &debug, const std::string &label)
|
|
{
|
|
InputText("Name", element->Name);
|
|
ImGui::InputFloat("Frame Time", &element->frameTime);
|
|
ImGui::SeparatorText("Sprites");
|
|
BeginList("SpriteList");
|
|
if(ListAddBtn())
|
|
{
|
|
element->Sprites.push_back(nullptr);
|
|
}
|
|
auto it = element->Sprites.begin();
|
|
for (int i = 0; i < element->Sprites.size(); i++)
|
|
{
|
|
BeginListItem("subcomponent##" + std::to_string(i),65);
|
|
Draw(element->Sprites[i],debug, std::to_string(i), true);
|
|
EndListItem();
|
|
if(ListItemXBotton("x##" + std::to_string(i)))
|
|
{
|
|
auto it2 = it;
|
|
it--;
|
|
element->Sprites.erase(it2);
|
|
i--;
|
|
}
|
|
it++;
|
|
}
|
|
EndList();
|
|
}
|
|
void ElementDrawer::DrawMeshCompact(Mesh *element, const bool &debug, const std::string &label)
|
|
{
|
|
float item_spacing = ImGui::GetStyle().ItemSpacing.x;
|
|
ImVec2 label_size = ImGui::CalcTextSize(label.c_str());
|
|
|
|
float available_width = ImGui::GetContentRegionAvail().x;
|
|
float field_width = available_width - label_size.x - item_spacing;
|
|
|
|
ImVec2 field_size = ImVec2(field_width, label_size.y + 4);
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_FrameBg)); // gleiche Farbe wie InputText
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, ImGui::GetStyle().FrameRounding);
|
|
|
|
ImGui::BeginChild("##FakeInput", field_size, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
|
|
|
ImGui::SetCursorPos(ImVec2(2, 2));
|
|
ImGui::TextUnformatted(element->name.c_str());
|
|
|
|
ImGui::EndChild();
|
|
|
|
ImGui::PopStyleVar();
|
|
ImGui::PopStyleColor();
|
|
|
|
ImGui::SameLine();
|
|
ImVec2 cursorCurrent = ImGui::GetCursorPos();
|
|
cursorCurrent.y += 2;
|
|
ImGui::SetCursorPos(cursorCurrent);
|
|
ImGui::TextUnformatted(label.c_str());
|
|
}
|
|
void ElementDrawer::DrawMeshNormal(Mesh *element, const bool &debug, const std::string &label)
|
|
{
|
|
ImGui::Text(("Name: " + element->name).c_str());
|
|
if(debug)
|
|
{
|
|
//ImGui::TextDisabled(("ID: " + to_string(element->id)).c_str());
|
|
}
|
|
ImGui::Separator();
|
|
ImGui::Text(("Vectex Count: " + std::to_string(element->vertecies.size())).c_str());
|
|
ImGui::Text(("Index Count: " + std::to_string(element->indecies.size())).c_str());
|
|
ImGui::Text(("UV Count: " + std::to_string(element->uvs.size())).c_str());
|
|
ImGui::Indent(20.0f);
|
|
if(ImGui::CollapsingHeader("Vertecies"))
|
|
{
|
|
ImGui::PushID("Verts");
|
|
ImGui::BeginDisabled();
|
|
for (int i = 0; i < element->vertecies.size(); i++)
|
|
{
|
|
ImGui::InputFloat3(std::to_string(i).c_str(), &element->vertecies[i].x);
|
|
}
|
|
ImGui::EndDisabled();
|
|
ImGui::PopID();
|
|
}
|
|
if(ImGui::CollapsingHeader("Indecies"))
|
|
{
|
|
ImGui::PushID("Inds");
|
|
ImGui::BeginDisabled();
|
|
for (int i = 0; i < element->indecies.size(); i++)
|
|
{
|
|
int val = element->indecies[i];
|
|
ImGui::InputInt(std::to_string(i).c_str(), &val);
|
|
}
|
|
ImGui::EndDisabled();
|
|
ImGui::PopID();
|
|
}
|
|
if(ImGui::CollapsingHeader("UVs"))
|
|
{
|
|
ImGui::PushID("Uvs");
|
|
ImGui::BeginDisabled();
|
|
for (int i = 0; i < element->uvs.size(); i++)
|
|
{
|
|
ImGui::InputFloat2(std::to_string(i).c_str(), &element->uvs[i].x);
|
|
}
|
|
ImGui::EndDisabled();
|
|
ImGui::PopID();
|
|
}
|
|
ImGui::Unindent(20.0f);
|
|
|
|
}
|
|
void ElementDrawer::DrawSpriteCompact(Sprite *element, const bool &debug, const std::string &label)
|
|
{
|
|
float item_spacing = ImGui::GetStyle().ItemSpacing.x;
|
|
ImVec2 label_size = ImGui::CalcTextSize(label.c_str());
|
|
|
|
float available_width = ImGui::GetContentRegionAvail().x;
|
|
float field_width = available_width - label_size.x - item_spacing;
|
|
|
|
ImVec2 field_size = ImVec2(field_width, 60);
|
|
|
|
Rect r = element->GetUVRect();
|
|
float ymultiplyer = (element->GetTexture()->height() * r.height()) / (element->GetTexture()->width() * r.width());
|
|
|
|
ImVec2 texSize (field_size.y - 2, (field_size.y - 2) * ymultiplyer);
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_FrameBg)); // gleiche Farbe wie InputText
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, ImGui::GetStyle().FrameRounding);
|
|
|
|
ImGui::BeginChild("##FakeInput", field_size, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
|
|
|
ImGui::SetCursorPos(ImVec2(1,(60-texSize.y) / 2));
|
|
ImGui::Image(element->GetTexture()->GetTextureId(), texSize, {r.p1.x,r.p2.y}, {r.p2.x,r.p1.y});
|
|
|
|
ImGui::EndChild();
|
|
|
|
ImGui::PopStyleVar();
|
|
ImGui::PopStyleColor();
|
|
|
|
ImGui::SameLine();
|
|
ImVec2 cursorCurrent = ImGui::GetCursorPos();
|
|
cursorCurrent.y += (60-label_size.y) / 2;
|
|
ImGui::SetCursorPos(cursorCurrent);
|
|
ImGui::TextUnformatted(label.c_str());
|
|
}
|
|
void ElementDrawer::DrawSpriteNormal(Sprite *element, const bool &debug, const std::string &label)
|
|
{
|
|
Rect& r = element->GetUVRect();
|
|
ImGui::InputFloat2("UV1", &r.p1.x);
|
|
ImGui::InputFloat2("UV2", &r.p2.x);
|
|
if(debug)
|
|
{
|
|
Draw(element->GetTexture(), debug, "Texture", true);
|
|
}
|
|
ImGui::Separator();
|
|
float available_width = ImGui::GetContentRegionAvail().x;
|
|
float ymultiplyer = (element->GetTexture()->height() * r.height()) / (element->GetTexture()->width() * r.width());
|
|
|
|
ImVec2 texSize (available_width, (available_width) * ymultiplyer);
|
|
ImGui::Image(element->GetTexture()->GetTextureId(), texSize, {r.p1.x,r.p2.y}, {r.p2.x,r.p1.y});
|
|
}
|
|
void ElementDrawer::DrawTextureCompact(Texture *element, const bool &debug, const std::string &label)
|
|
{
|
|
float item_spacing = ImGui::GetStyle().ItemSpacing.x;
|
|
ImVec2 label_size = ImGui::CalcTextSize(label.c_str());
|
|
|
|
float available_width = ImGui::GetContentRegionAvail().x;
|
|
float field_width = available_width - label_size.x - item_spacing;
|
|
|
|
ImVec2 field_size = ImVec2(field_width, 60);
|
|
|
|
float ymultiplyer = element->height() / element->width();
|
|
|
|
ImVec2 texSize (field_size.y - 2, (field_size.y - 2) * ymultiplyer);
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetColorU32(ImGuiCol_FrameBg)); // gleiche Farbe wie InputText
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, ImGui::GetStyle().FrameRounding);
|
|
|
|
ImGui::BeginChild("##FakeInput", field_size, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
|
|
|
ImGui::SetCursorPos(ImVec2(1,(60-texSize.y) / 2));
|
|
ImGui::Image(element->GetTextureId(), texSize, {0,1}, {1,0});
|
|
ImGui::SameLine();
|
|
ImGui::SetCursorPos(ImVec2(field_size.y + 1,(60-label_size.y) / 2));
|
|
ImGui::TextUnformatted(element->name.c_str());
|
|
|
|
ImGui::EndChild();
|
|
|
|
ImGui::PopStyleVar();
|
|
ImGui::PopStyleColor();
|
|
|
|
ImGui::SameLine();
|
|
ImVec2 cursorCurrent = ImGui::GetCursorPos();
|
|
cursorCurrent.y += (60-label_size.y) / 2;
|
|
ImGui::SetCursorPos(cursorCurrent);
|
|
ImGui::TextUnformatted(label.c_str());
|
|
}
|
|
void ElementDrawer::DrawTextureNormal(Texture *element, const bool &debug, const std::string& label)
|
|
{
|
|
ImGui::TextUnformatted(element->name.c_str());
|
|
if(debug)
|
|
{
|
|
ImGui::Separator();
|
|
ImGui::TextDisabled(("Width: " + std::to_string(element->width())).c_str());
|
|
ImGui::TextDisabled(("Height: " + std::to_string(element->height())).c_str());
|
|
ImGui::TextDisabled(("BPP: " + std::to_string(element->bpp())).c_str());
|
|
ImGui::TextDisabled(("Chanels: " + std::to_string(element->Chanels())).c_str());
|
|
ImGui::Separator();
|
|
ImGui::TextDisabled(("TextureID: " + std::to_string(element->GetTextureId())).c_str());
|
|
}
|
|
ImGui::Separator();
|
|
float available_width = ImGui::GetContentRegionAvail().x;
|
|
float ymultiplyer = element->height() / element->width();
|
|
|
|
ImVec2 texSize (available_width, (available_width) * ymultiplyer);
|
|
ImGui::Image(element->GetTextureId(), texSize, {0,1}, {1,0});
|
|
}
|
|
|
|
} // namespace TSE::EDITOR
|