#include "pch.h"

#include "Mesh2D.h"
#include <stdexcept>
#include <algorithm>
#include <cmath>
#include <glm/gtx/norm.hpp>

namespace Vivid2D {

    namespace {
        glm::vec2 barycentric(const glm::vec2& p, const glm::vec2& a, const glm::vec2& b, const glm::vec2& c) {
            glm::vec2 v0 = b - a, v1 = c - a, v2 = p - a;
            float d00 = glm::dot(v0, v0);
            float d01 = glm::dot(v0, v1);
            float d11 = glm::dot(v1, v1);
            float d20 = glm::dot(v2, v0);
            float d21 = glm::dot(v2, v1);
            float denom = d00 * d11 - d01 * d01;
            if (std::abs(denom) < 1e-9f) return glm::vec2(-1.0f); // 退化三角形
            float w = (d11 * d20 - d01 * d21) / denom;
            float v = (d00 * d21 - d01 * d20) / denom;
            return glm::vec2(w, v);
        }

        bool isPointInTriangle(const glm::vec2& p, const glm::vec2& a, const glm::vec2& b, const glm::vec2& c) {
            glm::vec2 coords = barycentric(p, a, b, c);
            const float epsilon = 1e-6f;
            return coords.x >= -epsilon && coords.y >= -epsilon && (coords.x + coords.y) <= 1.0f + epsilon;
        }
        struct TriangleInfo {
            int i1, i2, i3;
            Vertex* v1, * v2, * v3;
        };
    }

    // ==================== 构造/析构/拷贝/移动 ====================

    Mesh2D::Mesh2D(std::string name)
        : m_Name(std::move(name)), m_ActiveVertexList(std::make_unique<util::VertexList>("DefaultList")) {}

    Mesh2D::Mesh2D(std::string name, const std::vector<float>& vertices, const std::vector<float>& uvs, const std::vector<int>& indices)
        : Mesh2D(std::move(name)) {
        setMeshData(vertices, uvs, indices);
    }

    Mesh2D::~Mesh2D() {
        deleteGPU();
    }

    void Mesh2D::copyFrom(const Mesh2D& other) {
        m_Name = other.m_Name;
        m_ActiveVertexList = std::make_unique<util::VertexList>(*other.m_ActiveVertexList);
        m_ModelPart = other.m_ModelPart;
        m_Texture = other.m_Texture;
        m_IsVisible = other.m_IsVisible;
        m_DrawMode = other.m_DrawMode;
        m_Pivot = other.m_Pivot;
        m_OriginalPivot = other.m_OriginalPivot;
        m_IsDirty = true;
        m_IsUploaded = false;
        m_BoundsDirty = true;
        m_VaoID = m_VboID = m_EboID = 0;
        m_IndexCount = 0;
        m_IsSelected = other.m_IsSelected.load();
        m_DeformationControlVertices.clear();
    }

    Mesh2D::Mesh2D(const Mesh2D& other) { copyFrom(other); }

    Mesh2D& Mesh2D::operator=(const Mesh2D& other) {
        if (this != &other) {
            deleteGPU();
            copyFrom(other);
        }
        return *this;
    }

    Mesh2D::Mesh2D(Mesh2D&& other) noexcept
        : m_Name(std::move(other.m_Name)), m_ActiveVertexList(std::move(other.m_ActiveVertexList)),
        m_ModelPart(other.m_ModelPart), m_Texture(std::move(other.m_Texture)),
        m_IsVisible(other.m_IsVisible), m_DrawMode(other.m_DrawMode), m_VaoID(other.m_VaoID),
        m_VboID(other.m_VboID), m_EboID(other.m_EboID), m_IndexCount(other.m_IndexCount),
        m_IsUploaded(other.m_IsUploaded), m_IsDirty(other.m_IsDirty), m_Bounds(std::move(other.m_Bounds)),
        m_BoundsDirty(other.m_BoundsDirty), m_IsSelected(other.m_IsSelected.load()), m_Pivot(other.m_Pivot),
        m_OriginalPivot(other.m_OriginalPivot), m_DeformationControlVertices(std::move(other.m_DeformationControlVertices)) {
        other.m_VaoID = other.m_VboID = other.m_EboID = 0;
        other.m_IsUploaded = false;
    }

