feat: add click to select

This commit is contained in:
2026-10-23 20:53:56 +02:00
parent f055bdcbf1
commit f7e7c56392
20 changed files with 385 additions and 20 deletions
+3
View File
@@ -36,6 +36,8 @@ public:
private:
void setupSkybox();
void updateViewMode();
void focusSelection();
void updateFocus(float dt);
[[nodiscard]] CameraComponent* getSceneCamera() const;
[[nodiscard]] Camera& getViewCamera();
[[nodiscard]] bool isPlayerViewActive() const;
@@ -57,6 +59,7 @@ private:
Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)};
std::optional<Camera> editorCamera;
std::optional<glm::vec3> focusTarget;
std::unique_ptr<CubeMap> skyboxCubemap;
MainSceneObjects mainScene{};
+5
View File
@@ -65,6 +65,11 @@ void LightKeeper::customUpdate(float dt)
// after SDL events have been consumed.
if (!isPlayerViewActive() && getSceneCamera() == nullptr)
{
if (InputManager::GetInstance().WasKeyPressed(SDL_SCANCODE_F))
{
focusSelection();
}
updateFocus(dt);
camera.Update(dt);
}
if (InputManager::GetInstance().WasKeyPressed(SDL_SCANCODE_F11))
+74
View File
@@ -19,8 +19,12 @@
#include <components/FirstPersonController.h>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <filesystem>
#include <limits>
#include <vector>
#include <stdexcept>
#include <string>
#include <string_view>
@@ -162,6 +166,11 @@ void LightKeeper::drawDebugMenuBar()
if (ImGui::MenuItem("Forward+ Light Heatmap", nullptr, &lightHeatmap)) {
renderer.setRenderLightHeatmap(lightHeatmap);
}
bool selectionView = renderer.getRenderSelectionView();
if (ImGui::MenuItem("Selection Buffer", nullptr, &selectionView)) {
renderer.setRenderSelectionView(selectionView);
}
ImGui::EndMenu();
}
@@ -217,6 +226,71 @@ void LightKeeper::onViewportAssetDropped(std::string_view path)
}
}
void LightKeeper::focusSelection()
{
GameObject* selected = SceneManager::GetInstance().GetCurrentScene().GetSelectedObject();
if (selected == nullptr) {
return;
}
glm::vec3 boundsMin{std::numeric_limits<float>::max()};
glm::vec3 boundsMax{std::numeric_limits<float>::lowest()};
std::vector<GameObject*> pending{selected};
while (!pending.empty()) {
GameObject* object = pending.back();
pending.pop_back();
for (const Transform* child : object->GetTransform().GetChildren()) {
if (child != nullptr && child->GetOwner() != nullptr) {
pending.push_back(child->GetOwner());
}
}
const auto* meshRenderer = object->GetComponent<MeshRendererComponent>();
if (meshRenderer == nullptr || meshRenderer->GetMeshID() == NULL_MESH_ID) {
continue;
}
const GPUMesh& mesh = resources.meshes().getMesh(meshRenderer->GetMeshID());
const glm::mat4 world = object->GetTransform().GetWorldMatrix();
for (int corner = 0; corner < 8; ++corner) {
const glm::vec3 local{
corner & 1 ? mesh.maxPos.x : mesh.minPos.x,
corner & 2 ? mesh.maxPos.y : mesh.minPos.y,
corner & 4 ? mesh.maxPos.z : mesh.minPos.z,
};
const glm::vec3 point{world * glm::vec4{local, 1.0f}};
boundsMin = glm::min(boundsMin, point);
boundsMax = glm::max(boundsMax, point);
}
}
const bool hasBounds = boundsMin.x <= boundsMax.x;
const glm::vec3 center = hasBounds ? (boundsMin + boundsMax) * 0.5f : selected->GetTransform().GetWorldPosition();
const float radius = hasBounds ? std::max(glm::length(boundsMax - boundsMin) * 0.5f, 0.1f) : 1.0f;
// Fit the bounding sphere in the narrower of the two field of view angles
const float halfFovY = glm::radians(camera.GetFOVY()) * 0.5f;
const float halfFovX = std::atan(std::tan(halfFovY) * camera.GetAspectRatio());
const float distance = radius / std::sin(std::min(halfFovX, halfFovY)) * 1.1f;
focusTarget = center - camera.GetForward() * distance;
}
void LightKeeper::updateFocus(float dt)
{
if (!focusTarget) {
return;
}
if (InputManager::GetInstance().IsMouseDown(SDL_BUTTON_RIGHT)) {
focusTarget.reset();
return;
}
camera.m_position = glm::mix(camera.m_position, *focusTarget, 1.0f - std::exp(-12.0f * dt));
if (glm::distance(camera.m_position, *focusTarget) < 0.01f) {
camera.m_position = *focusTarget;
focusTarget.reset();
}
}
void LightKeeper::drawViewportOverlay()
{
if (!showTransformGizmo || isPlayerViewActive()) {