239 lines
7.5 KiB
C++
239 lines
7.5 KiB
C++
#include "LineCanvas.h"
|
|
|
|
static const char* codeVS = R"(
|
|
layout (location = 0) out vec4 out_color;
|
|
|
|
struct Vertex {
|
|
vec4 pos;
|
|
vec4 rgba;
|
|
};
|
|
|
|
layout(std430, buffer_reference) readonly buffer VertexBuffer {
|
|
Vertex vertices[];
|
|
};
|
|
|
|
layout(push_constant) uniform PushConstants {
|
|
mat4 mvp;
|
|
VertexBuffer vb;
|
|
};
|
|
|
|
void main() {
|
|
// Vertex v = vb.vertices[gl_VertexIndex]; <--- does not work on Snapdragon Adreno
|
|
out_color = vb.vertices[gl_VertexIndex].rgba;
|
|
gl_Position = mvp * vb.vertices[gl_VertexIndex].pos;
|
|
})";
|
|
|
|
static const char* codeFS = R"(
|
|
layout (location = 0) in vec4 in_color;
|
|
layout (location = 0) out vec4 out_color;
|
|
|
|
void main() {
|
|
out_color = in_color;
|
|
})";
|
|
|
|
void LineCanvas2D::render(const char* nameImGuiWindow)
|
|
{
|
|
LVK_PROFILER_FUNCTION();
|
|
|
|
ImGui::SetNextWindowPos(ImVec2(0, 0));
|
|
ImGui::SetNextWindowSize(ImGui::GetMainViewport()->Size);
|
|
ImGui::Begin(
|
|
nameImGuiWindow, nullptr,
|
|
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings |
|
|
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoInputs);
|
|
|
|
ImDrawList* drawList = ImGui::GetBackgroundDrawList();
|
|
|
|
for (const LineData& l : lines_) {
|
|
drawList->AddLine(ImVec2(l.p1.x, l.p1.y), ImVec2(l.p2.x, l.p2.y), ImColor(l.color.r, l.color.g, l.color.b, l.color.a));
|
|
}
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
void LineCanvas3D::line(const vec3& p1, const vec3& p2, const vec4& c)
|
|
{
|
|
lines_.push_back({ .pos = vec4(p1, 1.0f), .color = c });
|
|
lines_.push_back({ .pos = vec4(p2, 1.0f), .color = c });
|
|
}
|
|
|
|
void LineCanvas3D::plane(
|
|
const vec3& o, const vec3& v1, const vec3& v2, int n1, int n2, float s1, float s2, const vec4& color, const vec4& outlineColor)
|
|
{
|
|
line(o - s1 / 2.0f * v1 - s2 / 2.0f * v2, o - s1 / 2.0f * v1 + s2 / 2.0f * v2, outlineColor);
|
|
line(o + s1 / 2.0f * v1 - s2 / 2.0f * v2, o + s1 / 2.0f * v1 + s2 / 2.0f * v2, outlineColor);
|
|
|
|
line(o - s1 / 2.0f * v1 + s2 / 2.0f * v2, o + s1 / 2.0f * v1 + s2 / 2.0f * v2, outlineColor);
|
|
line(o - s1 / 2.0f * v1 - s2 / 2.0f * v2, o + s1 / 2.0f * v1 - s2 / 2.0f * v2, outlineColor);
|
|
|
|
for (int i = 1; i < n1; i++) {
|
|
float t = ((float)i - (float)n1 / 2.0f) * s1 / (float)n1;
|
|
const vec3 o1 = o + t * v1;
|
|
line(o1 - s2 / 2.0f * v2, o1 + s2 / 2.0f * v2, color);
|
|
}
|
|
|
|
for (int i = 1; i < n2; i++) {
|
|
const float t = ((float)i - (float)n2 / 2.0f) * s2 / (float)n2;
|
|
const vec3 o2 = o + t * v2;
|
|
line(o2 - s1 / 2.0f * v1, o2 + s1 / 2.0f * v1, color);
|
|
}
|
|
}
|
|
|
|
void LineCanvas3D::box(const mat4& m, const vec3& size, const vec4& c)
|
|
{
|
|
vec3 pts[8] = {
|
|
vec3(+size.x, +size.y, +size.z), vec3(+size.x, +size.y, -size.z), vec3(+size.x, -size.y, +size.z), vec3(+size.x, -size.y, -size.z),
|
|
vec3(-size.x, +size.y, +size.z), vec3(-size.x, +size.y, -size.z), vec3(-size.x, -size.y, +size.z), vec3(-size.x, -size.y, -size.z),
|
|
};
|
|
|
|
for (auto& p : pts)
|
|
p = vec3(m * vec4(p, 1.f));
|
|
|
|
line(pts[0], pts[1], c);
|
|
line(pts[2], pts[3], c);
|
|
line(pts[4], pts[5], c);
|
|
line(pts[6], pts[7], c);
|
|
|
|
line(pts[0], pts[2], c);
|
|
line(pts[1], pts[3], c);
|
|
line(pts[4], pts[6], c);
|
|
line(pts[5], pts[7], c);
|
|
|
|
line(pts[0], pts[4], c);
|
|
line(pts[1], pts[5], c);
|
|
line(pts[2], pts[6], c);
|
|
line(pts[3], pts[7], c);
|
|
}
|
|
|
|
void LineCanvas3D::box(const mat4& m, const BoundingBox& box, const glm::vec4& color)
|
|
{
|
|
this->box(m * glm::translate(mat4(1.f), .5f * (box.min_ + box.max_)), 0.5f * vec3(box.max_ - box.min_), color);
|
|
}
|
|
|
|
void LineCanvas3D::frustum(const mat4& camView, const mat4& camProj, const vec4& color)
|
|
{
|
|
const vec3 corners[] = { vec3(-1, -1, -1), vec3(+1, -1, -1), vec3(+1, +1, -1), vec3(-1, +1, -1),
|
|
vec3(-1, -1, +1), vec3(+1, -1, +1), vec3(+1, +1, +1), vec3(-1, +1, +1) };
|
|
|
|
vec3 pp[8];
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
vec4 q = glm::inverse(camView) * glm::inverse(camProj) * vec4(corners[i], 1.0f);
|
|
pp[i] = vec3(q.x / q.w, q.y / q.w, q.z / q.w);
|
|
}
|
|
line(pp[0], pp[4], color);
|
|
line(pp[1], pp[5], color);
|
|
line(pp[2], pp[6], color);
|
|
line(pp[3], pp[7], color);
|
|
// near
|
|
line(pp[0], pp[1], color);
|
|
line(pp[1], pp[2], color);
|
|
line(pp[2], pp[3], color);
|
|
line(pp[3], pp[0], color);
|
|
// x
|
|
line(pp[0], pp[2], color);
|
|
line(pp[1], pp[3], color);
|
|
// far
|
|
line(pp[4], pp[5], color);
|
|
line(pp[5], pp[6], color);
|
|
line(pp[6], pp[7], color);
|
|
line(pp[7], pp[4], color);
|
|
// x
|
|
line(pp[4], pp[6], color);
|
|
line(pp[5], pp[7], color);
|
|
|
|
const vec4 gridColor = color * 0.7f;
|
|
const int gridLines = 100;
|
|
|
|
// bottom
|
|
{
|
|
vec3 p1 = pp[0];
|
|
vec3 p2 = pp[1];
|
|
const vec3 s1 = (pp[4] - pp[0]) / float(gridLines);
|
|
const vec3 s2 = (pp[5] - pp[1]) / float(gridLines);
|
|
for (int i = 0; i != gridLines; i++, p1 += s1, p2 += s2)
|
|
line(p1, p2, gridColor);
|
|
}
|
|
// top
|
|
{
|
|
vec3 p1 = pp[2];
|
|
vec3 p2 = pp[3];
|
|
const vec3 s1 = (pp[6] - pp[2]) / float(gridLines);
|
|
const vec3 s2 = (pp[7] - pp[3]) / float(gridLines);
|
|
for (int i = 0; i != gridLines; i++, p1 += s1, p2 += s2)
|
|
line(p1, p2, gridColor);
|
|
}
|
|
// left
|
|
{
|
|
vec3 p1 = pp[0];
|
|
vec3 p2 = pp[3];
|
|
const vec3 s1 = (pp[4] - pp[0]) / float(gridLines);
|
|
const vec3 s2 = (pp[7] - pp[3]) / float(gridLines);
|
|
for (int i = 0; i != gridLines; i++, p1 += s1, p2 += s2)
|
|
line(p1, p2, gridColor);
|
|
}
|
|
// right
|
|
{
|
|
vec3 p1 = pp[1];
|
|
vec3 p2 = pp[2];
|
|
const vec3 s1 = (pp[5] - pp[1]) / float(gridLines);
|
|
const vec3 s2 = (pp[6] - pp[2]) / float(gridLines);
|
|
for (int i = 0; i != gridLines; i++, p1 += s1, p2 += s2)
|
|
line(p1, p2, gridColor);
|
|
}
|
|
}
|
|
|
|
void LineCanvas3D::render(lvk::IContext& ctx, const lvk::Framebuffer& desc, lvk::ICommandBuffer& buf, uint32_t numSamples)
|
|
{
|
|
LVK_PROFILER_FUNCTION();
|
|
|
|
if (lines_.empty()) {
|
|
return;
|
|
}
|
|
|
|
const uint32_t requiredSize = lines_.size() * sizeof(LineData);
|
|
|
|
if (currentBufferSize_[currentFrame_] < requiredSize) {
|
|
linesBuffer_[currentFrame_] = ctx.createBuffer(
|
|
{ .usage = lvk::BufferUsageBits_Storage, .storage = lvk::StorageType_HostVisible, .size = requiredSize, .data = lines_.data() });
|
|
currentBufferSize_[currentFrame_] = requiredSize;
|
|
} else {
|
|
ctx.upload(linesBuffer_[currentFrame_], lines_.data(), requiredSize);
|
|
}
|
|
|
|
if (pipeline_.empty() || pipelineSamples_ != numSamples) {
|
|
pipelineSamples_ = numSamples;
|
|
|
|
vert_ = ctx.createShaderModule({ codeVS, lvk::Stage_Vert, "Shader Module: imgui (vert)" });
|
|
frag_ = ctx.createShaderModule({ codeFS, lvk::Stage_Frag, "Shader Module: imgui (frag)" });
|
|
pipeline_ = ctx.createRenderPipeline(
|
|
{
|
|
.topology = lvk::Topology_Line,
|
|
.smVert = vert_,
|
|
.smFrag = frag_,
|
|
.color = { {
|
|
.format = ctx.getFormat(desc.color[0].texture),
|
|
.blendEnabled = true,
|
|
.srcRGBBlendFactor = lvk::BlendFactor_SrcAlpha,
|
|
.dstRGBBlendFactor = lvk::BlendFactor_OneMinusSrcAlpha,
|
|
} },
|
|
.depthFormat = desc.depthStencil.texture ? ctx.getFormat(desc.depthStencil.texture) : lvk::Format_Invalid,
|
|
.cullMode = lvk::CullMode_None,
|
|
.samplesCount = numSamples,
|
|
},
|
|
nullptr);
|
|
}
|
|
|
|
struct {
|
|
mat4 mvp;
|
|
uint64_t addr;
|
|
} pc{
|
|
.mvp = mvp_,
|
|
.addr = ctx.gpuAddress(linesBuffer_[currentFrame_]),
|
|
};
|
|
buf.cmdBindRenderPipeline(pipeline_);
|
|
buf.cmdPushConstants(pc);
|
|
buf.cmdDraw(lines_.size());
|
|
|
|
currentFrame_ = (currentFrame_ + 1) % LVK_ARRAY_NUM_ELEMENTS(linesBuffer_);
|
|
}
|