#ifndef RENDER_RENDER_OBJECT_H
#define RENDER_RENDER_OBJECT_H

#include <render_type_def.h>
#include <DirectXMath.h>
#include <d3d11.h>
#include <wrl/client.h>
#include "shared_model.h"
#include "shader.h"

class RenderMesh {
public:
    struct alignas(16) CBPerObj {
        DirectX::XMFLOAT4X4 world;
        // [PBR-ADD] 非均匀缩放下正确变换法线。
        DirectX::XMFLOAT4X4 worldInvTranspose;
    };
    static_assert(sizeof(CBPerObj) % 16 == 0);

public:
    ~RenderMesh() = default;
    [[nodiscard]] Material *GetMaterial() const noexcept { return m_material; }
    [[nodiscard]] bool CastShadow() const noexcept { return true; }
    void SetMaterial(Material *mat) noexcept { m_material = mat; }

    // PerObj CBuffer
    void Update_CBPerObj(ID3D11DeviceContext *ctx);

    // main pass
    void Update_BindMat(ID3D11DeviceContext *ctx);
    void Draw_Main(ID3D11DeviceContext *ctx) const;

    // shadow pass
    void Draw_Shadow(ID3D11DeviceContext *ctx) const;

private:
    friend class RenderObject;
    RenderMesh(const RenderObject *obj, UINT idx, Material *dftMat, ID3D11Device *device);
    bool InitGpuResources(ID3D11Device *device);
    void OnBaseObjMatrixChanged();

private:
    bool b_baseObj_dirty{true};

    const unsigned int m_modelIdx;
    const RenderObject *const m_baseRenderObj;
    const DirectX::XMFLOAT4X4 m_localMatrix;
    const SharedMesh *const m_sharedMesh;
    Material *m_material;

    // GPU资源 整个实例(以model为原本)的 worldMatrix X 自己的obj matrix, 作为shader的world输入
    CBPerObj m_cb_state{}; //每次UPDATE前乘以父obj的world后提交给GPU
    Microsoft::WRL::ComPtr<ID3D11Buffer> m_cbuffer;


};

class RenderObject {
public:
    //[sub]
    // struct alignas(16) CBPerObj {
    //     DirectX::XMFLOAT4X4 world;
    // };

public: //static
    static RenderObject *S_CreateRenderObj(SharedModel *model, Material *dftMat, ID3D11Device *device);

public: //instance
    [[nodiscard]] std::vector<RenderMesh> &GetRenderMeshes() noexcept { return m_renderMeshes; };
    void SetObjWorldMatrix(const DirectX::XMFLOAT4X4 &matrix) noexcept {
        m_worldMatrix = matrix;
        for (auto &item: m_renderMeshes) { item.OnBaseObjMatrixChanged(); }
    }
    bool SetMeshMaterial(int meshId, Material *mat);

private:
    RenderObject(SharedModel *model, Material *dftMat, ID3D11Device *device);
    ~RenderObject();

private:
    friend class RenderMesh;

    DirectX::XMFLOAT4X4 m_worldMatrix{}; // 更新时写入这里,update时读取这里
    SharedModel *m_model{};
    std::vector<RenderMesh> m_renderMeshes;


};


















#endif //RENDER_RENDER_OBJECT_H
