253 if (line == "0 BFC INVERTNEXT" or line == "0 BFC CERTIFY INVERTNEXT") |
253 if (line == "0 BFC INVERTNEXT" or line == "0 BFC CERTIFY INVERTNEXT") |
254 { |
254 { |
255 invertNext = true; |
255 invertNext = true; |
256 continue; |
256 continue; |
257 } |
257 } |
258 std::unique_ptr<linetypes::Object> object = parseFromString(line); |
258 std::unique_ptr<ldraw::Object> object = parseFromString(line); |
259 auto id = editor.append(std::move(object)); |
259 auto id = editor.append(std::move(object)); |
260 if (invertNext) |
260 if (invertNext) |
261 { |
261 { |
262 editor.invertObject(id); |
262 editor.invertObject(id); |
263 } |
263 } |
264 invertNext = false; |
264 invertNext = false; |
265 } |
265 } |
266 } |
266 } |
267 |
267 |
268 static Color colorFromString(const QString& colorString) |
268 static ldraw::Color colorFromString(const QString& colorString) |
269 { |
269 { |
270 bool colorSucceeded; |
270 bool colorSucceeded; |
271 const Color color = {colorString.toInt(&colorSucceeded)}; |
271 const ldraw::Color color = {colorString.toInt(&colorSucceeded)}; |
272 if (colorSucceeded) |
272 if (colorSucceeded) |
273 { |
273 { |
274 return color; |
274 return color; |
275 } |
275 } |
276 else |
276 else |
327 } |
327 } |
328 } |
328 } |
329 return result; |
329 return result; |
330 } |
330 } |
331 |
331 |
332 static std::unique_ptr<linetypes::Object> parseType0Line( |
332 static std::unique_ptr<ldraw::Object> parseType0Line( |
333 const QString& line, |
333 const QString& line, |
334 const QStringList& tokens) |
334 const QStringList& tokens) |
335 { |
335 { |
336 Q_UNUSED(tokens) |
336 Q_UNUSED(tokens) |
337 if (line.startsWith("0 //")) |
337 if (line.startsWith("0 //")) |
338 { |
338 { |
339 return std::make_unique<linetypes::Comment>(line.mid(std::strlen("0 //")).simplified()); |
339 return std::make_unique<ldraw::Comment>(line.mid(std::strlen("0 //")).simplified()); |
340 } |
340 } |
341 else |
341 else |
342 { |
342 { |
343 return std::make_unique<linetypes::MetaCommand>(line.mid(1).simplified()); |
343 return std::make_unique<ldraw::MetaCommand>(line.mid(1).simplified()); |
344 } |
344 } |
345 } |
345 } |
346 |
346 |
347 static std::unique_ptr<linetypes::SubfileReference> parseType1Line( |
347 static std::unique_ptr<ldraw::SubfileReference> parseType1Line( |
348 const QString& line, |
348 const QString& line, |
349 const QStringList& tokens) |
349 const QStringList& tokens) |
350 { |
350 { |
351 Q_UNUSED(line) |
351 Q_UNUSED(line) |
352 constexpr int colorPosition = 1; |
352 constexpr int colorPosition = 1; |
355 constexpr int namePosition = 14; |
355 constexpr int namePosition = 14; |
356 if (tokens.size() != 15) |
356 if (tokens.size() != 15) |
357 { |
357 { |
358 throw BodyParseError{"wrong amount of tokens in a type-1 line"}; |
358 throw BodyParseError{"wrong amount of tokens in a type-1 line"}; |
359 } |
359 } |
360 const Color color = colorFromString(tokens[colorPosition]); |
360 const ldraw::Color color = colorFromString(tokens[colorPosition]); |
361 const glm::mat4 transform = matrixFromStrings(tokens, transformPosition, positionPosition); |
361 const glm::mat4 transform = matrixFromStrings(tokens, transformPosition, positionPosition); |
362 const QString& name = tokens[namePosition]; |
362 const QString& name = tokens[namePosition]; |
363 return std::make_unique<linetypes::SubfileReference>(transform, name, color); |
363 return std::make_unique<ldraw::SubfileReference>(transform, name, color); |
364 } |
364 } |
365 |
365 |
366 template<typename T, int NumVertices> |
366 template<typename T, int NumVertices> |
367 static std::unique_ptr<T> parsePolygon( |
367 static std::unique_ptr<T> parsePolygon( |
368 const QString& line, |
368 const QString& line, |
373 auto vertexPosition = [](int n) { return 2 + 3*n; }; |
373 auto vertexPosition = [](int n) { return 2 + 3*n; }; |
374 if (tokens.size() != 2 + 3 * NumVertices) |
374 if (tokens.size() != 2 + 3 * NumVertices) |
375 { |
375 { |
376 throw BodyParseError{"wrong amount of tokens"}; |
376 throw BodyParseError{"wrong amount of tokens"}; |
377 } |
377 } |
378 const Color color = colorFromString(tokens[colorPosition]); |
378 const ldraw::Color color = colorFromString(tokens[colorPosition]); |
379 QVector<glm::vec3> vertices; |
379 QVector<glm::vec3> vertices; |
380 vertices.reserve(NumVertices); |
380 vertices.reserve(NumVertices); |
381 for (int i = 0; i < NumVertices; i += 1) |
381 for (int i = 0; i < NumVertices; i += 1) |
382 { |
382 { |
383 vertices.append(vertexFromStrings(tokens, vertexPosition(i))); |
383 vertices.append(vertexFromStrings(tokens, vertexPosition(i))); |
384 } |
384 } |
385 return std::make_unique<T>(vertices, color); |
385 return std::make_unique<T>(vertices, color); |
386 } |
386 } |
387 |
387 |
388 std::unique_ptr<linetypes::Object> Parser::parseFromString(QString line) |
388 std::unique_ptr<ldraw::Object> Parser::parseFromString(QString line) |
389 { |
389 { |
390 line = line.simplified(); |
390 line = line.simplified(); |
391 try |
391 try |
392 { |
392 { |
393 const QStringList tokens = line.split(QRegExp{R"(\s+)"}); |
393 const QStringList tokens = line.split(QRegExp{R"(\s+)"}); |
394 if (tokens.empty() or tokens == QStringList{{""}}) |
394 if (tokens.empty() or tokens == QStringList{{""}}) |
395 { |
395 { |
396 return std::make_unique<linetypes::Empty>(); |
396 return std::make_unique<ldraw::Empty>(); |
397 } |
397 } |
398 bool ok_code; |
398 bool ok_code; |
399 const int code = tokens[0].toInt(&ok_code); |
399 const int code = tokens[0].toInt(&ok_code); |
400 if (not ok_code) |
400 if (not ok_code) |
401 { |
401 { |
406 case 0: |
406 case 0: |
407 return parseType0Line(line, tokens); |
407 return parseType0Line(line, tokens); |
408 case 1: |
408 case 1: |
409 return parseType1Line(line, tokens); |
409 return parseType1Line(line, tokens); |
410 case 2: |
410 case 2: |
411 return parsePolygon<linetypes::Edge, 2>(line, tokens); |
411 return parsePolygon<ldraw::Edge, 2>(line, tokens); |
412 case 3: |
412 case 3: |
413 return parsePolygon<linetypes::Triangle, 3>(line, tokens); |
413 return parsePolygon<ldraw::Triangle, 3>(line, tokens); |
414 case 4: |
414 case 4: |
415 return parsePolygon<linetypes::Quadrilateral, 4>(line, tokens); |
415 return parsePolygon<ldraw::Quadrilateral, 4>(line, tokens); |
416 case 5: |
416 case 5: |
417 return parsePolygon<linetypes::ConditionalEdge, 4>(line, tokens); |
417 return parsePolygon<ldraw::ConditionalEdge, 4>(line, tokens); |
418 default: |
418 default: |
419 throw BodyParseError{utility::format("bad line type '%1'", code)}; |
419 throw BodyParseError{utility::format("bad line type '%1'", code)}; |
420 } |
420 } |
421 } |
421 } |
422 catch(const BodyParseError& error) |
422 catch(const BodyParseError& error) |
423 { |
423 { |
424 return std::make_unique<linetypes::ErrorLine>(line, error.message); |
424 return std::make_unique<ldraw::ErrorLine>(line, error.message); |
425 } |
425 } |
426 } |
426 } |