#include "model.h"
#include "zlog.h"
#include "assimp/Importer.hpp"
#include "assimp/scene.h"
#include "assimp/postprocess.h"
#include "asset/asset_manager.h"
namespace engineapi {
    void Model::BeginLoad()
    {
        Asset::BeginLoad();
        // 用ASSIMP加载模型文件
        Assimp::Importer importer;
        const aiScene* scene = importer.ReadFile(mName, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace
            | aiProcess_FixInfacingNormals | aiProcess_FlipWindingOrder | aiProcess_LimitBoneWeights);

        // 检查异常
        if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
        {
            zlog::error("ASSIMP: {}", importer.GetErrorString());
            return;
        }
        ProcessNode(scene->mRootNode, scene);
    }
    void Model::ProcessNode(const aiNode* pNode, const aiScene* pScene)
    {
        // 处理Mesh数据
        for (unsigned int i = 0; i < pNode->mNumMeshes; i++)
        {
            // aiNode仅包含索引来获取aiScene中的实际对象
            // aiScene包含所有数据，aiNode只是为了让数据组织起来(比如记录节点之间的关系)
            aiMesh* mesh = pScene->mMeshes[pNode->mMeshes[i]];
            mMeshes.push_back(ProcessMesh(mesh));
        }

        // 加载骨骼数据
        //pBoneNode->name = pNode->mName.C_Str();
        //pBoneNode->transform = aiMatrix4x4ToMatrix4(pNode->mTransformation);

        // 递归处理子节点
        for (unsigned int i = 0; i < pNode->mNumChildren; i++)
        {
            //pBoneNode->children.push_back(new BoneNode());
            ProcessNode(pNode->mChildren[i], pScene);
        }
    }
    Mesh* Model::ProcessMesh(const aiMesh* mesh) {
        // data to fill
        parray<Vertex> vertices(mesh->mNumVertices, sizeof(BoneVertex));
        parray<Vertex> vertices2(mesh->mNumVertices, sizeof(BoneVertex));
        BoneVertex vertex2;
        vertices2.push_back(vertex2);
        vector<uint32_t> indices;
        // Walk through each of the mesh's vertices
        for (unsigned int i = 0; i < mesh->mNumVertices; i++)
        {
            BoneVertex vertex;
            Vector3 vector; // we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to Vector3 class so we transfer the data to this placeholder Vector3 first.

            // positions
            vector.x = mesh->mVertices[i].x;
            vector.y = mesh->mVertices[i].y;
            vector.z = mesh->mVertices[i].z;
            vertex.Position = vector;

            // normals
            vector.x = mesh->mNormals[i].x;
            vector.y = mesh->mNormals[i].y;
            vector.z = mesh->mNormals[i].z;
            vertex.Normal = vector;

            // texture coordinates
            if (mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
            {
                Vector2 vec;
                // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't 
                // use models where a vertex can have multiple texture coordinates so we always take the first set (0).
                vec.x = mesh->mTextureCoords[0][i].x;
                vec.y = mesh->mTextureCoords[0][i].y;
                vertex.TexCoords = vec;
            }
            else
            {
                vertex.TexCoords = Vector2(0.0f, 0.0f);
            }

            // tangent and bitangent
            if (mesh->HasTangentsAndBitangents())
            {
                vector.x = mesh->mTangents[i].x;
                vector.y = mesh->mTangents[i].y;
                vector.z = mesh->mTangents[i].z;
                vertex.Tangent = vector;
            }
            else
            {
                vertex.Tangent = Vector3(0.0f, 0.0f, 0.0f);
            }
            vertices.push_back(vertex);
        }
        // now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
        for (unsigned int i = 0; i < mesh->mNumFaces; i++)
        {
            const aiFace& face = mesh->mFaces[i];
            // retrieve all indices of the face and store them in the indices vector
            for (unsigned int j = 0; j < face.mNumIndices; j++)
            {
                indices.push_back(face.mIndices[j]);
            }
        }
        Mesh* model = new Mesh(mesh->mName.C_Str(), mFlags, vertices, indices);
        return model;
    }
    void Model::Use()
    {

    }
}

