| 1 | #include "BlenderCustomData.h" |
| 2 | #include "BlenderDNA.h" |
| 3 | #include <array> |
| 4 | #include <functional> |
| 5 | |
| 6 | namespace Assimp { |
| 7 | namespace Blender { |
| 8 | /** |
| 9 | * @brief read/convert of Structure array to memory |
| 10 | */ |
| 11 | template<typename T> |
| 12 | bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) { |
| 13 | for (size_t i = 0; i < cnt; ++i) { |
| 14 | T read; |
| 15 | s.Convert(read, db); |
| 16 | *p = read; |
| 17 | p++; |
| 18 | } |
| 19 | return true; |
| 20 | } |
| 21 | |
| 22 | /** |
| 23 | * @brief pointer to function read memory for n CustomData types |
| 24 | */ |
| 25 | typedef bool (*PRead)(ElemBase *pOut, const size_t cnt, const FileDatabase &db); |
| 26 | typedef ElemBase * (*PCreate)(const size_t cnt); |
| 27 | typedef void(*PDestroy)(ElemBase *); |
| 28 | |
| 29 | #define IMPL_STRUCT_READ(ty) \ |
| 30 | bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \ |
| 31 | ty *ptr = dynamic_cast<ty*>(v); \ |
| 32 | if (nullptr == ptr) { \ |
| 33 | return false; \ |
| 34 | } \ |
| 35 | return read<ty>(db.dna[#ty], ptr, cnt, db); \ |
| 36 | } |
| 37 | |
| 38 | #define IMPL_STRUCT_CREATE(ty) \ |
| 39 | ElemBase *create##ty(const size_t cnt) { \ |
| 40 | return new ty[cnt]; \ |
| 41 | } |
| 42 | |
| 43 | #define IMPL_STRUCT_DESTROY(ty) \ |
| 44 | void destroy##ty(ElemBase *pE) { \ |
| 45 | ty *p = dynamic_cast<ty *>(pE); \ |
| 46 | delete[]p; \ |
| 47 | } |
| 48 | |
| 49 | /** |
| 50 | * @brief helper macro to define Structure functions |
| 51 | */ |
| 52 | #define IMPL_STRUCT(ty) \ |
| 53 | IMPL_STRUCT_READ(ty) \ |
| 54 | IMPL_STRUCT_CREATE(ty) \ |
| 55 | IMPL_STRUCT_DESTROY(ty) |
| 56 | |
| 57 | // supported structures for CustomData |
| 58 | IMPL_STRUCT(MVert) |
| 59 | IMPL_STRUCT(MEdge) |
| 60 | IMPL_STRUCT(MFace) |
| 61 | IMPL_STRUCT(MTFace) |
| 62 | IMPL_STRUCT(MTexPoly) |
| 63 | IMPL_STRUCT(MLoopUV) |
| 64 | IMPL_STRUCT(MLoopCol) |
| 65 | IMPL_STRUCT(MPoly) |
| 66 | IMPL_STRUCT(MLoop) |
| 67 | |
| 68 | /** |
| 69 | * @brief describes the size of data and the read function to be used for single CustomerData.type |
| 70 | */ |
| 71 | struct CustomDataTypeDescription { |
| 72 | PRead Read; ///< function to read one CustomData type element |
| 73 | PCreate Create; ///< function to allocate n type elements |
| 74 | PDestroy Destroy; |
| 75 | |
| 76 | CustomDataTypeDescription(PRead read, PCreate create, PDestroy destroy) |
| 77 | : Read(read) |
| 78 | , Create(create) |
| 79 | , Destroy(destroy) |
| 80 | {} |
| 81 | }; |
| 82 | |
| 83 | |
| 84 | /** |
| 85 | * @brief helper macro to define Structure type specific CustomDataTypeDescription |
| 86 | * @note IMPL_STRUCT_READ for same ty must be used earlier to implement the typespecific read function |
| 87 | */ |
| 88 | #define DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(ty) \ |
| 89 | CustomDataTypeDescription{&read##ty, &create##ty, &destroy##ty} |
| 90 | |
| 91 | /** |
| 92 | * @brief helper macro to define CustomDataTypeDescription for UNSUPPORTED type |
| 93 | */ |
| 94 | #define DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION \ |
| 95 | CustomDataTypeDescription{nullptr, nullptr, nullptr} |
| 96 | |
| 97 | /** |
| 98 | * @brief descriptors for data pointed to from CustomDataLayer.data |
| 99 | * @note some of the CustomData uses already well defined Structures |
| 100 | * other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures |
| 101 | * use a special readfunction for that cases |
| 102 | */ |
| 103 | std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { ._M_elems: { |
| 104 | DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert), |
| 105 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 106 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 107 | DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge), |
| 108 | DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MFace), |
| 109 | DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTFace), |
| 110 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 111 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 112 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 113 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 114 | |
| 115 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 116 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 117 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 118 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 119 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 120 | DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTexPoly), |
| 121 | DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopUV), |
| 122 | DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopCol), |
| 123 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 124 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 125 | |
| 126 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 127 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 128 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 129 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 130 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 131 | DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MPoly), |
| 132 | DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoop), |
| 133 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 134 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 135 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 136 | |
| 137 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 138 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 139 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 140 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 141 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 142 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 143 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 144 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 145 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 146 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 147 | |
| 148 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, |
| 149 | DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION |
| 150 | }}; |
| 151 | |
| 152 | |
| 153 | bool isValidCustomDataType(const int cdtype) { |
| 154 | return cdtype >= 0 && cdtype < CD_NUMTYPES; |
| 155 | } |
| 156 | |
| 157 | bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) { |
| 158 | if (!isValidCustomDataType(cdtype)) { |
| 159 | throw Error((Formatter::format(), "CustomData.type " , cdtype, " out of index" )); |
| 160 | } |
| 161 | |
| 162 | const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype]; |
| 163 | if (cdtd.Read && cdtd.Create && cdtd.Destroy && cnt > 0) { |
| 164 | // allocate cnt elements and parse them from file |
| 165 | out.reset(p: cdtd.Create(cnt), d: cdtd.Destroy); |
| 166 | return cdtd.Read(out.get(), cnt, db); |
| 167 | } |
| 168 | return false; |
| 169 | } |
| 170 | |
| 171 | std::shared_ptr<CustomDataLayer> getCustomDataLayer(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) { |
| 172 | for (auto it = customdata.layers.begin(); it != customdata.layers.end(); ++it) { |
| 173 | if (it->get()->type == cdtype && name == it->get()->name) { |
| 174 | return *it; |
| 175 | } |
| 176 | } |
| 177 | return nullptr; |
| 178 | } |
| 179 | |
| 180 | const ElemBase * getCustomDataLayerData(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) |
| 181 | { |
| 182 | const std::shared_ptr<CustomDataLayer> pLayer = getCustomDataLayer(customdata, cdtype, name); |
| 183 | if (pLayer && pLayer->data) { |
| 184 | return pLayer->data.get(); |
| 185 | } |
| 186 | return nullptr; |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | |