1 #pragma once |
|
2 #include "main.h" |
|
3 #include "colors.h" |
|
4 |
|
5 class Vec3Editor; |
|
6 class MatrixEditor; |
|
7 |
|
8 namespace ldraw |
|
9 { |
|
10 enum CircularPrimitiveType |
|
11 { |
|
12 Circle, |
|
13 Disc |
|
14 }; |
|
15 enum class Property; |
|
16 struct PropertyKeyValue; |
|
17 template<Property property> |
|
18 struct PropertyTraits |
|
19 { |
|
20 static constexpr bool defined = false; |
|
21 }; |
|
22 } |
|
23 |
|
24 Q_DECLARE_METATYPE(ldraw::CircularPrimitiveType) |
|
25 |
|
26 /** |
|
27 * Different properties |
|
28 */ |
|
29 enum class ldraw::Property |
|
30 { |
|
31 Color, // Color of the object |
|
32 Text, // Text contained in a comment |
|
33 Point0, // First vertex in a polygon or edge line |
|
34 Point1, // Second vertex in a polygon or edge line |
|
35 Point2, // Third vertex in a polygon |
|
36 Point3, // Fourth vertex in a quadrilateral |
|
37 Transformation, // 4x4 transformation matrix of a subfile reference |
|
38 ReferenceName, // Subfile reference name |
|
39 IsInverted, // Whether or not the object has been inverted with BFC INVERTNEXT |
|
40 ErrorMessage, // For error lines, why parsing failed |
|
41 CircularPrimitiveType, // Type of circular primitive (circle, disc, ...) |
|
42 Segments, // Amount of circular segments this primitive covers (numerator) |
|
43 Divisions, // Amount of segments in the circle this primitive fits in (8, 16, 48, ...) |
|
44 }; |
|
45 |
|
46 Q_DECLARE_METATYPE(ldraw::Property) |
|
47 |
|
48 // Mapping of properties to types |
|
49 #define LDFORGE_DEFINE_PROPERTY_TYPE(PROPERTY, TYPE) \ |
|
50 namespace ldraw \ |
|
51 { \ |
|
52 template<> struct PropertyTraits<ldraw::Property::PROPERTY> \ |
|
53 { \ |
|
54 using type = TYPE; \ |
|
55 static constexpr std::array<char, 256> name{#PROPERTY}; \ |
|
56 static constexpr bool defined = true; \ |
|
57 }; \ |
|
58 } |
|
59 |
|
60 LDFORGE_DEFINE_PROPERTY_TYPE(Color, ldraw::Color) |
|
61 LDFORGE_DEFINE_PROPERTY_TYPE(Text, QString) |
|
62 LDFORGE_DEFINE_PROPERTY_TYPE(Point0, glm::vec3) |
|
63 LDFORGE_DEFINE_PROPERTY_TYPE(Point1, glm::vec3) |
|
64 LDFORGE_DEFINE_PROPERTY_TYPE(Point2, glm::vec3) |
|
65 LDFORGE_DEFINE_PROPERTY_TYPE(Point3, glm::vec3) |
|
66 LDFORGE_DEFINE_PROPERTY_TYPE(Transformation, glm::mat4) |
|
67 LDFORGE_DEFINE_PROPERTY_TYPE(ReferenceName, QString) |
|
68 LDFORGE_DEFINE_PROPERTY_TYPE(IsInverted, bool) |
|
69 LDFORGE_DEFINE_PROPERTY_TYPE(ErrorMessage, QString) |
|
70 LDFORGE_DEFINE_PROPERTY_TYPE(CircularPrimitiveType, ldraw::CircularPrimitiveType) |
|
71 LDFORGE_DEFINE_PROPERTY_TYPE(Segments, int) |
|
72 LDFORGE_DEFINE_PROPERTY_TYPE(Divisions, int) |
|
73 |
|
74 #define LDRAW_OBJECT_HANDLE_SET_PROPERTY(PROPERTY, HANDLER) \ |
|
75 {this->handle<ldraw::Property::PROPERTY>(result, pair, \ |
|
76 [&](const ldraw::PropertyType<ldraw::Property::PROPERTY>& value) HANDLER);} |
|
77 |
|
78 // Generics |
|
79 namespace ldraw |
|
80 { |
|
81 template<ldraw::Property property> |
|
82 using PropertyType = typename PropertyTraits<property>::type; |
|
83 |
|
84 template<ldraw::Property property> |
|
85 inline const char* PROPERTY_NAME = PropertyTraits<property>::name; |
|
86 |
|
87 constexpr int MAX_POINTS = 4; |
|
88 |
|
89 struct PropertyKeyValue |
|
90 { |
|
91 Property key; |
|
92 QVariant value; |
|
93 }; |
|
94 |
|
95 constexpr Property pointProperty(int n) |
|
96 { |
|
97 Q_ASSERT(n >= 0 and n < MAX_POINTS); |
|
98 return static_cast<Property>(static_cast<int>(Property::Point0) + n); |
|
99 } |
|
100 |
|
101 struct PropertyTrait |
|
102 { |
|
103 ldraw::Property property; |
|
104 std::array<char, 256> name; |
|
105 int type; |
|
106 }; |
|
107 |
|
108 namespace detail |
|
109 { |
|
110 template<int N> |
|
111 constexpr int propertyCountHelper() |
|
112 { |
|
113 if constexpr (ldraw::PropertyTraits<static_cast<Property>(N)>::defined) |
|
114 { |
|
115 return propertyCountHelper<N + 1>(); |
|
116 } |
|
117 else |
|
118 { |
|
119 return N; |
|
120 } |
|
121 } |
|
122 |
|
123 template<int k> |
|
124 constexpr PropertyTrait getPropertyTrait() |
|
125 { |
|
126 constexpr auto property = static_cast<ldraw::Property>(k); |
|
127 using trait = ldraw::PropertyTraits<property>; |
|
128 return PropertyTrait{ |
|
129 property, |
|
130 trait::name, |
|
131 qMetaTypeId<typename trait::type>() |
|
132 }; |
|
133 } |
|
134 |
|
135 template<int... Ints> |
|
136 auto getPropertyTraits(std::integer_sequence<int, Ints...>) |
|
137 { |
|
138 return std::array<PropertyTrait, sizeof...(Ints)>{getPropertyTrait<Ints>()...}; |
|
139 } |
|
140 } |
|
141 |
|
142 constexpr int NUM_PROPERTIES = detail::propertyCountHelper<0>(); |
|
143 inline const auto& traits() |
|
144 { |
|
145 static std::array<PropertyTrait, NUM_PROPERTIES> result = |
|
146 detail::getPropertyTraits(std::make_integer_sequence<int, NUM_PROPERTIES>()); |
|
147 return result; |
|
148 } |
|
149 |
|
150 inline const auto& traits(ldraw::Property property) |
|
151 { |
|
152 return traits()[static_cast<int>(property)]; |
|
153 } |
|
154 |
|
155 template<typename T, std::size_t... Ints> |
|
156 constexpr auto makeIndexArray(std::index_sequence<Ints...>) |
|
157 { |
|
158 return std::array{static_cast<T>(Ints)...}; |
|
159 } |
|
160 |
|
161 constexpr auto ALL_PROPERTIES = makeIndexArray<Property>(std::make_index_sequence<NUM_PROPERTIES>{}); |
|
162 |
|
163 template<typename T> |
|
164 bool testPropertyType(ldraw::Property property) |
|
165 { |
|
166 return qMetaTypeId<T>() == ldraw::traits(property).type; |
|
167 } |
|
168 } |
|