Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(590)

Side by Side Diff: chrome/browser/android/vr_shell/gltf_parser.cc

Issue 2774653002: Support for parsing external file references in a glTF resource. (Closed)
Patch Set: Scoped holders and tests for parsing failures. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/android/vr_shell/gltf_parser.h" 5 #include "chrome/browser/android/vr_shell/gltf_parser.h"
6 6
7 #include "base/base64.h" 7 #include "base/files/file_util.h"
8 #include "base/json/json_file_value_serializer.h"
8 #include "base/logging.h" 9 #include "base/logging.h"
9 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
11 #include "net/base/data_url.h"
12 #include "net/base/filename_util.h"
13 #include "url/gurl.h"
10 14
11 namespace vr_shell { 15 namespace vr_shell {
12 16
13 constexpr char kBase64Header[] = "data:application/octet-stream;base64,";
14 constexpr size_t kBase64HeaderSize = 37;
15
16 GltfParser::GltfParser() {} 17 GltfParser::GltfParser() {}
17 18
18 GltfParser::~GltfParser() = default; 19 GltfParser::~GltfParser() = default;
19 20
21 GltfParser::Helper::Helper(const base::FilePath& path)
22 : asset(base::MakeUnique<gltf::Asset>()), path(path) {}
23
24 GltfParser::Helper::~Helper() = default;
25
20 std::unique_ptr<gltf::Asset> GltfParser::Parse( 26 std::unique_ptr<gltf::Asset> GltfParser::Parse(
21 const base::DictionaryValue& dict) { 27 const base::DictionaryValue& dict,
28 const base::FilePath& path) {
29 Helper helper(path);
30 helper_ = &helper;
mthiesse 2017/03/24 18:11:10 Okay, this is worse than what you had before ;) I
acondor_ 2017/03/24 20:36:13 Done.
31
22 std::string gltf_version; 32 std::string gltf_version;
23 if (!dict.GetString("asset.version", &gltf_version) || gltf_version != "1.0") 33 if (!dict.GetString("asset.version", &gltf_version) || gltf_version != "1.0")
24 return nullptr; 34 return nullptr;
25 35
26 asset_ = base::MakeUnique<gltf::Asset>();
27
28 if (!ParseInternal(dict)) {
29 asset_.reset();
30 return nullptr;
31 }
32
33 return std::move(asset_);
34 }
35
36 bool GltfParser::ParseInternal(const base::DictionaryValue& dict) {
37 const base::DictionaryValue* sub_dict; 36 const base::DictionaryValue* sub_dict;
38 if (dict.GetDictionary("buffers", &sub_dict) && !SetBuffers(*sub_dict)) 37 if (dict.GetDictionary("buffers", &sub_dict) && !SetBuffers(*sub_dict))
39 return false; 38 return nullptr;
40 if (dict.GetDictionary("bufferViews", &sub_dict) && 39 if (dict.GetDictionary("bufferViews", &sub_dict) &&
41 !SetBufferViews(*sub_dict)) 40 !SetBufferViews(*sub_dict))
42 return false; 41 return nullptr;
43 if (dict.GetDictionary("accessors", &sub_dict) && !SetAccessors(*sub_dict)) 42 if (dict.GetDictionary("accessors", &sub_dict) && !SetAccessors(*sub_dict))
44 return false; 43 return nullptr;
45 if (dict.GetDictionary("meshes", &sub_dict) && !SetMeshes(*sub_dict)) 44 if (dict.GetDictionary("meshes", &sub_dict) && !SetMeshes(*sub_dict))
46 return false; 45 return nullptr;
47 if (dict.GetDictionary("nodes", &sub_dict) && !SetNodes(*sub_dict)) 46 if (dict.GetDictionary("nodes", &sub_dict) && !SetNodes(*sub_dict))
48 return false; 47 return nullptr;
49 if (dict.GetDictionary("scenes", &sub_dict) && !SetScenes(*sub_dict)) 48 if (dict.GetDictionary("scenes", &sub_dict) && !SetScenes(*sub_dict))
50 return false; 49 return nullptr;
51 50
52 std::string scene_key; 51 std::string scene_key;
53 if (dict.GetString("scene", &scene_key)) { 52 if (dict.GetString("scene", &scene_key)) {
54 auto scene_it = scene_ids_.find(scene_key); 53 auto scene_it = helper.scene_ids.find(scene_key);
55 if (scene_it == scene_ids_.end()) 54 if (scene_it == helper.scene_ids.end())
56 return false; 55 return nullptr;
57 asset_->SetMainScene(asset_->GetScene(scene_it->second)); 56 helper.asset->SetMainScene(helper.asset->GetScene(scene_it->second));
58 } 57 }
59 58
60 return true; 59 return std::move(helper.asset);
60 }
61
62 std::unique_ptr<gltf::Asset> GltfParser::Parse(
63 const base::FilePath& gltf_path) {
64 JSONFileValueDeserializer json_deserializer(gltf_path);
65 int error_code;
66 std::string error_msg;
67 auto asset_value = json_deserializer.Deserialize(&error_code, &error_msg);
68 if (!asset_value)
69 return nullptr;
70 base::DictionaryValue* asset;
71 if (!asset_value->GetAsDictionary(&asset))
72 return nullptr;
73 return Parse(*asset, gltf_path);
61 } 74 }
62 75
63 bool GltfParser::SetBuffers(const base::DictionaryValue& dict) { 76 bool GltfParser::SetBuffers(const base::DictionaryValue& dict) {
64 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { 77 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
65 const base::DictionaryValue* buffer_dict; 78 const base::DictionaryValue* buffer_dict;
66 if (!it.value().GetAsDictionary(&buffer_dict)) 79 if (!it.value().GetAsDictionary(&buffer_dict))
67 return false; 80 return false;
68 81
69 std::string uri; 82 std::string uri_str;
70 // TODO(acondor): Support files. Only inline data is supported now. 83 if (!buffer_dict->GetString("uri", &uri_str))
71 if (!buffer_dict->GetString("uri", &uri) ||
72 uri.substr(0, kBase64HeaderSize) != kBase64Header)
73 return false; 84 return false;
74 85 auto buffer = ProcessUri(uri_str);
75 auto buffer = base::MakeUnique<gltf::Buffer>(); 86 if (!buffer)
76 if (!base::Base64Decode(uri.substr(kBase64HeaderSize), buffer.get()))
77 return false; 87 return false;
78 88
79 int byte_length; 89 int byte_length;
80 if (buffer_dict->GetInteger("byteLength", &byte_length) && 90 if (buffer_dict->GetInteger("byteLength", &byte_length) &&
81 static_cast<int>(buffer->length()) != byte_length) 91 static_cast<int>(buffer->length()) != byte_length)
82 return false; 92 return false;
83 93
84 buffer_ids_[it.key()] = asset_->AddBuffer(std::move(buffer)); 94 helper_->buffer_ids[it.key()] =
95 helper_->asset->AddBuffer(std::move(buffer));
85 } 96 }
86 return true; 97 return true;
87 } 98 }
88 99
100 std::unique_ptr<gltf::Buffer> GltfParser::ProcessUri(
101 const std::string& uri_str) {
102 auto uri = helper_->path.empty()
103 ? GURL(uri_str)
104 : net::FilePathToFileURL(helper_->path).Resolve(uri_str);
105 if (!uri.is_valid())
106 return nullptr;
107 if (uri.SchemeIs(url::kDataScheme)) {
108 std::string mime_type;
109 std::string charset;
110 auto data = base::MakeUnique<gltf::Buffer>();
111 if (!net::DataURL::Parse(uri, &mime_type, &charset, data.get()))
112 return nullptr;
113 return data;
114 }
115 if (uri.SchemeIsFile()) {
116 auto data = base::MakeUnique<gltf::Buffer>();
117 if (!base::ReadFileToString(base::FilePath(uri.path()), data.get()))
118 return nullptr;
119 return data;
120 }
121 // No other schemes are supported yet.
122 return nullptr;
123 }
124
89 bool GltfParser::SetBufferViews(const base::DictionaryValue& dict) { 125 bool GltfParser::SetBufferViews(const base::DictionaryValue& dict) {
90 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { 126 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
91 const base::DictionaryValue* buffer_view_dict; 127 const base::DictionaryValue* buffer_view_dict;
92 if (!it.value().GetAsDictionary(&buffer_view_dict)) 128 if (!it.value().GetAsDictionary(&buffer_view_dict))
93 return false; 129 return false;
94 130
95 auto buffer_view = base::MakeUnique<gltf::BufferView>(); 131 auto buffer_view = base::MakeUnique<gltf::BufferView>();
96 std::string buffer_key; 132 std::string buffer_key;
97 if (!buffer_view_dict->GetString("buffer", &buffer_key)) 133 if (!buffer_view_dict->GetString("buffer", &buffer_key))
98 return false; 134 return false;
99 auto buffer_it = buffer_ids_.find(buffer_key); 135 auto buffer_it = helper_->buffer_ids.find(buffer_key);
100 if (buffer_it == buffer_ids_.end()) 136 if (buffer_it == helper_->buffer_ids.end())
101 return false; 137 return false;
102 buffer_view->buffer = asset_->GetBuffer(buffer_it->second); 138 buffer_view->buffer = helper_->asset->GetBuffer(buffer_it->second);
103 if (!buffer_view_dict->GetInteger("byteOffset", &buffer_view->byte_offset)) 139 if (!buffer_view_dict->GetInteger("byteOffset", &buffer_view->byte_offset))
104 return false; 140 return false;
105 buffer_view_dict->GetInteger("byteLength", &buffer_view->byte_length); 141 buffer_view_dict->GetInteger("byteLength", &buffer_view->byte_length);
106 buffer_view_dict->GetInteger("target", &buffer_view->target); 142 buffer_view_dict->GetInteger("target", &buffer_view->target);
107 143
108 buffer_view_ids_[it.key()] = asset_->AddBufferView(std::move(buffer_view)); 144 helper_->buffer_view_ids[it.key()] =
145 helper_->asset->AddBufferView(std::move(buffer_view));
109 } 146 }
110 return true; 147 return true;
111 } 148 }
112 149
113 bool GltfParser::SetAccessors(const base::DictionaryValue& dict) { 150 bool GltfParser::SetAccessors(const base::DictionaryValue& dict) {
114 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { 151 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
115 const base::DictionaryValue* accessor_dict; 152 const base::DictionaryValue* accessor_dict;
116 if (!it.value().GetAsDictionary(&accessor_dict)) 153 if (!it.value().GetAsDictionary(&accessor_dict))
117 return false; 154 return false;
118 155
119 auto accessor = base::MakeUnique<gltf::Accessor>(); 156 auto accessor = base::MakeUnique<gltf::Accessor>();
120 std::string buffer_view_key; 157 std::string buffer_view_key;
121 std::string type_str; 158 std::string type_str;
122 if (!accessor_dict->GetString("bufferView", &buffer_view_key)) 159 if (!accessor_dict->GetString("bufferView", &buffer_view_key))
123 return false; 160 return false;
124 auto buffer_view_it = buffer_view_ids_.find(buffer_view_key); 161 auto buffer_view_it = helper_->buffer_view_ids.find(buffer_view_key);
125 if (buffer_view_it == buffer_view_ids_.end()) 162 if (buffer_view_it == helper_->buffer_view_ids.end())
126 return false; 163 return false;
127 accessor->buffer_view = asset_->GetBufferView(buffer_view_it->second); 164 accessor->buffer_view =
165 helper_->asset->GetBufferView(buffer_view_it->second);
128 if (!accessor_dict->GetInteger("byteOffset", &accessor->byte_offset)) 166 if (!accessor_dict->GetInteger("byteOffset", &accessor->byte_offset))
129 return false; 167 return false;
130 accessor_dict->GetInteger("byteStride", &accessor->byte_stride); 168 accessor_dict->GetInteger("byteStride", &accessor->byte_stride);
131 if (!accessor_dict->GetInteger("componentType", &accessor->component_type)) 169 if (!accessor_dict->GetInteger("componentType", &accessor->component_type))
132 return false; 170 return false;
133 if (!accessor_dict->GetInteger("count", &accessor->count)) 171 if (!accessor_dict->GetInteger("count", &accessor->count))
134 return false; 172 return false;
135 if (!accessor_dict->GetString("type", &type_str)) 173 if (!accessor_dict->GetString("type", &type_str))
136 return false; 174 return false;
137 gltf::Type type = gltf::GetType(type_str); 175 gltf::Type type = gltf::GetType(type_str);
138 if (type == gltf::UNKNOWN) 176 if (type == gltf::UNKNOWN)
139 return false; 177 return false;
140 accessor->type = type; 178 accessor->type = type;
141 179
142 accessor_ids_[it.key()] = asset_->AddAccessor(std::move(accessor)); 180 helper_->accessor_ids[it.key()] =
181 helper_->asset->AddAccessor(std::move(accessor));
143 } 182 }
144 return true; 183 return true;
145 } 184 }
146 185
147 bool GltfParser::SetMeshes(const base::DictionaryValue& dict) { 186 bool GltfParser::SetMeshes(const base::DictionaryValue& dict) {
148 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { 187 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
149 const base::DictionaryValue* mesh_dict; 188 const base::DictionaryValue* mesh_dict;
150 if (!it.value().GetAsDictionary(&mesh_dict)) 189 if (!it.value().GetAsDictionary(&mesh_dict))
151 return false; 190 return false;
152 191
153 auto mesh = base::MakeUnique<gltf::Mesh>(); 192 auto mesh = base::MakeUnique<gltf::Mesh>();
154 const base::ListValue* list; 193 const base::ListValue* list;
155 if (mesh_dict->GetList("primitives", &list)) { 194 if (mesh_dict->GetList("primitives", &list)) {
156 for (const auto& primitive_value : *list) { 195 for (const auto& primitive_value : *list) {
157 const base::DictionaryValue* primitive_dict; 196 const base::DictionaryValue* primitive_dict;
158 if (!primitive_value->GetAsDictionary(&primitive_dict)) 197 if (!primitive_value->GetAsDictionary(&primitive_dict))
159 return false; 198 return false;
160 199
161 auto primitive = ProcessPrimitive(*primitive_dict); 200 auto primitive = ProcessPrimitive(*primitive_dict);
162 if (!primitive) 201 if (!primitive)
163 return false; 202 return false;
164 mesh->primitives.push_back(std::move(primitive)); 203 mesh->primitives.push_back(std::move(primitive));
165 } 204 }
166 } 205 }
167 206
168 mesh_ids_[it.key()] = asset_->AddMesh(std::move(mesh)); 207 helper_->mesh_ids[it.key()] = helper_->asset->AddMesh(std::move(mesh));
169 } 208 }
170 return true; 209 return true;
171 } 210 }
172 211
173 std::unique_ptr<gltf::Mesh::Primitive> GltfParser::ProcessPrimitive( 212 std::unique_ptr<gltf::Mesh::Primitive> GltfParser::ProcessPrimitive(
174 const base::DictionaryValue& dict) { 213 const base::DictionaryValue& dict) {
175 auto primitive = base::MakeUnique<gltf::Mesh::Primitive>(); 214 auto primitive = base::MakeUnique<gltf::Mesh::Primitive>();
176 std::string indices_key; 215 std::string indices_key;
177 const base::DictionaryValue* attributes; 216 const base::DictionaryValue* attributes;
178 if (dict.GetString("indices", &indices_key)) { 217 if (dict.GetString("indices", &indices_key)) {
179 auto accessor_it = accessor_ids_.find(indices_key); 218 auto accessor_it = helper_->accessor_ids.find(indices_key);
180 if (accessor_it == accessor_ids_.end()) 219 if (accessor_it == helper_->accessor_ids.end())
181 return nullptr; 220 return nullptr;
182 primitive->indices = asset_->GetAccessor(accessor_it->second); 221 primitive->indices = helper_->asset->GetAccessor(accessor_it->second);
183 } 222 }
184 dict.GetInteger("mode", &primitive->mode); 223 dict.GetInteger("mode", &primitive->mode);
185 if (dict.GetDictionary("attributes", &attributes)) { 224 if (dict.GetDictionary("attributes", &attributes)) {
186 for (base::DictionaryValue::Iterator it(*attributes); !it.IsAtEnd(); 225 for (base::DictionaryValue::Iterator it(*attributes); !it.IsAtEnd();
187 it.Advance()) { 226 it.Advance()) {
188 std::string accessor_key; 227 std::string accessor_key;
189 if (!it.value().GetAsString(&accessor_key)) 228 if (!it.value().GetAsString(&accessor_key))
190 return nullptr; 229 return nullptr;
191 auto accessor_it = accessor_ids_.find(accessor_key); 230 auto accessor_it = helper_->accessor_ids.find(accessor_key);
192 if (accessor_it == accessor_ids_.end()) 231 if (accessor_it == helper_->accessor_ids.end())
193 return nullptr; 232 return nullptr;
194 primitive->attributes[it.key()] = 233 primitive->attributes[it.key()] =
195 asset_->GetAccessor(accessor_it->second); 234 helper_->asset->GetAccessor(accessor_it->second);
196 } 235 }
197 } 236 }
198 return primitive; 237 return primitive;
199 } 238 }
200 239
201 bool GltfParser::SetNodes(const base::DictionaryValue& dict) { 240 bool GltfParser::SetNodes(const base::DictionaryValue& dict) {
202 std::unordered_map<std::string, gltf::Node*> nodes; 241 std::unordered_map<std::string, gltf::Node*> nodes;
203 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { 242 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
204 const base::DictionaryValue* node_dict; 243 const base::DictionaryValue* node_dict;
205 if (!it.value().GetAsDictionary(&node_dict)) 244 if (!it.value().GetAsDictionary(&node_dict))
206 return false; 245 return false;
207 246
208 auto node = base::MakeUnique<gltf::Node>(); 247 auto node = base::MakeUnique<gltf::Node>();
209 const base::ListValue* list; 248 const base::ListValue* list;
210 if (node_dict->GetList("meshes", &list)) { 249 if (node_dict->GetList("meshes", &list)) {
211 std::string mesh_key; 250 std::string mesh_key;
212 for (const auto& mesh_value : *list) { 251 for (const auto& mesh_value : *list) {
213 if (!mesh_value->GetAsString(&mesh_key)) 252 if (!mesh_value->GetAsString(&mesh_key))
214 return false; 253 return false;
215 auto mesh_it = mesh_ids_.find(mesh_key); 254 auto mesh_it = helper_->mesh_ids.find(mesh_key);
216 if (mesh_it == mesh_ids_.end()) 255 if (mesh_it == helper_->mesh_ids.end())
217 return false; 256 return false;
218 node->meshes.push_back(asset_->GetMesh(mesh_it->second)); 257 node->meshes.push_back(helper_->asset->GetMesh(mesh_it->second));
219 } 258 }
220 } 259 }
221 260
222 nodes[it.key()] = node.get(); 261 nodes[it.key()] = node.get();
223 node_ids_[it.key()] = asset_->AddNode(std::move(node)); 262 helper_->node_ids[it.key()] = helper_->asset->AddNode(std::move(node));
224 } 263 }
225 264
226 // Processing children after all nodes have been added to the asset. 265 // Processing children after all nodes have been added to the asset.
227 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { 266 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
228 const base::DictionaryValue* node_dict; 267 const base::DictionaryValue* node_dict;
229 it.value().GetAsDictionary(&node_dict); 268 it.value().GetAsDictionary(&node_dict);
230 269
231 gltf::Node* node = nodes[it.key()]; 270 gltf::Node* node = nodes[it.key()];
232 const base::ListValue* list; 271 const base::ListValue* list;
233 if (node_dict->GetList("children", &list)) { 272 if (node_dict->GetList("children", &list)) {
(...skipping 18 matching lines...) Expand all
252 if (!it.value().GetAsDictionary(&scene_dict)) 291 if (!it.value().GetAsDictionary(&scene_dict))
253 return false; 292 return false;
254 293
255 auto scene = base::MakeUnique<gltf::Scene>(); 294 auto scene = base::MakeUnique<gltf::Scene>();
256 const base::ListValue* list; 295 const base::ListValue* list;
257 if (scene_dict->GetList("nodes", &list)) { 296 if (scene_dict->GetList("nodes", &list)) {
258 std::string node_key; 297 std::string node_key;
259 for (const auto& node_value : *list) { 298 for (const auto& node_value : *list) {
260 if (!node_value->GetAsString(&node_key)) 299 if (!node_value->GetAsString(&node_key))
261 return false; 300 return false;
262 auto node_it = node_ids_.find(node_key); 301 auto node_it = helper_->node_ids.find(node_key);
263 if (node_it == node_ids_.end()) 302 if (node_it == helper_->node_ids.end())
264 return false; 303 return false;
265 scene->nodes.push_back(asset_->GetNode(node_it->second)); 304 scene->nodes.push_back(helper_->asset->GetNode(node_it->second));
266 } 305 }
267 } 306 }
268 307
269 scene_ids_[it.key()] = asset_->AddScene(std::move(scene)); 308 helper_->scene_ids[it.key()] = helper_->asset->AddScene(std::move(scene));
270 } 309 }
271 return true; 310 return true;
272 } 311 }
273 312
274 } // namespace vr_shell 313 } // namespace vr_shell
OLDNEW
« no previous file with comments | « chrome/browser/android/vr_shell/gltf_parser.h ('k') | chrome/browser/android/vr_shell/gltf_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698