1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "CarModelConfigReader.h"
18 #include "ConfigReaderUtil.h"
19 #include "MathHelp.h"
20 #include "core_lib.h"
21
22 #include <android-base/logging.h>
23 #include <tinyxml2.h>
24 #include <sstream>
25 #include <string>
26 #include <utility>
27
28 namespace android {
29 namespace hardware {
30 namespace automotive {
31 namespace sv {
32 namespace V1_0 {
33 namespace implementation {
34
35 // Macro returning IoStatus::ERROR_READ_ANIMATION if condition evaluates to false.
36 #define RETURN_ERROR_STATUS_IF_FALSE(cond) \
37 do { \
38 if (!(cond)) { \
39 return IOStatus::ERROR_READ_ANIMATION; \
40 } \
41 } while (0)
42
43 using tinyxml2::XML_SUCCESS;
44 using tinyxml2::XMLDocument;
45 using tinyxml2::XMLElement;
46
47 namespace {
48
ReadValueHex(const XMLElement * parent,const char * elementName,uint32_t * hex)49 bool ReadValueHex(const XMLElement* parent, const char* elementName, uint32_t* hex) {
50 const XMLElement* element = nullptr;
51 RETURN_IF_FALSE(GetElement(parent, elementName, &element));
52 RETURN_IF_FALSE(ElementHasText(element));
53 *hex = std::stoul(element->GetText(), nullptr, 16);
54 return true;
55 }
56
ReadValueList(const XMLElement * parent,const char * elementName,std::vector<std::string> * valueList)57 bool ReadValueList(const XMLElement* parent, const char* elementName,
58 std::vector<std::string>* valueList) {
59 valueList->clear();
60 for (const XMLElement* elem = parent->FirstChildElement(elementName); elem != nullptr;
61 elem = elem->NextSiblingElement(elementName)) {
62 RETURN_IF_FALSE(ElementHasText(elem));
63 valueList->push_back(std::string(elem->GetText()));
64 }
65 return true;
66 }
67
68 // ReadValue for SurroundView2dParams::BlendingType.
ReadAnimationType(const XMLElement * parent,const char * elementName,AnimationType * type)69 bool ReadAnimationType(const XMLElement* parent, const char* elementName, AnimationType* type) {
70 const XMLElement* element = nullptr;
71 RETURN_IF_FALSE(GetElement(parent, elementName, &element));
72 RETURN_IF_FALSE(ElementHasText(element));
73 const std::string animationTypeStr(element->GetText());
74
75 if (animationTypeStr == "RotationAngle") {
76 *type = AnimationType::ROTATION_ANGLE;
77 } else if (animationTypeStr == "RotationSpeed") {
78 *type = AnimationType::ROTATION_SPEED;
79 } else if (animationTypeStr == "Translation") {
80 *type = AnimationType::TRANSLATION;
81 } else if (animationTypeStr == "SwitchTextureOnce") {
82 *type = AnimationType::SWITCH_TEXTURE_ONCE;
83 } else if (animationTypeStr == "AdjustGammaOnce") {
84 *type = AnimationType::ADJUST_GAMMA_ONCE;
85 } else if (animationTypeStr == "SwitchTextureRepeat") {
86 *type = AnimationType::SWITCH_TEXTURE_REPEAT;
87 } else if (animationTypeStr == "AdjustGammaRepeat") {
88 *type = AnimationType::ADJUST_GAMMA_REPEAT;
89 } else {
90 LOG(ERROR) << "Unknown AnimationType specified: " << animationTypeStr;
91 return false;
92 }
93 return true;
94 }
95
ReadRange(const XMLElement * parent,const char * elementName,Range * range)96 bool ReadRange(const XMLElement* parent, const char* elementName, Range* range) {
97 const XMLElement* rangeElem = nullptr;
98 RETURN_IF_FALSE(GetElement(parent, elementName, &rangeElem));
99 {
100 RETURN_IF_FALSE(ReadValue(rangeElem, "Start", &range->start));
101 RETURN_IF_FALSE(ReadValue(rangeElem, "End", &range->end));
102 }
103 return true;
104 }
105
ReadFloat3(const XMLElement * parent,const char * elementName,std::array<float,3> * float3)106 bool ReadFloat3(const XMLElement* parent, const char* elementName, std::array<float, 3>* float3) {
107 const XMLElement* arrayElem = nullptr;
108 RETURN_IF_FALSE(GetElement(parent, elementName, &arrayElem));
109 {
110 RETURN_IF_FALSE(ReadValue(arrayElem, "X", &float3->at(0)));
111 RETURN_IF_FALSE(ReadValue(arrayElem, "Y", &float3->at(1)));
112 RETURN_IF_FALSE(ReadValue(arrayElem, "Z", &float3->at(2)));
113 }
114 return true;
115 }
116
117 // Generic template for reading a animation op, each op type must be specialized.
118 template <typename OpType>
ReadOp(const XMLElement * opElem,OpType * op)119 bool ReadOp(const XMLElement* opElem, OpType* op) {
120 (void)opElem;
121 (void)op;
122 LOG(ERROR) << "Unexpected internal error: Op type in not supported.";
123 return false;
124 }
125
126 // Reads vhal property.
ReadVhalProperty(const XMLElement * parent,const char * elementName,uint64_t * vhalProperty)127 bool ReadVhalProperty(const XMLElement* parent, const char* elementName, uint64_t* vhalProperty) {
128 const XMLElement* vhalPropElem = nullptr;
129 RETURN_IF_FALSE(GetElement(parent, elementName, &vhalPropElem));
130 {
131 uint32_t propertyId;
132 uint32_t areaId;
133 RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "PropertyId", &propertyId));
134 RETURN_IF_FALSE(ReadValueHex(vhalPropElem, "AreaId", &areaId));
135 *vhalProperty = (static_cast<uint64_t>(propertyId) << 32) | areaId;
136 }
137 return true;
138 }
139
140 template <>
ReadOp(const XMLElement * rotationOpElem,RotationOp * rotationOp)141 bool ReadOp<RotationOp>(const XMLElement* rotationOpElem, RotationOp* rotationOp) {
142 RETURN_IF_FALSE(ReadVhalProperty(rotationOpElem, "VhalProperty", &rotationOp->vhalProperty));
143
144 RETURN_IF_FALSE(ReadAnimationType(rotationOpElem, "AnimationType", &rotationOp->type));
145
146 RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationAxis", &rotationOp->axis.axisVector));
147
148 RETURN_IF_FALSE(ReadFloat3(rotationOpElem, "RotationPoint", &rotationOp->axis.rotationPoint));
149
150 RETURN_IF_FALSE(
151 ReadValue(rotationOpElem, "DefaultRotationValue", &rotationOp->defaultRotationValue));
152
153 RETURN_IF_FALSE(ReadValue(rotationOpElem, "AnimationTimeMs", &rotationOp->animationTime));
154
155 RETURN_IF_FALSE(ReadRange(rotationOpElem, "RotationRange", &rotationOp->rotationRange));
156
157 RETURN_IF_FALSE(ReadRange(rotationOpElem, "VhalRange", &rotationOp->vhalRange));
158
159 return true;
160 }
161
162 template <>
ReadOp(const XMLElement * translationOpElem,TranslationOp * translationOp)163 bool ReadOp<TranslationOp>(const XMLElement* translationOpElem, TranslationOp* translationOp) {
164 RETURN_IF_FALSE(
165 ReadVhalProperty(translationOpElem, "VhalProperty", &translationOp->vhalProperty));
166
167 RETURN_IF_FALSE(ReadAnimationType(translationOpElem, "AnimationType", &translationOp->type));
168
169 RETURN_IF_FALSE(ReadFloat3(translationOpElem, "Direction", &translationOp->direction));
170
171 RETURN_IF_FALSE(ReadValue(translationOpElem, "DefaultTranslationValue",
172 &translationOp->defaultTranslationValue));
173
174 RETURN_IF_FALSE(ReadValue(translationOpElem, "AnimationTimeMs", &translationOp->animationTime));
175
176 RETURN_IF_FALSE(
177 ReadRange(translationOpElem, "TranslationRange", &translationOp->translationRange));
178
179 RETURN_IF_FALSE(ReadRange(translationOpElem, "VhalRange", &translationOp->vhalRange));
180
181 return true;
182 }
183
184 template <>
ReadOp(const XMLElement * textureOpElem,TextureOp * textureOp)185 bool ReadOp<TextureOp>(const XMLElement* textureOpElem, TextureOp* textureOp) {
186 RETURN_IF_FALSE(ReadVhalProperty(textureOpElem, "VhalProperty", &textureOp->vhalProperty));
187
188 RETURN_IF_FALSE(ReadAnimationType(textureOpElem, "AnimationType", &textureOp->type));
189
190 RETURN_IF_FALSE(ReadValue(textureOpElem, "DefaultTexture", &textureOp->defaultTexture));
191
192 RETURN_IF_FALSE(ReadValue(textureOpElem, "AnimationTimeMs", &textureOp->animationTime));
193
194 RETURN_IF_FALSE(ReadRange(textureOpElem, "TextureRange", &textureOp->textureRange));
195
196 RETURN_IF_FALSE(ReadRange(textureOpElem, "VhalRange", &textureOp->vhalRange));
197
198 return true;
199 }
200
201 template <>
ReadOp(const XMLElement * gammaOpElem,GammaOp * gammaOp)202 bool ReadOp<GammaOp>(const XMLElement* gammaOpElem, GammaOp* gammaOp) {
203 RETURN_IF_FALSE(ReadVhalProperty(gammaOpElem, "VhalProperty", &gammaOp->vhalProperty));
204
205 RETURN_IF_FALSE(ReadAnimationType(gammaOpElem, "AnimationType", &gammaOp->type));
206
207 RETURN_IF_FALSE(ReadValue(gammaOpElem, "AnimationTimeMs", &gammaOp->animationTime));
208
209 RETURN_IF_FALSE(ReadRange(gammaOpElem, "GammaRange", &gammaOp->gammaRange));
210
211 RETURN_IF_FALSE(ReadRange(gammaOpElem, "VhalRange", &gammaOp->vhalRange));
212
213 return true;
214 }
215
216 template <typename OpType>
ReadAllOps(const XMLElement * animationElem,const char * elemName,std::map<uint64_t,std::vector<OpType>> * mapOps)217 bool ReadAllOps(const XMLElement* animationElem, const char* elemName,
218 std::map<uint64_t, std::vector<OpType>>* mapOps) {
219 for (const XMLElement* elem = animationElem->FirstChildElement(elemName); elem != nullptr;
220 elem = elem->NextSiblingElement(elemName)) {
221 OpType op;
222 RETURN_IF_FALSE(ReadOp(elem, &op));
223 if (mapOps->find(op.vhalProperty) == mapOps->end()) {
224 mapOps->emplace(op.vhalProperty, std::vector<OpType>());
225 }
226 mapOps->at(op.vhalProperty).push_back(op);
227 }
228 return true;
229 }
230
ReadAnimation(const XMLElement * animationElem,AnimationInfo * animationInfo)231 bool ReadAnimation(const XMLElement* animationElem, AnimationInfo* animationInfo) {
232 RETURN_IF_FALSE(ReadValue(animationElem, "PartId", &animationInfo->partId));
233 RETURN_IF_FALSE(ReadValue(animationElem, "ParentPartId", &animationInfo->parentId));
234
235 // Child Part Ids (Optional)
236 const XMLElement* childPartsElem = nullptr;
237 GetElement(animationElem, "ChildParts", &childPartsElem);
238 if (childPartsElem != nullptr) {
239 RETURN_IF_FALSE(ReadValueList(childPartsElem, "PartId", &animationInfo->childIds));
240 }
241
242 // Set to the default Identity.
243 animationInfo->pose = gMat4Identity;
244
245 // All animation operations.
246 RETURN_IF_FALSE(ReadAllOps(animationElem, "RotationOp", &animationInfo->rotationOpsMap));
247 RETURN_IF_FALSE(ReadAllOps(animationElem, "TranslationOp", &animationInfo->translationOpsMap));
248 RETURN_IF_FALSE(ReadAllOps(animationElem, "TextureOp", &animationInfo->textureOpsMap));
249 RETURN_IF_FALSE(ReadAllOps(animationElem, "GammaOp", &animationInfo->gammaOpsMap));
250 return true;
251 }
252
ReadAllAnimations(const XMLElement * rootElem,std::vector<AnimationInfo> * animations)253 bool ReadAllAnimations(const XMLElement* rootElem, std::vector<AnimationInfo>* animations) {
254 animations->clear();
255 // Loop over animation elements.
256 for (const XMLElement* elem = rootElem->FirstChildElement("Animation"); elem != nullptr;
257 elem = elem->NextSiblingElement("Animation")) {
258 AnimationInfo animationInfo;
259 RETURN_IF_FALSE(ReadAnimation(elem, &animationInfo));
260 animations->push_back(animationInfo);
261 }
262 return true;
263 }
264
265 } // namespace
266
ReadCarModelConfig(const std::string & carModelConfigFile,AnimationConfig * animationConfig)267 IOStatus ReadCarModelConfig(const std::string& carModelConfigFile,
268 AnimationConfig* animationConfig) {
269 XMLDocument xmlDoc;
270
271 /* load and parse a configuration file */
272 xmlDoc.LoadFile(carModelConfigFile.c_str());
273 if (xmlDoc.ErrorID() != XML_SUCCESS) {
274 LOG(ERROR) << "Failed to load and/or parse a configuration file, " << xmlDoc.ErrorStr();
275 return IOStatus::ERROR_READ_ANIMATION;
276 }
277
278 const XMLElement* rootElem = xmlDoc.RootElement();
279 if (strcmp(rootElem->Name(), "SurroundViewCarModelConfig")) {
280 LOG(ERROR) << "Config file is not in the required format: " << carModelConfigFile;
281 return IOStatus::ERROR_READ_ANIMATION;
282 }
283
284 // version
285 RETURN_ERROR_STATUS_IF_FALSE(ReadValue(rootElem, "Version", &animationConfig->version));
286
287 // animations
288 RETURN_ERROR_STATUS_IF_FALSE(ReadAllAnimations(rootElem, &animationConfig->animations));
289
290 return IOStatus::OK;
291 }
292
293 } // namespace implementation
294 } // namespace V1_0
295 } // namespace sv
296 } // namespace automotive
297 } // namespace hardware
298 } // namespace android
299