feat: add line renderer / visualisations for box collidors as a test
This commit is contained in:
+181
-69
@@ -1,7 +1,9 @@
|
||||
#include "Lightkeeper.h"
|
||||
|
||||
#include <array>
|
||||
#include <destrum/FS/AssetFS.h>
|
||||
#include <destrum/Assets/AssetManager.h>
|
||||
#include <destrum/Graphics/Managers/LineRenderingManager.h>
|
||||
#include "glm/gtx/transform.hpp"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <destrum/Components/Physics/Rigidbody.h>
|
||||
@@ -446,90 +448,199 @@ void LightKeeper::customUpdate(float dt)
|
||||
SceneManager::GetInstance().Update(dt);
|
||||
SceneManager::GetInstance().LateUpdate(dt);
|
||||
|
||||
if (m_params.showDebugUi) {
|
||||
drawDebugMenuBar();
|
||||
}
|
||||
|
||||
LineRenderingManager::GetInstance().SubmitLine({0, 0, 0}, {0, 10, 0}, {255, 0, 0, 255});
|
||||
|
||||
if (InputManager::GetInstance().WasKeyPressed(SDL_SCANCODE_1))
|
||||
{
|
||||
renderer.setRenderWireframe(!renderer.getRenderWireframe());
|
||||
}
|
||||
|
||||
ImGui::Begin("Test");
|
||||
if (ImGui::Button("SPawn ball"))
|
||||
{
|
||||
auto sphere = SceneManager::GetInstance().GetCurrentScene().CreateGameObject("Sphere");
|
||||
sphere->AddComponent<SphereCollider>(1.5f);
|
||||
auto rb = sphere->AddComponent<Rigidbody>();
|
||||
rb->SetMass(1000);
|
||||
if (m_params.showDebugUi) {
|
||||
ImGui::Begin("Test");
|
||||
if (ImGui::Button("SPawn ball"))
|
||||
{
|
||||
auto sphere = SceneManager::GetInstance().GetCurrentScene().CreateGameObject("Sphere");
|
||||
sphere->AddComponent<SphereCollider>(1.5f);
|
||||
auto rb = sphere->AddComponent<Rigidbody>();
|
||||
rb->SetMass(1000);
|
||||
|
||||
auto meshRenderComp = sphere->AddComponent<MeshRendererComponent>();
|
||||
meshRenderComp->SetMaterialID(sphereMaterial);
|
||||
meshRenderComp->SetMeshID(sphereMesh);
|
||||
auto meshRenderComp = sphere->AddComponent<MeshRendererComponent>();
|
||||
meshRenderComp->SetMaterialID(sphereMaterial);
|
||||
meshRenderComp->SetMeshID(sphereMesh);
|
||||
|
||||
sphere->GetTransform().SetWorldPosition((std::rand() % 2) - 0.5f, 100, (std::rand() % 2) - 0.5f);
|
||||
sphere->GetTransform().SetWorldScale(glm::vec3{0.015f});
|
||||
sphere->GetTransform().SetWorldPosition((std::rand() % 2) - 0.5f, 100, (std::rand() % 2) - 0.5f);
|
||||
sphere->GetTransform().SetWorldScale(glm::vec3{0.015f});
|
||||
|
||||
|
||||
SceneManager::GetInstance().GetCurrentScene().GetPhysics().RefreshGameObject(*sphere);
|
||||
SceneManager::GetInstance().GetCurrentScene().GetPhysics().RefreshGameObject(*sphere);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
ImGui::Begin("Scene Debug");
|
||||
ImGui::InputText("Scene path", scenePath, sizeof(scenePath));
|
||||
ImGui::InputText("New scene name", newSceneName, sizeof(newSceneName));
|
||||
void LightKeeper::drawDebugMenuBar()
|
||||
{
|
||||
if (!ImGui::BeginMainMenuBar()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Save Current Scene")) {
|
||||
try {
|
||||
const auto path = ResolveScenePath(scenePath, m_params.exeDir);
|
||||
const auto parent = path.parent_path();
|
||||
if (!parent.empty()) {
|
||||
std::filesystem::create_directories(parent);
|
||||
}
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
ImGui::TextDisabled("Scene");
|
||||
|
||||
if (SceneSerializer::Save(
|
||||
SceneManager::GetInstance().GetCurrentScene(),
|
||||
path)) {
|
||||
sceneStatus = "Saved scene to " + path.string();
|
||||
} else {
|
||||
sceneStatus = "Failed to save scene to " + path.string();
|
||||
}
|
||||
} catch (const std::exception& exception) {
|
||||
sceneStatus = std::string{"Save failed: "} + exception.what();
|
||||
ImGui::SetNextItemWidth(320.0f);
|
||||
ImGui::InputText("Scene path", scenePath, sizeof(scenePath));
|
||||
|
||||
ImGui::SetNextItemWidth(320.0f);
|
||||
ImGui::InputText("New scene name", newSceneName, sizeof(newSceneName));
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("New Empty Scene")) {
|
||||
createEmptyScene();
|
||||
}
|
||||
if (ImGui::MenuItem("Load")) {
|
||||
loadScene();
|
||||
}
|
||||
if (ImGui::MenuItem("Save")) {
|
||||
saveCurrentScene();
|
||||
}
|
||||
|
||||
if (!sceneStatus.empty()) {
|
||||
ImGui::Separator();
|
||||
ImGui::TextWrapped("%s", sceneStatus.c_str());
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Render")) {
|
||||
ImGui::MenuItem("Box Colliders", nullptr, &renderBoxColliders);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
|
||||
void LightKeeper::saveCurrentScene()
|
||||
{
|
||||
try {
|
||||
const auto path = ResolveScenePath(scenePath, m_params.exeDir);
|
||||
const auto parent = path.parent_path();
|
||||
if (!parent.empty()) {
|
||||
std::filesystem::create_directories(parent);
|
||||
}
|
||||
|
||||
if (SceneSerializer::Save(
|
||||
SceneManager::GetInstance().GetCurrentScene(),
|
||||
path)) {
|
||||
sceneStatus = "Saved scene to " + path.string();
|
||||
} else {
|
||||
sceneStatus = "Failed to save scene to " + path.string();
|
||||
}
|
||||
} catch (const std::exception& exception) {
|
||||
sceneStatus = std::string{"Save failed: "} + exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
void LightKeeper::loadScene()
|
||||
{
|
||||
try {
|
||||
const auto path = ResolveScenePath(scenePath, m_params.exeDir);
|
||||
if (SceneSerializer::Load(
|
||||
SceneManager::GetInstance().GetCurrentScene(),
|
||||
path)) {
|
||||
sceneStatus = "Loaded scene from " + path.string();
|
||||
} else {
|
||||
sceneStatus = "Failed to load scene from " + path.string();
|
||||
}
|
||||
} catch (const std::exception& exception) {
|
||||
sceneStatus = std::string{"Load failed: "} + exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
void LightKeeper::createEmptyScene()
|
||||
{
|
||||
try {
|
||||
const std::string name = newSceneName[0] != '\0'
|
||||
? newSceneName
|
||||
: "EmptyScene";
|
||||
auto& sceneManager = SceneManager::GetInstance();
|
||||
const int newSceneIndex = sceneManager.GetSceneCount();
|
||||
sceneManager.CreateScene(name);
|
||||
sceneManager.SwitchScene(newSceneIndex);
|
||||
sceneStatus = "Created and switched to scene '" + name + "'";
|
||||
} catch (const std::exception& exception) {
|
||||
sceneStatus = std::string{"New scene failed: "} + exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
void LightKeeper::submitBoxColliderDebugLines()
|
||||
{
|
||||
if (!renderBoxColliders) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& sceneManager = SceneManager::GetInstance();
|
||||
if (sceneManager.GetSceneCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Scene& scene = sceneManager.GetCurrentScene();
|
||||
auto& lineManager = LineRenderingManager::GetInstance();
|
||||
constexpr std::array<std::array<std::size_t, 2>, 12> edges{{
|
||||
{{0, 1}}, {{1, 3}}, {{3, 2}}, {{2, 0}},
|
||||
{{4, 5}}, {{5, 7}}, {{7, 6}}, {{6, 4}},
|
||||
{{0, 4}}, {{1, 5}}, {{2, 6}}, {{3, 7}},
|
||||
}};
|
||||
|
||||
for (const auto& objectPtr : scene.GetObjects()) {
|
||||
if (!objectPtr || objectPtr->IsBeingDestroyed() ||
|
||||
!objectPtr->IsActiveInHierarchy()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto* boxCollider = objectPtr->GetComponent<BoxCollider>();
|
||||
if (boxCollider == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Collider dimensions are already in world units. Physics does not
|
||||
// apply the GameObject scale when constructing the shape.
|
||||
const glm::vec3 center = boxCollider->GetCenterOffset();
|
||||
const glm::vec3 halfExtents = boxCollider->GetHalfExtents();
|
||||
const std::array<glm::vec3, 8> localCorners{
|
||||
center + glm::vec3{-halfExtents.x, -halfExtents.y, -halfExtents.z},
|
||||
center + glm::vec3{ halfExtents.x, -halfExtents.y, -halfExtents.z},
|
||||
center + glm::vec3{-halfExtents.x, halfExtents.y, -halfExtents.z},
|
||||
center + glm::vec3{ halfExtents.x, halfExtents.y, -halfExtents.z},
|
||||
center + glm::vec3{-halfExtents.x, -halfExtents.y, halfExtents.z},
|
||||
center + glm::vec3{ halfExtents.x, -halfExtents.y, halfExtents.z},
|
||||
center + glm::vec3{-halfExtents.x, halfExtents.y, halfExtents.z},
|
||||
center + glm::vec3{ halfExtents.x, halfExtents.y, halfExtents.z},
|
||||
};
|
||||
|
||||
Transform& transform = objectPtr->GetTransform();
|
||||
const glm::vec3 worldPosition = transform.GetWorldPosition();
|
||||
const glm::quat worldRotation = transform.GetWorldRotation();
|
||||
std::array<glm::vec3, 8> worldCorners{};
|
||||
for (std::size_t index = 0; index < localCorners.size(); ++index) {
|
||||
worldCorners[index] = worldPosition + worldRotation * localCorners[index];
|
||||
}
|
||||
|
||||
const glm::vec4 color = boxCollider->IsTrigger()
|
||||
? glm::vec4{1.0f, 0.75f, 0.1f, 1.0f}
|
||||
: glm::vec4{0.1f, 0.8f, 1.0f, 1.0f};
|
||||
for (const auto& edge : edges) {
|
||||
lineManager.SubmitLine(
|
||||
worldCorners[edge[0]],
|
||||
worldCorners[edge[1]],
|
||||
color);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Load Scene")) {
|
||||
try {
|
||||
const auto path = ResolveScenePath(scenePath, m_params.exeDir);
|
||||
if (SceneSerializer::Load(
|
||||
SceneManager::GetInstance().GetCurrentScene(),
|
||||
path)) {
|
||||
sceneStatus = "Loaded scene from " + path.string();
|
||||
} else {
|
||||
sceneStatus = "Failed to load scene from " + path.string();
|
||||
}
|
||||
} catch (const std::exception& exception) {
|
||||
sceneStatus = std::string{"Load failed: "} + exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("New Empty Scene")) {
|
||||
try {
|
||||
const std::string name = newSceneName[0] != '\0'
|
||||
? newSceneName
|
||||
: "EmptyScene";
|
||||
auto& sceneManager = SceneManager::GetInstance();
|
||||
const int newSceneIndex = sceneManager.GetSceneCount();
|
||||
sceneManager.CreateScene(name);
|
||||
sceneManager.SwitchScene(newSceneIndex);
|
||||
sceneStatus = "Created and switched to scene '" + name + "'";
|
||||
} catch (const std::exception& exception) {
|
||||
sceneStatus = std::string{"New scene failed: "} + exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
if (!sceneStatus.empty()) {
|
||||
ImGui::TextWrapped("%s", sceneStatus.c_str());
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void LightKeeper::customDraw()
|
||||
@@ -540,6 +651,7 @@ void LightKeeper::customDraw()
|
||||
}
|
||||
|
||||
renderer.beginDrawing(gfxDevice);
|
||||
submitBoxColliderDebugLines();
|
||||
|
||||
const RenderContext ctx{
|
||||
.renderer = renderer,
|
||||
|
||||
Reference in New Issue
Block a user