feat(editor): random rotation, placed object list, quality of life

- Random Rotation checkbox: each placed object gets a random Y rotation
  (great for natural-looking tree/rock placement without manual tweaking)
- Placed Object List: collapsible list in Object panel showing all placed
  objects with name and position, click to select
- Both features reduce repetitive manual work when building dense zones
This commit is contained in:
Kelsi 2026-05-05 04:57:42 -07:00
parent 89312120f4
commit 5df007b7b9
3 changed files with 34 additions and 1 deletions

View file

@ -463,6 +463,9 @@ void EditorUI::renderObjectPanel(EditorApp& app) {
float rot = placer.getPlacementRotationY();
if (ImGui::SliderFloat("Y Rotation", &rot, 0.0f, 360.0f, "%.0f deg"))
placer.setPlacementRotationY(rot);
bool randRot = placer.getRandomRotation();
if (ImGui::Checkbox("Random Rotation", &randRot))
placer.setRandomRotation(randRot);
float scale = placer.getPlacementScale();
if (ImGui::SliderFloat("Scale", &scale, 0.1f, 10.0f, "%.2f"))
placer.setPlacementScale(scale);
@ -513,6 +516,27 @@ void EditorUI::renderObjectPanel(EditorApp& app) {
ImGui::Separator();
ImGui::Text("Placed: %zu objects", placer.objectCount());
if (placer.objectCount() > 0 && ImGui::CollapsingHeader("Object List")) {
ImGui::BeginChild("ObjPlacedList", ImVec2(0, 100), true);
for (int i = 0; i < static_cast<int>(placer.objectCount()); i++) {
auto& o = const_cast<std::vector<PlacedObject>&>(placer.getObjects())[i];
std::string disp = o.path;
auto sl = disp.rfind('\\');
if (sl != std::string::npos) disp = disp.substr(sl + 1);
char lbl[128];
std::snprintf(lbl, sizeof(lbl), "%s (%.0f,%.0f,%.0f)##obj%d",
disp.c_str(), o.position.x, o.position.y, o.position.z, i);
if (ImGui::Selectable(lbl, o.selected)) {
placer.clearSelection();
// Select by creating a ray through the object position
rendering::Ray r;
r.origin = o.position + glm::vec3(0, 0, 1);
r.direction = glm::vec3(0, 0, -1);
placer.selectAt(r, 1000.0f);
}
}
ImGui::EndChild();
}
if (auto* sel = placer.getSelected()) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 0.9f, 0.3f, 1));
ImGui::Text("Selected: %s", sel->path.c_str());

View file

@ -25,7 +25,13 @@ void ObjectPlacer::placeObject(const glm::vec3& position) {
obj.nameId = 0;
obj.uniqueId = nextUniqueId();
obj.position = position;
obj.rotation = glm::vec3(0.0f, placementRotY_, 0.0f);
float rotY = placementRotY_;
if (randomRotation_) {
static std::mt19937 rng(42);
std::uniform_real_distribution<float> dist(0.0f, 360.0f);
rotY = dist(rng);
}
obj.rotation = glm::vec3(0.0f, rotY, 0.0f);
obj.scale = placementScale_;
obj.selected = false;

View file

@ -56,6 +56,8 @@ public:
void setPlacementRotationY(float deg) { placementRotY_ = deg; }
float getPlacementScale() const { return placementScale_; }
void setPlacementScale(float s) { placementScale_ = s; }
bool getRandomRotation() const { return randomRotation_; }
void setRandomRotation(bool v) { randomRotation_ = v; }
// Undo last placement
bool canUndoPlace() const { return !undoStack_.empty(); }
@ -78,6 +80,7 @@ private:
uint32_t uniqueIdCounter_ = 1;
float placementRotY_ = 0.0f;
float placementScale_ = 1.0f;
bool randomRotation_ = false;
};
} // namespace editor