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>
read(const Structure & s,T * p,const size_t cnt,const FileDatabase & db)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 
CustomDataTypeDescriptionAssimp::Blender::CustomDataTypeDescription76     CustomDataTypeDescription(PRead read, PCreate create, PDestroy destroy) :
77             Read(read), Create(create), Destroy(destroy) {}
78 };
79 
80 /**
81         *   @brief  helper macro to define Structure type specific CustomDataTypeDescription
82         *   @note   IMPL_STRUCT_READ for same ty must be used earlier to implement the typespecific read function
83         */
84 #define DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(ty) \
85     CustomDataTypeDescription { &read##ty, &create##ty, &destroy##ty }
86 
87 /**
88         *   @brief  helper macro to define CustomDataTypeDescription for UNSUPPORTED type
89         */
90 #define DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION \
91     CustomDataTypeDescription { nullptr, nullptr, nullptr }
92 
93 /**
94         *   @brief  descriptors for data pointed to from CustomDataLayer.data
95         *   @note   some of the CustomData uses already well defined Structures
96         *           other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures
97         *           use a special readfunction for that cases
98         */
99 std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { { DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
100         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
101         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
102         DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge),
103         DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MFace),
104         DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTFace),
105         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
106         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
107         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
108         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
109 
110         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
111         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
112         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
113         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
114         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
115         DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTexPoly),
116         DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopUV),
117         DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopCol),
118         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
119         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
120 
121         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
122         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
123         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
124         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
125         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
126         DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MPoly),
127         DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoop),
128         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
129         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
130         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
131 
132         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
133         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
134         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
135         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
136         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
137         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
138         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
139         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
140         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
141         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
142 
143         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
144         DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION } };
145 
isValidCustomDataType(const int cdtype)146 bool isValidCustomDataType(const int cdtype) {
147     return cdtype >= 0 && cdtype < CD_NUMTYPES;
148 }
149 
readCustomData(std::shared_ptr<ElemBase> & out,const int cdtype,const size_t cnt,const FileDatabase & db)150 bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
151     if (!isValidCustomDataType(cdtype)) {
152         throw Error("CustomData.type ", cdtype, " out of index");
153     }
154 
155     const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];
156     if (cdtd.Read && cdtd.Create && cdtd.Destroy && cnt > 0) {
157         // allocate cnt elements and parse them from file
158         out.reset(cdtd.Create(cnt), cdtd.Destroy);
159         return cdtd.Read(out.get(), cnt, db);
160     }
161     return false;
162 }
163 
getCustomDataLayer(const CustomData & customdata,const CustomDataType cdtype,const std::string & name)164 std::shared_ptr<CustomDataLayer> getCustomDataLayer(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
165     for (auto it = customdata.layers.begin(); it != customdata.layers.end(); ++it) {
166         if (it->get()->type == cdtype && name == it->get()->name) {
167             return *it;
168         }
169     }
170     return nullptr;
171 }
172 
getCustomDataLayerData(const CustomData & customdata,const CustomDataType cdtype,const std::string & name)173 const ElemBase *getCustomDataLayerData(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
174     const std::shared_ptr<CustomDataLayer> pLayer = getCustomDataLayer(customdata, cdtype, name);
175     if (pLayer && pLayer->data) {
176         return pLayer->data.get();
177     }
178     return nullptr;
179 }
180 } // namespace Blender
181 } // namespace Assimp
182