    Mesh2D& Mesh2D::operator=(Mesh2D&& other) noexcept {
        if (this != &other) {
            deleteGPU();
            m_Name = std::move(other.m_Name); m_ActiveVertexList = std::move(other.m_ActiveVertexList);
            m_ModelPart = other.m_ModelPart; m_Texture = std::move(other.m_Texture);
            m_IsVisible = other.m_IsVisible; m_DrawMode = other.m_DrawMode;
            m_VaoID = other.m_VaoID; m_VboID = other.m_VboID; m_EboID = other.m_EboID;
            m_IndexCount = other.m_IndexCount; m_IsUploaded = other.m_IsUploaded;
            m_IsDirty = other.m_IsDirty; m_Bounds = std::move(other.m_Bounds);
            m_BoundsDirty = other.m_BoundsDirty; m_IsSelected = other.m_IsSelected.load();
            m_Pivot = other.m_Pivot; m_OriginalPivot = other.m_OriginalPivot;
            m_DeformationControlVertices = std::move(other.m_DeformationControlVertices);
            other.m_VaoID = other.m_VboID = other.m_EboID = 0; other.m_IsUploaded = false;
        }
        return *this;
    }

    // ==================== 变形引擎 ====================
    Vertex* Mesh2D::addControlPointAt(float x, float y) {
        if (m_ActiveVertexList->getIndices().empty() || !m_ModelPart) return nullptr;
        glm::vec2 worldPoint(x, y);
        std::optional<TriangleInfo> containingTriangle;
        const auto& indices = m_ActiveVertexList->getIndices();
        for (size_t i = 0; i < indices.size(); i += 3) {
            const auto& indices = m_ActiveVertexList->getIndices();
            for (size_t i = 0; i < indices.size(); i += 3) {
                int i1 = indices[i], i2 = indices[i + 1], i3 = indices[i + 2];
                Vertex* v1 = &m_ActiveVertexList->vertices[i1];
                Vertex* v2 = &m_ActiveVertexList->vertices[i2];
                Vertex* v3 = &m_ActiveVertexList->vertices[i3];
                if (isPointInTriangle(worldPoint, v1->position, v2->position, v3->position)) {
                    containingTriangle = TriangleInfo{ i1, i2, i3, v1, v2, v3 };
                    break;
                }
            }
        }
        if (!containingTriangle) return nullptr;
        glm::vec2 baryCoords = barycentric(worldPoint, containingTriangle->v1->position, containingTriangle->v2->position, containingTriangle->v3->position);
        float w = baryCoords.x, v = baryCoords.y, u = 1.0f - w - v;
        glm::vec2 newUv = containingTriangle->v1->uv * u + containingTriangle->v2->uv * w + containingTriangle->v3->uv * v;
        glm::vec2 newOriginalPos = containingTriangle->v1->originalPosition * u + containingTriangle->v2->originalPosition * w + containingTriangle->v3->originalPosition * v;
        Vertex newVertex(worldPoint, newUv, util::VertexTag::DEFORMATION);
        newVertex.originalPosition = newOriginalPos;
        addVertex(newVertex);
        const int newVertexIndex = getVertexCount() - 1;
        std::vector<int> newIndices; newIndices.reserve(indices.size() + 6);
        for (size_t i = 0; i < indices.size(); i += 3) {
            if (indices[i] == containingTriangle->i1 && indices[i + 1] == containingTriangle->i2 && indices[i + 2] == containingTriangle->i3) {
                newIndices.insert(newIndices.end(), { containingTriangle->i1, containingTriangle->i2, newVertexIndex });
                newIndices.insert(newIndices.end(), { containingTriangle->i2, containingTriangle->i3, newVertexIndex });
                newIndices.insert(newIndices.end(), { containingTriangle->i3, containingTriangle->i1, newVertexIndex });
            }
            else {
                newIndices.insert(newIndices.end(), { indices[i], indices[i + 1], indices[i + 2] });
            }
        }
        m_ActiveVertexList->setIndices(newIndices);
        Vertex* newVertexPtr = getVertex(newVertexIndex);
        m_DeformationControlVertices.push_back(newVertexPtr);
        markDirty();
        return newVertexPtr;
    }

    void Mesh2D::setDeformationControlVertices(const std::vector<Vertex*>& controlVertices) { m_DeformationControlVertices = controlVertices; }

    void Mesh2D::applyLocalizedPush(const std::vector<Vertex>& baseVertexState, const glm::vec2& pushCenterWorld, const glm::vec2& delta, float radius) {
        if (!m_ActiveVertexList || m_ActiveVertexList->isEmpty() || baseVertexState.size() != m_ActiveVertexList->size()) return;
        float radiusSq = radius * radius;
        for (size_t i = 0; i < m_ActiveVertexList->size(); ++i) {
            Vertex* currentVertex = &m_ActiveVertexList->vertices[i];
            const Vertex& baseStateVertex = baseVertexState[i];
            float distSq = glm::distance2(currentVertex->originalPosition, pushCenterWorld); // 修正：使用 glm::distance2
            if (distSq < radiusSq) {
                float influence = std::exp(-(distSq / radiusSq) * 4.0f);
                currentVertex->position = baseStateVertex.position + delta * influence;
            }
            else {
                currentVertex->position = baseStateVertex.position;
            }
        }
        markDirty();
    }

    // ==================== 网格数据设置 ====================
    void Mesh2D::setMeshData(const std::vector<float>& vertices, const std::vector<float>& uvs, const std::vector<int>& indices) {
        if (vertices.size() % 2 != 0 || uvs.size() % 2 != 0 || vertices.size() != uvs.size())
            throw std::invalid_argument("Invalid vertex or uv data.");
        m_ActiveVertexList->clear();
        for (size_t i = 0; i < vertices.size() / 2; ++i) {
            m_ActiveVertexList->add(Vertex(vertices[i * 2], vertices[i * 2 + 1], uvs[i * 2], uvs[i * 2 + 1]));
        }
        m_ActiveVertexList->setIndices(indices);
        m_OriginalPivot = m_Pivot;
        markDirty();
    }

    void Mesh2D::setVertices(const std::vector<float>& vertices, bool updateOriginal) {
        if (vertices.size() % 2 != 0) throw std::invalid_argument("Vertices array must have even length.");
        size_t newVertexCount = vertices.size() / 2;
        size_t oldVertexCount = getVertexCount();
        if (newVertexCount != oldVertexCount) {
            std::vector<Vertex> newVertexCollection; newVertexCollection.reserve(newVertexCount);
            for (size_t i = 0; i < newVertexCount; ++i) {
                if (i < oldVertexCount) {
                    newVertexCollection.emplace_back(vertices[i * 2], vertices[i * 2 + 1], getVertex(i)->uv.x, getVertex(i)->uv.y);
                }
                else {
                    newVertexCollection.emplace_back(vertices[i * 2], vertices[i * 2 + 1], 0.5f, 0.5f);
                }
            }
            m_ActiveVertexList->vertices = newVertexCollection; // 修正：直接赋值
            regenerateIndicesForNewVertexCount(newVertexCount);
        }
        else {
            for (size_t i = 0; i < newVertexCount; ++i) {
                getVertex(i)->position = { vertices[i * 2], vertices[i * 2 + 1] };
            }
        }
        markDirty();
        if (updateOriginal) saveAsOriginal();
    }

    void Mesh2D::regenerateIndicesForNewVertexCount(int newVertexCount) {
        if (newVertexCount < 3) { m_ActiveVertexList->setIndices({}); return; }
        std::vector<int> newIndices;
        for (int i = 1; i < newVertexCount - 1; ++i) { newIndices.insert(newIndices.end(), { 0, i, i + 1 }); }
        m_ActiveVertexList->setIndices(newIndices);
    }

    void Mesh2D::setTexture(std::shared_ptr<Vivid2D::Render::Texture::Texture> texture) { m_Texture = std::move(texture); }
    void Mesh2D::setModelPart(ModelPart* modelPart) { m_ModelPart = modelPart; }
    void Mesh2D::setPivot(const glm::vec2& pivot) { m_Pivot = pivot; markDirty(); }
    void Mesh2D::movePivot(float dx, float dy) { m_Pivot += glm::vec2(dx, dy); markDirty(); }

    // ==================== 顶点操作 ====================
    void Mesh2D::addVertex(const Vertex& vertex) { m_ActiveVertexList->add(vertex); markDirty(); }

    void Mesh2D::insertVertex(int index, const Vertex& vertex) {
        m_ActiveVertexList->vertices.insert(m_ActiveVertexList->vertices.begin() + index, vertex);
        updateIndicesAfterVertexInsertion(index);
        markDirty();
    }

    void Mesh2D::removeVertex(int index) {
        m_ActiveVertexList->remove(index); // VertexList 应该有这个方法
        updateIndicesAfterVertexRemoval(index);
        markDirty();
    }

    void Mesh2D::updateIndicesAfterVertexInsertion(int insertedIndex) {
        auto indices = m_ActiveVertexList->getIndices();
        for (int& idx : indices) {
            if (idx >= insertedIndex) {
                idx++;
            }
        }
        m_ActiveVertexList->setIndices(indices);
    }

    void Mesh2D::updateIndicesAfterVertexRemoval(int removedIndex) {
        auto indices = m_ActiveVertexList->getIndices(); // 获取副本
        std::vector<int> newIndices;
        for (size_t i = 0; i < indices.size(); i += 3) {
            int i1 = indices[i], i2 = indices[i + 1], i3 = indices[i + 2];
            if (i1 == removedIndex || i2 == removedIndex || i3 == removedIndex) continue;
            if (i1 > removedIndex) i1--; if (i2 > removedIndex) i2--; if (i3 > removedIndex) i3--;
            newIndices.insert(newIndices.end(), { i1, i2, i3 });
        }
        m_ActiveVertexList->setIndices(newIndices);
    }

    void Mesh2D::removeVertexAndRemapIndices(Vertex* vertexToRemove) {
        if (!m_ActiveVertexList) return;
        int removedIndex = -1;
        for (int i = 0; i < getVertexCount(); ++i) {
            if (getVertex(i) == vertexToRemove) { removedIndex = i; break; }
        }
        if (removedIndex != -1) removeVertex(removedIndex);
    }

    Vertex* Mesh2D::findVertexByName(const std::string& name) {
        if (!m_ActiveVertexList) {
            return nullptr;
        }
        for (Vertex& vertex : m_ActiveVertexList->getVertices()) {
            if (vertex.getName() == name) {
                return &vertex;
            }
        }
        return nullptr;
    }

    const Vertex* Mesh2D::findVertexByName(const std::string& name) const {
        if (!m_ActiveVertexList) {
            return nullptr;
        }
        for (const Vertex& vertex : m_ActiveVertexList->getVertices()) {
            if (vertex.getName() == name) {
                return &vertex;
            }
        }
        return nullptr;
    }

    // ==================== 变换与状态 ====================
    void Mesh2D::resetToOriginal() {
        if (m_ActiveVertexList) {
            for (auto& v : m_ActiveVertexList->vertices) { v.resetToOriginal(); }
            markDirty();
        }
    }

    void Mesh2D::saveAsOriginal() {
        if (!m_ActiveVertexList || !m_ModelPart) return;
        glm::mat3 inverseWorld = glm::inverse(m_ModelPart->getWorldTransform());
        for (auto& v : m_ActiveVertexList->vertices) {
            glm::vec3 transformed = inverseWorld * glm::vec3(v.position, 1.0f);
            v.originalPosition = glm::vec2(transformed);
        }
        for (Vertex* vPtr : m_DeformationControlVertices) {
            glm::vec3 transformed = inverseWorld * glm::vec3(vPtr->position, 1.0f);
            vPtr->originalPosition = glm::vec2(transformed);
        }
    }

    void Mesh2D::transformVertices(const std::function<void(glm::vec2&, int)>& transformer) {
        if (m_ActiveVertexList) {
            for (int i = 0; i < getVertexCount(); ++i) { transformer(getVertex(i)->position, i); }
            markDirty();
        }
    }

    void Mesh2D::markDirty() { m_IsDirty = true; m_BoundsDirty = true; }
    bool Mesh2D::isDirty() const { return m_IsDirty; }

    // ==================== 边界框与碰撞检测 ====================
    void Mesh2D::updateBounds() const {
        m_Bounds.reset();
        if (m_ActiveVertexList) {
            for (const auto& v : m_ActiveVertexList->vertices) { m_Bounds.expand(v.position); }
        }
        m_BoundsDirty = false;
    }

    const util::BoundingBox& Mesh2D::getBounds() const {
        if (m_BoundsDirty) updateBounds();
        return m_Bounds;
    }

    bool Mesh2D::containsPoint(float x, float y, bool precise) const {
        if (!getBounds().contains(x, y)) return false;
        if (precise) return isPointInMeshGeometry(x, y);
        return true;
    }

    bool Mesh2D::containsPoint(const glm::vec2& point, bool precise) const { return containsPoint(point.x, point.y, precise); }

