OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/android/vr_shell/gltf_parser.h" | |
6 | |
7 #include "base/base64.h" | |
8 #include "base/logging.h" | |
9 #include "base/memory/ptr_util.h" | |
10 | |
11 namespace vr_shell { | |
12 | |
13 constexpr char kBase64Header[] = "data:application/octet-stream;base64,"; | |
14 constexpr size_t kBase64HeaderSize = 37; | |
15 | |
16 GltfParser::GltfParser() {} | |
17 | |
18 GltfParser::~GltfParser() = default; | |
19 | |
20 std::unique_ptr<gltf::Asset> GltfParser::Parse( | |
21 const base::DictionaryValue& dict) { | |
22 std::string gltf_version; | |
23 if (!dict.GetString("asset.version", &gltf_version) || gltf_version != "1.0") | |
24 return nullptr; | |
25 | |
26 asset_ = base::MakeUnique<gltf::Asset>(); | |
27 | |
28 const base::DictionaryValue* sub_dict; | |
29 if (dict.GetDictionary("buffers", &sub_dict) && !SetBuffers(*sub_dict)) { | |
30 asset_.reset(); | |
mthiesse
2017/03/21 20:24:37
Rather than making asset_ a member variable and ha
acondor_
2017/03/22 16:25:28
I went for the 2nd option
| |
31 return nullptr; | |
32 } | |
33 if (dict.GetDictionary("bufferViews", &sub_dict) && | |
34 !SetBufferViews(*sub_dict)) { | |
35 asset_.reset(); | |
36 return nullptr; | |
37 } | |
38 if (dict.GetDictionary("accessors", &sub_dict) && !SetAccessors(*sub_dict)) { | |
39 asset_.reset(); | |
40 return nullptr; | |
41 } | |
42 if (dict.GetDictionary("meshes", &sub_dict) && !SetMeshes(*sub_dict)) { | |
43 asset_.reset(); | |
44 return nullptr; | |
45 } | |
46 if (dict.GetDictionary("nodes", &sub_dict) && !SetNodes(*sub_dict)) { | |
47 asset_.reset(); | |
48 return nullptr; | |
49 } | |
50 if (dict.GetDictionary("scenes", &sub_dict) && !SetScenes(*sub_dict)) { | |
51 asset_.reset(); | |
52 return nullptr; | |
53 } | |
54 | |
55 std::string scene_key; | |
56 if (dict.GetString("scene", &scene_key)) { | |
57 auto scene_it = scene_ids_.find(scene_key); | |
58 if (scene_it == scene_ids_.end()) { | |
59 asset_.reset(); | |
60 return nullptr; | |
61 } | |
62 asset_->SetMainScene(asset_->GetScene(scene_it->second)); | |
63 } | |
64 | |
65 return std::move(asset_); | |
66 } | |
67 | |
68 bool GltfParser::SetBuffers(const base::DictionaryValue& dict) { | |
69 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { | |
70 const base::DictionaryValue* buffer_dict; | |
71 if (!it.value().GetAsDictionary(&buffer_dict)) | |
72 return false; | |
73 | |
74 std::string uri; | |
75 // TODO(acondor): Support files. Only inline data is supported now. | |
76 if (!buffer_dict->GetString("uri", &uri) || | |
77 uri.substr(0, kBase64HeaderSize) != kBase64Header) | |
78 return false; | |
79 | |
80 auto buffer = base::MakeUnique<gltf::Buffer>(); | |
81 if (!base::Base64Decode(uri.substr(kBase64HeaderSize), buffer.get())) | |
82 return false; | |
83 | |
84 int byte_length; | |
85 if (buffer_dict->GetInteger("byteLength", &byte_length) && | |
86 static_cast<int>(buffer->length()) != byte_length) | |
87 return false; | |
88 | |
89 buffer_ids_[it.key()] = asset_->AddBuffer(std::move(buffer)); | |
90 } | |
91 return true; | |
92 } | |
93 | |
94 bool GltfParser::SetBufferViews(const base::DictionaryValue& dict) { | |
95 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { | |
96 const base::DictionaryValue* buffer_view_dict; | |
97 if (!it.value().GetAsDictionary(&buffer_view_dict)) | |
98 return false; | |
99 | |
100 auto buffer_view = base::MakeUnique<gltf::BufferView>(); | |
101 std::string buffer_key; | |
102 if (!buffer_view_dict->GetString("buffer", &buffer_key)) | |
103 return false; | |
104 auto buffer_it = buffer_ids_.find(buffer_key); | |
105 if (buffer_it == buffer_ids_.end()) | |
106 return false; | |
107 buffer_view->buffer = asset_->GetBuffer(buffer_it->second); | |
108 if (!buffer_view_dict->GetInteger("byteOffset", &buffer_view->byte_offset)) | |
109 return false; | |
110 buffer_view_dict->GetInteger("byteLength", &buffer_view->byte_length); | |
111 buffer_view_dict->GetInteger("target", &buffer_view->target); | |
112 | |
113 buffer_view_ids_[it.key()] = asset_->AddBufferView(std::move(buffer_view)); | |
114 } | |
115 return true; | |
116 } | |
117 | |
118 bool GltfParser::SetAccessors(const base::DictionaryValue& dict) { | |
119 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { | |
120 const base::DictionaryValue* accessor_dict; | |
121 if (!it.value().GetAsDictionary(&accessor_dict)) | |
122 return false; | |
123 | |
124 auto accessor = base::MakeUnique<gltf::Accessor>(); | |
125 std::string buffer_view_key; | |
126 std::string type_str; | |
127 if (!accessor_dict->GetString("bufferView", &buffer_view_key)) | |
128 return false; | |
129 auto buffer_view_it = buffer_view_ids_.find(buffer_view_key); | |
130 if (buffer_view_it == buffer_view_ids_.end()) | |
131 return false; | |
132 accessor->buffer_view = asset_->GetBufferView(buffer_view_it->second); | |
133 if (!accessor_dict->GetInteger("byteOffset", &accessor->byte_offset)) | |
134 return false; | |
135 accessor_dict->GetInteger("byteStride", &accessor->byte_stride); | |
136 if (!accessor_dict->GetInteger("componentType", &accessor->component_type)) | |
137 return false; | |
138 if (!accessor_dict->GetInteger("count", &accessor->count)) | |
139 return false; | |
140 if (!accessor_dict->GetString("type", &type_str)) | |
141 return false; | |
142 gltf::Type type = gltf::GetType(type_str); | |
143 if (type == gltf::UNKNOWN) | |
144 return false; | |
145 accessor->type = type; | |
146 | |
147 accessor_ids_[it.key()] = asset_->AddAccessor(std::move(accessor)); | |
148 } | |
149 return true; | |
150 } | |
151 | |
152 bool GltfParser::SetMeshes(const base::DictionaryValue& dict) { | |
153 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { | |
154 const base::DictionaryValue* mesh_dict; | |
155 if (!it.value().GetAsDictionary(&mesh_dict)) | |
156 return false; | |
157 | |
158 auto mesh = base::MakeUnique<gltf::Mesh>(); | |
159 const base::ListValue* list; | |
160 if (mesh_dict->GetList("primitives", &list)) { | |
161 for (const auto& primitive_value : *list) { | |
162 const base::DictionaryValue* primitive_dict; | |
163 if (!primitive_value->GetAsDictionary(&primitive_dict)) | |
164 return false; | |
165 | |
166 auto primitive = ProcessPrimitive(*primitive_dict); | |
167 if (!primitive) | |
168 return false; | |
169 mesh->primitives.push_back(std::move(primitive)); | |
170 } | |
171 } | |
172 | |
173 mesh_ids_[it.key()] = asset_->AddMesh(std::move(mesh)); | |
174 } | |
175 return true; | |
176 } | |
177 | |
178 std::unique_ptr<gltf::Mesh::Primitive> GltfParser::ProcessPrimitive( | |
179 const base::DictionaryValue& dict) { | |
180 auto primitive = base::MakeUnique<gltf::Mesh::Primitive>(); | |
181 std::string indices_key; | |
182 const base::DictionaryValue* attributes; | |
183 if (dict.GetString("indices", &indices_key)) { | |
184 auto accessor_it = accessor_ids_.find(indices_key); | |
185 if (accessor_it == accessor_ids_.end()) | |
186 return nullptr; | |
187 primitive->indices = asset_->GetAccessor(accessor_it->second); | |
188 } | |
189 dict.GetInteger("mode", &primitive->mode); | |
190 if (dict.GetDictionary("attributes", &attributes)) { | |
191 for (base::DictionaryValue::Iterator it(*attributes); !it.IsAtEnd(); | |
192 it.Advance()) { | |
193 std::string accessor_key; | |
194 if (!it.value().GetAsString(&accessor_key)) | |
195 return nullptr; | |
196 auto accessor_it = accessor_ids_.find(accessor_key); | |
197 if (accessor_it == accessor_ids_.end()) | |
198 return nullptr; | |
199 primitive->attributes[it.key()] = | |
200 asset_->GetAccessor(accessor_it->second); | |
201 } | |
202 } | |
203 return primitive; | |
204 } | |
205 | |
206 bool GltfParser::SetNodes(const base::DictionaryValue& dict) { | |
207 std::unordered_map<std::string, gltf::Node*> nodes; | |
208 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { | |
209 const base::DictionaryValue* node_dict; | |
210 if (!it.value().GetAsDictionary(&node_dict)) | |
211 return false; | |
212 | |
213 auto node = base::MakeUnique<gltf::Node>(); | |
214 const base::ListValue* list; | |
215 if (node_dict->GetList("meshes", &list)) { | |
216 std::string mesh_key; | |
217 for (const auto& mesh_value : *list) { | |
218 if (!mesh_value->GetAsString(&mesh_key)) | |
219 return false; | |
220 auto mesh_it = mesh_ids_.find(mesh_key); | |
221 if (mesh_it == mesh_ids_.end()) | |
222 return false; | |
223 node->meshes.push_back(asset_->GetMesh(mesh_it->second)); | |
224 } | |
225 } | |
226 | |
227 nodes[it.key()] = node.get(); | |
228 node_ids_[it.key()] = asset_->AddNode(std::move(node)); | |
229 } | |
230 | |
231 // Processing children after all nodes have been added to the asset. | |
232 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { | |
233 const base::DictionaryValue* node_dict; | |
234 it.value().GetAsDictionary(&node_dict); | |
235 | |
236 gltf::Node* node = nodes[it.key()]; | |
237 const base::ListValue* list; | |
238 if (node_dict->GetList("children", &list)) { | |
239 std::string node_key; | |
240 for (const auto& mesh_value : *list) { | |
241 if (!mesh_value->GetAsString(&node_key)) | |
242 return false; | |
243 auto node_it = nodes.find(node_key); | |
244 if (node_it == nodes.end()) | |
245 return false; | |
246 node->children.push_back(node_it->second); | |
247 } | |
248 } | |
249 } | |
250 | |
251 return true; | |
252 } | |
253 | |
254 bool GltfParser::SetScenes(const base::DictionaryValue& dict) { | |
255 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { | |
256 const base::DictionaryValue* scene_dict; | |
257 if (!it.value().GetAsDictionary(&scene_dict)) | |
258 return false; | |
259 | |
260 auto scene = base::MakeUnique<gltf::Scene>(); | |
261 const base::ListValue* list; | |
262 if (scene_dict->GetList("nodes", &list)) { | |
263 std::string node_key; | |
264 for (const auto& node_value : *list) { | |
265 if (!node_value->GetAsString(&node_key)) | |
266 return false; | |
267 auto node_it = node_ids_.find(node_key); | |
268 if (node_it == node_ids_.end()) | |
269 return false; | |
270 scene->nodes.push_back(asset_->GetNode(node_it->second)); | |
271 } | |
272 } | |
273 | |
274 scene_ids_[it.key()] = asset_->AddScene(std::move(scene)); | |
275 } | |
276 return true; | |
277 } | |
278 | |
279 } // namespace vr_shell | |
OLD | NEW |