From 5ccc61f14468b525ef32ac3c1735ad0d8fedac89 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 5 May 2026 05:59:06 -0700 Subject: [PATCH] fix(editor): NPC position markers always visible regardless of M2 rendering - Colored diamond markers rendered at every NPC position on terrain: red for hostile, green for friendly, with vertical pillar for height - Renders through water pipeline (alpha-blended, depth-tested) - Always visible regardless of whether M2 creature model renders - Scales with NPC scale setting for consistent visual size - This guarantees you can always see where NPCs are placed --- tools/editor/editor_viewport.cpp | 57 ++++++++++++++++++++++++++++++++ tools/editor/editor_viewport.hpp | 5 +++ 2 files changed, 62 insertions(+) diff --git a/tools/editor/editor_viewport.cpp b/tools/editor/editor_viewport.cpp index eca94612..44f9f6e3 100644 --- a/tools/editor/editor_viewport.cpp +++ b/tools/editor/editor_viewport.cpp @@ -56,6 +56,7 @@ void EditorViewport::shutdown() { if (!vkCtx_) return; vkDeviceWaitIdle(vkCtx_->getDevice()); + if (npcMarkerVB_) { vmaDestroyBuffer(vkCtx_->getAllocator(), npcMarkerVB_, npcMarkerVBAlloc_); npcMarkerVB_ = VK_NULL_HANDLE; } if (brushVB_) { vmaDestroyBuffer(vkCtx_->getAllocator(), brushVB_, brushVBAlloc_); brushVB_ = VK_NULL_HANDLE; } gizmo_.shutdown(); waterRenderer_.shutdown(); @@ -246,6 +247,48 @@ void EditorViewport::rebuildObjects(const std::vector& objects, vkCtx_->waitAllUploads(); vkCtx_->pollUploadBatches(); + + // Build NPC position markers (always visible, renders as colored discs) + if (npcMarkerVB_) { + vmaDestroyBuffer(vkCtx_->getAllocator(), npcMarkerVB_, npcMarkerVBAlloc_); + npcMarkerVB_ = VK_NULL_HANDLE; + npcMarkerVertCount_ = 0; + } + if (!npcs.empty()) { + struct MV { float pos[3]; float color[4]; }; + std::vector verts; + for (const auto& npc : npcs) { + float s = 3.0f * npc.scale; + float x = npc.position.x, y = npc.position.y, z = npc.position.z + 0.5f; + float r = npc.hostile ? 0.9f : 0.2f; + float g = npc.hostile ? 0.2f : 0.8f; + float b = 0.2f, a = 0.85f; + // Flat diamond on ground + MV v; v.color[0]=r; v.color[1]=g; v.color[2]=b; v.color[3]=a; + v.pos[0]=x+s; v.pos[1]=y; v.pos[2]=z; verts.push_back(v); + v.pos[0]=x; v.pos[1]=y+s; v.pos[2]=z; verts.push_back(v); + v.pos[0]=x-s; v.pos[1]=y; v.pos[2]=z; verts.push_back(v); + v.pos[0]=x+s; v.pos[1]=y; v.pos[2]=z; verts.push_back(v); + v.pos[0]=x-s; v.pos[1]=y; v.pos[2]=z; verts.push_back(v); + v.pos[0]=x; v.pos[1]=y-s; v.pos[2]=z; verts.push_back(v); + // Vertical pillar + float h = s * 3.0f; + v.color[3] = 0.6f; + v.pos[0]=x-0.5f; v.pos[1]=y; v.pos[2]=z; verts.push_back(v); + v.pos[0]=x+0.5f; v.pos[1]=y; v.pos[2]=z; verts.push_back(v); + v.pos[0]=x; v.pos[1]=y; v.pos[2]=z+h; verts.push_back(v); + } + npcMarkerVertCount_ = static_cast(verts.size()); + VkBufferCreateInfo bi{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bi.size = verts.size() * sizeof(MV); + bi.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + VmaAllocationCreateInfo ai{}; ai.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; + ai.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + VmaAllocationInfo mi{}; + if (vmaCreateBuffer(vkCtx_->getAllocator(), &bi, &ai, + &npcMarkerVB_, &npcMarkerVBAlloc_, &mi) == VK_SUCCESS) + std::memcpy(mi.pMappedData, verts.data(), verts.size() * sizeof(MV)); + } } void EditorViewport::setBrushIndicator(const glm::vec3& center, float radius, bool active) { @@ -382,6 +425,20 @@ void EditorViewport::render(VkCommandBuffer cmd) { waterRenderer_.render(cmd, perFrameSet); + // NPC position markers (always visible) + if (npcMarkerVB_ && npcMarkerVertCount_ > 0) { + auto* wp = waterRenderer_.getPipeline(); + auto* wl = waterRenderer_.getPipelineLayout(); + if (wp && wl) { + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, wp); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, wl, + 0, 1, &perFrameSet, 0, nullptr); + VkDeviceSize off = 0; + vkCmdBindVertexBuffers(cmd, 0, 1, &npcMarkerVB_, &off); + vkCmdDraw(cmd, npcMarkerVertCount_, 1, 0, 0); + } + } + // Brush indicator circle if (brushVisible_ && brushVB_ && brushVertCount_ > 0) { // Reuse gizmo pipeline (same vertex format, no depth test, alpha blend) diff --git a/tools/editor/editor_viewport.hpp b/tools/editor/editor_viewport.hpp index 0c649334..d71a56d2 100644 --- a/tools/editor/editor_viewport.hpp +++ b/tools/editor/editor_viewport.hpp @@ -105,6 +105,11 @@ private: VmaAllocation brushVBAlloc_ = VK_NULL_HANDLE; uint32_t brushVertCount_ = 0; bool brushVisible_ = false; + + // NPC position markers (always visible fallback) + VkBuffer npcMarkerVB_ = VK_NULL_HANDLE; + VmaAllocation npcMarkerVBAlloc_ = VK_NULL_HANDLE; + uint32_t npcMarkerVertCount_ = 0; }; } // namespace editor