    bool Mesh2D::isPointInMeshGeometry(float x, float y) const {
        if (!m_ActiveVertexList || getVertexCount() < 3) return false;
        const auto& indices = m_ActiveVertexList->getIndices();
        for (size_t i = 0; i < indices.size(); i += 3) {
            const auto& v1 = m_ActiveVertexList->get(indices[i]).position;
            const auto& v2 = m_ActiveVertexList->get(indices[i + 1]).position;
            const auto& v3 = m_ActiveVertexList->get(indices[i + 2]).position;
            if (isPointInTriangle({ x,y }, v1, v2, v3)) return true;
        }
        return false;
    }

    // ==================== 渲染 ====================
    void Mesh2D::uploadToGPU() {
        if (m_IsUploaded) return;
        RenderSystem::assertOnRenderThreadOrInit();
        int vertCount = getVertexCount();
        if (vertCount == 0 || m_ActiveVertexList->getIndices().empty()) return;
        std::vector<float> interleavedData; interleavedData.reserve(vertCount * 4);
        for (int i = 0; i < vertCount; ++i) {
            const auto* v = getVertex(i);
            interleavedData.insert(interleavedData.end(), { v->position.x, v->position.y, v->uv.x, v->uv.y });
        }
        m_VaoID = RenderSystem::GenVertexArrays(); RenderSystem::BindVertexArray(m_VaoID);
        m_VboID = RenderSystem::GenBuffers(); RenderSystem::BindBuffer(GL_ARRAY_BUFFER, m_VboID);
        RenderSystem::BufferData(GL_ARRAY_BUFFER, interleavedData.size() * sizeof(float), interleavedData.data(), GL_DYNAMIC_DRAW);
        const auto& indices = m_ActiveVertexList->getIndices();
        m_EboID = RenderSystem::GenBuffers(); RenderSystem::BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EboID);
        RenderSystem::BufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(int), indices.data(), GL_DYNAMIC_DRAW);
        GLsizei stride = 4 * sizeof(float);
        RenderSystem::enableVertexAttribArray(0); RenderSystem::vertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, stride, (void*)0);
        RenderSystem::enableVertexAttribArray(1); RenderSystem::vertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (void*)(2 * sizeof(float)));
        RenderSystem::BindVertexArray(0);
        m_IndexCount = indices.size(); m_IsUploaded = true; m_IsDirty = false;
    }

    void Mesh2D::deleteGPU() {
        if (!m_IsUploaded) return;
        RenderSystem::DeleteBuffers(m_VboID); RenderSystem::DeleteBuffers(m_EboID); RenderSystem::DeleteVertexArrays(m_VaoID);
        m_VboID = m_EboID = m_VaoID = 0; m_IsUploaded = false;
    }

    void Mesh2D::draw(int shaderProgram, const glm::mat3& modelMatrix) {
        if (!m_IsVisible || getVertexCount() == 0) return;
        if (m_IsDirty) { deleteGPU(); uploadToGPU(); }
        else if (!m_IsUploaded) { uploadToGPU(); }
        if (!m_IsUploaded) return;
        GLint prevProgram = RenderSystem::getCurrentProgram();
        RenderSystem::useProgram(shaderProgram);
        RenderSystem::activeTexture(GL_TEXTURE0);
        if (m_Texture) m_Texture->bind(); else RenderSystem::bindTexture(0);
        RenderSystem::uniform1i(RenderSystem::getUniformLocation(shaderProgram, "uTexture"), 0);
        RenderSystem::uniformMatrix3(RenderSystem::getUniformLocation(shaderProgram, "uModelMatrix"), modelMatrix);
        RenderSystem::BindVertexArray(m_VaoID);
        RenderSystem::drawElements(GL_TRIANGLES, m_IndexCount, GL_UNSIGNED_INT, nullptr);
        RenderSystem::BindVertexArray(0);
        if (m_Texture) m_Texture->unbind();
        RenderSystem::useProgram(prevProgram);
        if (m_IsSelected) { /* 绘制选中框逻辑 */ }
    }

    // ==================== Getters & Setters ====================
    const std::string& Mesh2D::getName() const { return m_Name; }
    void Mesh2D::setName(const std::string& name) { m_Name = name; }
    std::vector<float> Mesh2D::getVertices() const {
        std::vector<float> verts; if (!m_ActiveVertexList) return verts;
        verts.reserve(getVertexCount() * 2);
        for (const auto& v : m_ActiveVertexList->vertices) { verts.push_back(v.position.x); verts.push_back(v.position.y); }
        return verts;
    }
    std::vector<float> Mesh2D::getUVs() const {
        std::vector<float> uvs; if (!m_ActiveVertexList) return uvs;
        uvs.reserve(getVertexCount() * 2);
        for (const auto& v : m_ActiveVertexList->vertices) { uvs.push_back(v.uv.x); uvs.push_back(v.uv.y); }
        return uvs;
    }
    std::vector<float> Mesh2D::getOriginalVertices() const {
        std::vector<float> verts; if (!m_ActiveVertexList) return verts;
        verts.reserve(getVertexCount() * 2);
        for (const auto& v : m_ActiveVertexList->vertices) { verts.push_back(v.originalPosition.x); verts.push_back(v.originalPosition.y); }
        return verts;
    }
    std::vector<int> Mesh2D::getIndices() const { return m_ActiveVertexList ? m_ActiveVertexList->getIndices() : std::vector<int>{}; }
    int Mesh2D::getVertexCount() const { return m_ActiveVertexList ? m_ActiveVertexList->size() : 0; }
    Vertex* Mesh2D::getVertex(int index) { return m_ActiveVertexList ? &m_ActiveVertexList->vertices[index] : nullptr; }
    const Vertex* Mesh2D::getVertex(int index) const { return m_ActiveVertexList ? &m_ActiveVertexList->vertices[index] : nullptr; }
    const glm::vec2& Mesh2D::getPivot() const { return m_Pivot; }
    const glm::vec2& Mesh2D::getOriginalPivot() const { return m_OriginalPivot; }
    bool Mesh2D::isVisible() const { return m_IsVisible; }
    void Mesh2D::setVisible(bool visible) { m_IsVisible = visible; }
    Mesh2D::DrawMode Mesh2D::getDrawMode() const { return m_DrawMode; }
    void Mesh2D::setDrawMode(DrawMode mode) { m_DrawMode = mode; }
    bool Mesh2D::isSelected() const { return m_IsSelected.load(); }
    void Mesh2D::setSelected(bool selected) { m_IsSelected.store(selected); }
    ModelPart* Mesh2D::getModelPart() const { return m_ModelPart; }
    util::VertexList* Mesh2D::getActiveVertexList() const { return m_ActiveVertexList.get(); }
    const std::vector<Vertex*>& Mesh2D::getDeformationControlVertices() const { return m_DeformationControlVertices; }

    // ==================== 静态工厂方法 ====================
    std::unique_ptr<Mesh2D> Mesh2D::createQuad(const std::string& name, float width, float height) {
        float hw = width / 2.0f, hh = height / 2.0f;
        std::vector<float> vertices = { -hw,-hh, hw,-hh, hw,hh, -hw,hh, 0,-hh, hw,0, 0,hh, -hw,0, 0,0 };
        std::vector<float> uvs = { 0,1, 1,1, 1,0, 0,0, 0.5f,1, 1,0.5f, 0.5f,0, 0,0.5f, 0.5f,0.5f };
        std::vector<int> indices = { 8,0,4, 8,4,1, 8,1,5, 8,5,2, 8,2,6, 8,6,3, 8,3,7, 8,7,0 };
        return std::make_unique<Mesh2D>(name, vertices, uvs, indices);
    }

    std::unique_ptr<Mesh2D> Mesh2D::createCircle(const std::string& name, float radius, int segments) {
        if (segments < 3) segments = 3;
        std::vector<float> vertices, uvs; std::vector<int> indices;
        vertices.insert(vertices.end(), { 0.0f, 0.0f }); uvs.insert(uvs.end(), { 0.5f, 0.5f });
        for (int i = 0; i < segments; ++i) {
            float angle = i * 2.0f * 3.14159265f / segments;
            vertices.push_back(std::cos(angle) * radius); vertices.push_back(std::sin(angle) * radius);
            uvs.push_back(std::cos(angle) * 0.5f + 0.5f); uvs.push_back(std::sin(angle) * 0.5f + 0.5f);
        }
        for (int i = 1; i <= segments; ++i) {
            indices.insert(indices.end(), { 0, i, (i % segments) + 1 });
        }
        return std::make_unique<Mesh2D>(name, vertices, uvs, indices);
    }

} // namespace Vivid2D