text: #pragma once
  
  #include <memory>
  #include <optional>
  #include <utility>
  #include <vector>
  
  #include "Runtime/CToken.hpp"
  #include "Runtime/Character/CSkinRules.hpp"
  #include "Runtime/Graphics/CModel.hpp"
  
  #include <zeus/CVector3f.hpp>
  
  namespace urde {
  class CCharLayoutInfo;
  class CModel;
  class CPoseAsTransforms;
  class CVertexMorphEffect;
  class IObjectStore;
  
  class CSkinnedModel {
    friend class CBooModel;
    std::unique_ptr<CBooModel> m_modelInst;
    TLockedToken<CModel> x4_model;
    TLockedToken<CSkinRules> x10_skinRules;
    TLockedToken<CCharLayoutInfo> x1c_layoutInfo;
    std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>> m_vertWorkspace;
    bool m_modifiedVBO = false;
  
  public:
    enum class EDataOwnership { Zero, One };
    CSkinnedModel(TLockedToken<CModel> model, TLockedToken<CSkinRules> skinRules,
                  TLockedToken<CCharLayoutInfo> layoutInfo, int shaderIdx, int drawInsts);
    CSkinnedModel(IObjectStore& store, CAssetId model, CAssetId skinRules, CAssetId layoutInfo, int shaderIdx,
                  int drawInsts);
    std::unique_ptr<CSkinnedModel> Clone(int shaderIdx = 0, int drawInsts = 1) const {
      return std::make_unique<CSkinnedModel>(x4_model, x10_skinRules, x1c_layoutInfo, shaderIdx, drawInsts);
    }
  
    const TLockedToken<CModel>& GetModel() const { return x4_model; }
    const std::unique_ptr<CBooModel>& GetModelInst() const { return m_modelInst; }
    const TLockedToken<CSkinRules>& GetSkinRules() const { return x10_skinRules; }
    void SetLayoutInfo(const TLockedToken<CCharLayoutInfo>& inf) { x1c_layoutInfo = inf; }
    const TLockedToken<CCharLayoutInfo>& GetLayoutInfo() const { return x1c_layoutInfo; }
  
    void Calculate(const CPoseAsTransforms& pose, const CModelFlags& drawFlags,
                   const std::optional<CVertexMorphEffect>& morphEffect, const float* morphMagnitudes);
    void Draw(const CModelFlags& drawFlags) const;
  
    using FPointGenerator = void (*)(void* item, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn);
    static void SetPointGeneratorFunc(void* ctx, FPointGenerator func) {
      g_PointGenFunc = func;
      g_PointGenCtx = ctx;
    }
    static void ClearPointGeneratorFunc() { g_PointGenFunc = nullptr; }
    static FPointGenerator g_PointGenFunc;
    static void* g_PointGenCtx;
  };
  
  class CMorphableSkinnedModel : public CSkinnedModel {
    std::unique_ptr<float[]> x40_morphMagnitudes;
  
  public:
    CMorphableSkinnedModel(IObjectStore& store, CAssetId model, CAssetId skinRules, CAssetId layoutInfo, int shaderIdx,
                           int drawInsts);
    const float* GetMorphMagnitudes() const { return x40_morphMagnitudes.get(); }
  };
  
  } // namespace urde
  