File indexing completed on 2025-01-05 04:01:18
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "rive_loader.hpp" 0008 0009 #include "io/animated_properties.hpp" 0010 #include "model/assets/assets.hpp" 0011 #include "model/shapes/precomp_layer.hpp" 0012 #include "model/shapes/rect.hpp" 0013 #include "model/shapes/ellipse.hpp" 0014 #include "model/shapes/polystar.hpp" 0015 #include "model/shapes/path.hpp" 0016 #include "model/shapes/fill.hpp" 0017 #include "model/shapes/stroke.hpp" 0018 #include "model/shapes/image.hpp" 0019 0020 using namespace glaxnimate; 0021 using namespace glaxnimate::io; 0022 using namespace glaxnimate::io::rive; 0023 0024 namespace { 0025 0026 struct Artboard 0027 { 0028 Artboard() = default; 0029 0030 Artboard(Object* first, Object* last) 0031 : object(first), 0032 children(object), 0033 child_count(last - first + 1) 0034 {} 0035 0036 Object* operator->() const { return object; } 0037 0038 Object* object = nullptr; 0039 Object* children = nullptr; 0040 Identifier child_count = 0; 0041 VarUint timeline_duration = 0; 0042 VarUint keyframe_timeline_duration = 0; 0043 model::Composition* comp = nullptr; 0044 QSizeF size; 0045 }; 0046 0047 template<class T> T load_property_get_keyframe(const detail::JoinedPropertyKeyframe& kf, std::size_t index); 0048 template<> Float32 load_property_get_keyframe<Float32>(const detail::JoinedPropertyKeyframe& kf, std::size_t index) 0049 { 0050 return kf.values[index].vector()[0]; 0051 } 0052 template<> VarUint load_property_get_keyframe<VarUint>(const detail::JoinedPropertyKeyframe& kf, std::size_t index) 0053 { 0054 return kf.values[index].vector()[0]; 0055 } 0056 template<> QColor load_property_get_keyframe<QColor>(const detail::JoinedPropertyKeyframe& kf, std::size_t index) 0057 { 0058 return kf.values[index].color(); 0059 } 0060 0061 template<class... T, class PropT, class Func, std::size_t... Ind, std::size_t N> 0062 void load_property_impl(Object* rive, PropT& property, const detail::AnimatedProperties& animations, 0063 const std::array<const char*, N>& names, T... defvals, const Func& value_func, std::index_sequence<Ind...>) 0064 { 0065 property.set(value_func(rive->get<T>(names[Ind], defvals)...)); 0066 0067 for ( const auto& kf : animations.joined(std::vector<QString>(names.begin(), names.end())) ) 0068 property.set_keyframe(kf.time, value_func(load_property_get_keyframe<T>(kf, Ind)...))->set_transition(kf.transition); 0069 0070 } 0071 0072 template<class... T, class PropT, class Func> 0073 void load_property(Object* rive, PropT& property, const detail::AnimatedProperties& animations, 0074 const std::array<const char*, sizeof...(T)>& names, T... defvals, const Func& value_func) 0075 { 0076 load_property_impl<T...>(rive, property, animations, names, defvals..., value_func, std::index_sequence_for<T...>{}); 0077 } 0078 0079 template<std::size_t RetInd, class... T, class PropT, class Func, std::size_t... Ind, std::size_t N> 0080 void load_property_vector_impl(Object* rive, PropT& property, const detail::AnimatedProperties& animations, 0081 const std::array<const char*, N>& names, T... defvals, const Func& value_func, std::index_sequence<Ind...>) 0082 { 0083 property.set( 0084 std::get<RetInd>( 0085 value_func(rive->get<T>(names[Ind], defvals)...) 0086 ) 0087 ); 0088 0089 for ( const auto& kf : animations.joined(std::vector<QString>(names.begin(), names.end())) ) 0090 property.set_keyframe(kf.time, 0091 std::get<RetInd>(value_func(load_property_get_keyframe<T>(kf, Ind)...)) 0092 )->set_transition(kf.transition); 0093 0094 } 0095 0096 0097 template<class T> 0098 void expand(T...) {} 0099 0100 template<class... T, class... PropT, class Func, std::size_t... Ind, std::size_t... PropInd, std::size_t N> 0101 void load_properties_impl(Object* rive, const std::tuple<PropT...>& properties, const detail::AnimatedProperties& animations, 0102 const std::array<const char*, N>& names, T... defvals, const Func& value_func, 0103 std::index_sequence<Ind...> ind, std::index_sequence<PropInd...>) 0104 { 0105 expand( 0106 (load_property_vector_impl<PropInd, T...>( 0107 rive, *std::get<PropInd>(properties), animations, names, defvals..., value_func, ind 0108 ), 0) ... 0109 ); 0110 } 0111 0112 template<class... T, class... PropT, class Func> 0113 void load_properties( 0114 Object* rive, std::tuple<PropT...> properties, const detail::AnimatedProperties& animations, 0115 const std::array<const char*, sizeof...(T)>& names, T... defvals, const Func& value_func) 0116 { 0117 load_properties_impl<T...>( 0118 rive, properties, animations, names, defvals..., value_func, 0119 std::index_sequence_for<T...>{}, std::index_sequence_for<PropT...>{}); 0120 } 0121 0122 template<class T, class PropT> 0123 void load_property(Object* rive, PropT& property, const detail::AnimatedProperties& animations, const char* name, T defval = {}) 0124 { 0125 property.set(rive->get<T>(name, defval)); 0126 0127 for ( const auto& kf : animations.joined({name}) ) 0128 property.set_keyframe(kf.time, load_property_get_keyframe<T>(kf, 0))->set_transition(kf.transition); 0129 } 0130 0131 QPointF make_point(Float32 x, Float32 y) 0132 { 0133 return QPointF(x, y); 0134 } 0135 0136 struct Asset 0137 { 0138 Object* object = nullptr; 0139 model::Asset* asset = nullptr; 0140 }; 0141 0142 struct LoadCotext 0143 { 0144 void new_artboard(Object* object) 0145 { 0146 artboards[object] = Artboard(object, &objects.back()); 0147 artboard = &artboards[object]; 0148 artboards_id.push_back(artboard); 0149 artboard->comp = document->assets()->compositions->values.insert(std::make_unique<model::Composition>(document)); 0150 artboard->size = QSizeF( 0151 object->get<Float32>("width"), 0152 object->get<Float32>("height") 0153 ); 0154 } 0155 0156 Object* artboard_child(Identifier id) const 0157 { 0158 if ( artboard && id < artboard->child_count ) 0159 return artboard->children + id; 0160 return nullptr; 0161 } 0162 0163 LoadCotext(RiveFormat* format, model::Document* document) 0164 : document(document), format(format) 0165 { 0166 main = document->assets()->compositions->values.insert(std::make_unique<model::Composition>(document)); 0167 } 0168 0169 void preprocess_object(Object* object) 0170 { 0171 if ( object->type().id == TypeId::Artboard ) 0172 { 0173 new_artboard(object); 0174 } 0175 else if ( object->type().id == TypeId::KeyedObject ) 0176 { 0177 if ( !artboard ) 0178 { 0179 format->warning(i18n("Unexpected Keyed Object")); 0180 return; 0181 } 0182 auto id = object->get<Identifier>("objectId", artboard->child_count); 0183 keyed_object = artboard_child(id); 0184 keyed_property = nullptr; 0185 if ( !keyed_object ) 0186 { 0187 format->warning(i18n("Invalid Keyed Object id %1", id)); 0188 return; 0189 } 0190 } 0191 else if ( object->type().id == TypeId::KeyedProperty ) 0192 { 0193 if ( !keyed_object ) 0194 { 0195 format->warning(i18n("Unexpected Keyed Property")); 0196 return; 0197 } 0198 0199 auto id = object->get<Identifier>("propertyKey"); 0200 auto prop = keyed_object->type().property(id); 0201 0202 if ( !prop ) 0203 { 0204 format->warning(i18n("Unknown Keyed Property id %1", id)); 0205 return; 0206 } 0207 0208 keyed_object->animations().push_back({prop, {}}); 0209 keyed_property = &keyed_object->animations().back(); 0210 } 0211 else if ( object->type().id == TypeId::LinearAnimation ) 0212 { 0213 if ( !artboard ) 0214 { 0215 format->warning(i18n("Unexpected Animation")); 0216 return; 0217 } 0218 0219 auto duration = object->get<VarUint>("duration"); 0220 if ( duration > artboard->timeline_duration ) 0221 artboard->timeline_duration = duration; 0222 } 0223 else if ( object->type().id == TypeId::ImageAsset ) 0224 { 0225 assets.push_back({object, load_image_asset(object)}); 0226 } 0227 else if ( object->type().id == TypeId::FileAssetContents ) 0228 { 0229 if ( assets.empty() ) 0230 { 0231 format->warning(i18n("Unexpected Asset Contents")); 0232 return; 0233 } 0234 0235 auto data = object->get<QByteArray>("bytes"); 0236 if ( data.isEmpty() ) 0237 return; 0238 0239 if ( auto img = qobject_cast<model::Bitmap*>(assets.back().asset) ) 0240 { 0241 if ( !img->from_raw_data(data) ) 0242 format->warning(i18n("Invalid Image Data")); 0243 } 0244 } 0245 else if ( object->has_type(TypeId::Asset) ) 0246 { 0247 assets.push_back({object, nullptr}); 0248 } 0249 else if ( object->has_type(TypeId::KeyFrame) ) 0250 { 0251 if ( !keyed_property ) 0252 { 0253 format->warning(i18n("Unexpected Keyframe")); 0254 return; 0255 } 0256 0257 auto frame = object->get<VarUint>("duration"); 0258 if ( frame > artboard->keyframe_timeline_duration ) 0259 artboard->keyframe_timeline_duration = frame; 0260 0261 keyed_property->keyframes.push_back(object); 0262 } 0263 else if ( object->has("parentId") ) 0264 { 0265 auto parent_id = object->get<Identifier>("parentId"); 0266 auto parent = artboard_child(parent_id); 0267 if ( !parent ) 0268 format->warning(i18n("Could not find parent with id %1", parent_id)); 0269 else 0270 parent->children().push_back(object); 0271 } 0272 } 0273 0274 void process_object(Object* object) 0275 { 0276 if ( object->type().id == TypeId::Artboard ) 0277 { 0278 process_artboard(object); 0279 } 0280 } 0281 0282 void process_artboard(Object* object) 0283 { 0284 const auto& artboard = artboards.at(object); 0285 0286 artboard.comp->name.set(object->get<QString>("name")); 0287 add_shapes(object, artboard.comp->shapes); 0288 0289 auto precomp_layer = std::make_unique<model::PreCompLayer>(document); 0290 precomp_layer->name.set(artboard.comp->name.get()); 0291 precomp_layer->size.set(artboard.size.toSize()); 0292 detail::AnimatedProperties animations = load_animations(object); 0293 load_transform(object, precomp_layer->transform.get(), animations, QRectF(QPointF(0, 0), artboard.size)); 0294 precomp_layer->opacity.set(object->get<Float32>("opacity", 1)); 0295 precomp_layer->composition.set(artboard.comp); 0296 0297 float last_frame = artboard.timeline_duration == 0 ? artboard.keyframe_timeline_duration : artboard.timeline_duration; 0298 main->animation->last_frame.set(qMax(main->animation->last_frame.get(), last_frame)); 0299 0300 if ( document->assets()->compositions->values.size() == 1 ) 0301 { 0302 main->width.set(precomp_layer->size.get().width()); 0303 main->height.set(precomp_layer->size.get().height()); 0304 } 0305 0306 main->shapes.insert(std::move(precomp_layer)); 0307 } 0308 0309 void add_shapes(Object* parent, model::ObjectListProperty<model::ShapeElement>& prop) 0310 { 0311 0312 std::vector<std::unique_ptr<model::ShapeElement>> shapes; 0313 0314 for ( Object* child : parent->children() ) 0315 { 0316 if ( child == parent ) 0317 { 0318 format->error(i18n("Parent circular reference detected")); 0319 continue; 0320 } 0321 0322 auto shape = load_shape(child); 0323 if ( shape ) 0324 { 0325 if ( child->has_type(TypeId::Node) ) 0326 shapes.emplace_back(std::move(shape)); 0327 else 0328 prop.insert(std::move(shape)); 0329 } 0330 } 0331 0332 for ( auto it = shapes.rbegin(); it != shapes.rend(); ++it ) 0333 prop.insert(std::move(*it)); 0334 } 0335 0336 std::unique_ptr<model::Layer> load_shape_layer(Object* shape, const detail::AnimatedProperties& animations) 0337 { 0338 auto layer = std::make_unique<model::Layer>(document); 0339 load_shape_group(shape, layer.get(), animations); 0340 return layer; 0341 } 0342 0343 void load_transform(Object* rive, model::Transform* transform, const detail::AnimatedProperties& animations, const QRectF& bbox) 0344 { 0345 load_property<Float32, Float32>(rive, transform->position, animations, {"x", "y"}, 0, 0, &make_point); 0346 0347 if ( rive->type().property("originX") ) 0348 { 0349 load_property<Float32, Float32>(rive, transform->anchor_point, animations, {"originX", "originY"}, 0.5, 0.5, 0350 [&bbox](Float32 ox, Float32 oy){ 0351 return QPointF( 0352 math::lerp(bbox.left(), bbox.right(), ox), 0353 math::lerp(bbox.top(), bbox.bottom(), oy) 0354 ); 0355 } 0356 ); 0357 } 0358 0359 /*load_properties<Float32, Float32, Float32, Float32>( 0360 rive, 0361 std::make_tuple(&transform->position, &transform->anchor_point), 0362 animations, 0363 {"x", "y", "originX", "originY"}, 0364 0, 0, 0.5, 0.5, 0365 [&bbox] ( Float32 x, Float32 y, Float32 ox, Float32 oy ) { 0366 QPointF anchor( 0367 math::lerp(bbox.left(), bbox.right(), ox), 0368 math::lerp(bbox.top(), bbox.bottom(), oy) 0369 ); 0370 return std::make_tuple(QPointF(x, y) - anchor, anchor); 0371 } 0372 );*/ 0373 load_property<Float32>(rive, transform->rotation, animations, "rotation"); 0374 load_property<Float32, Float32>(rive, transform->scale, animations, {"scaleX", "scaleX"}, 1, 1, [](Float32 x, Float32 y){ 0375 return QVector2D(x, y); 0376 }); 0377 } 0378 0379 void load_shape_group(Object* shape, model::Group* group, const detail::AnimatedProperties& animations) 0380 { 0381 load_property<Float32>(shape, group->opacity, animations, "opacity", 1); 0382 group->name.set(shape->get<QString>("name")); 0383 add_shapes(shape, group->shapes); 0384 auto box = group->local_bounding_rect(0); 0385 load_transform(shape, group->transform.get(), animations, box); 0386 } 0387 0388 std::unique_ptr<model::ShapeElement> load_shape(Object* object) 0389 { 0390 detail::AnimatedProperties animations = load_animations(object); 0391 0392 switch ( object->type().id ) 0393 { 0394 case TypeId::Shape: 0395 case TypeId::Node: 0396 return load_shape_layer(object, animations); 0397 case TypeId::Rectangle: 0398 return load_rectangle(object, animations); 0399 case TypeId::Ellipse: 0400 return load_ellipse(object, animations); 0401 case TypeId::Fill: 0402 return load_fill(object, animations); 0403 case TypeId::Stroke: 0404 return load_stroke(object, animations); 0405 case TypeId::Polygon: 0406 return load_polygon(object, animations, model::PolyStar::Polygon); 0407 case TypeId::Star: 0408 return load_polygon(object, animations, model::PolyStar::Star); 0409 case TypeId::Triangle: 0410 return load_triangle(object, animations); 0411 case TypeId::PointsPath: 0412 return load_path(object, animations); 0413 case TypeId::NestedArtboard: 0414 return load_precomp(object, animations); 0415 case TypeId::Image: 0416 return load_image(object, animations); 0417 case TypeId::TrimPath: 0418 case TypeId::Bone: 0419 case TypeId::RootBone: 0420 case TypeId::ClippingShape: 0421 case TypeId::Text: 0422 /// \todo 0423 default: 0424 return {}; 0425 } 0426 } 0427 0428 std::unique_ptr<model::Group> load_rectangle(Object* object, const detail::AnimatedProperties& animations) 0429 { 0430 auto group = std::make_unique<model::Group>(document); 0431 auto shape = std::make_unique<model::Rect>(document); 0432 shape->name.set(object->get<QString>("name")); 0433 0434 load_property<Float32, Float32, Float32, Float32>(object, shape->rounded, animations, 0435 {"cornerRadiusTL", "cornerRadiusBL", "cornerRadiusBR", "cornerRadiusTR"}, 0436 0, 0, 0, 0, 0437 [](Float32 tl, Float32 bl, Float32 br, Float32 tr){ 0438 return (tl + bl + br + tr) / 4; 0439 } 0440 ); 0441 0442 load_property<Float32, Float32>(object, shape->size, animations, {"width", "height"}, 0, 0, [](Float32 x, Float32 y){ 0443 return QSizeF(x, y); 0444 }); 0445 0446 group->shapes.insert(std::move(shape)); 0447 load_shape_group(object, group.get(), animations); 0448 return group; 0449 } 0450 0451 std::unique_ptr<model::Group> load_ellipse(Object* object, const detail::AnimatedProperties& animations) 0452 { 0453 auto group = std::make_unique<model::Group>(document); 0454 auto shape = std::make_unique<model::Ellipse>(document); 0455 shape->name.set(object->get<QString>("name")); 0456 0457 0458 load_property<Float32, Float32>(object, shape->size, animations, {"width", "height"}, 0, 0, [](Float32 x, Float32 y){ 0459 return QSizeF(x, y); 0460 }); 0461 0462 group->shapes.insert(std::move(shape)); 0463 load_shape_group(object, group.get(), animations); 0464 return group; 0465 } 0466 0467 std::unique_ptr<model::Fill> load_fill(Object* object, const detail::AnimatedProperties& animations) 0468 { 0469 auto shape = std::make_unique<model::Fill>(document); 0470 load_styler(object, shape.get(), animations); 0471 /// \todo fillRule 0472 return shape; 0473 } 0474 0475 std::unique_ptr<model::Stroke> load_stroke(Object* object, const detail::AnimatedProperties& animations) 0476 { 0477 auto shape = std::make_unique<model::Stroke>(document); 0478 load_styler(object, shape.get(), animations); 0479 load_property<Float32>(object, shape->width, animations, "thickness"); 0480 /// \todo cap + join 0481 return shape; 0482 } 0483 0484 void load_styler(Object* object, model::Styler* shape, const detail::AnimatedProperties& animations) 0485 { 0486 shape->name.set(object->get<QString>("name")); 0487 shape->visible.set(object->get<bool>("isVisible", true)); 0488 load_property<Float32>(object, shape->opacity, animations, "opacity", 1); 0489 0490 for ( const auto& child : object->children() ) 0491 { 0492 if ( child->type().id == TypeId::SolidColor ) 0493 load_property<QColor>(child, shape->color, load_animations(child), "colorValue", QColor("#747474")); 0494 else if ( child->type().id == TypeId::LinearGradient ) 0495 shape->use.set(load_gradient(child, model::Gradient::Linear)); 0496 else if ( child->type().id == TypeId::RadialGradient ) 0497 shape->use.set(load_gradient(child, model::Gradient::Radial)); 0498 } 0499 } 0500 0501 model::Gradient* load_gradient(Object* object, model::Gradient::GradientType type) 0502 { 0503 auto colors = std::make_unique<glaxnimate::model::GradientColors>(document); 0504 colors->name.set(object->get<QString>("name")); 0505 auto colors_ptr = colors.get(); 0506 document->assets()->gradient_colors->values.insert(std::move(colors)); 0507 0508 auto gradient = std::make_unique<glaxnimate::model::Gradient>(document); 0509 gradient->name.set(object->get<QString>("name")); 0510 gradient->colors.set(colors_ptr); 0511 gradient->type.set(type); 0512 0513 auto animations = load_animations(object); 0514 load_property<Float32, Float32>(object, gradient->start_point, animations, {"startX", "startY"}, 0, 0, &make_point); 0515 load_property<Float32, Float32>(object, gradient->end_point, animations, {"endX", "endY"}, 0, 0, &make_point); 0516 0517 /// \todo color animations 0518 QGradientStops stops; 0519 for ( const auto& child : object->children() ) 0520 { 0521 if ( child->type().id == TypeId::GradientStop ) 0522 { 0523 stops.push_back({ 0524 child->get<Float32>("position"), 0525 child->get<QColor>("colorValue"), 0526 }); 0527 } 0528 } 0529 colors_ptr->colors.set(stops); 0530 0531 auto ptr = gradient.get(); 0532 document->assets()->gradients->values.insert(std::move(gradient)); 0533 return ptr; 0534 } 0535 0536 detail::AnimatedProperties load_animations(Object* object) 0537 { 0538 using namespace glaxnimate::io::detail; 0539 0540 AnimatedProperties props; 0541 for ( const auto& anim : object->animations() ) 0542 { 0543 AnimatedProperty& prop = props.properties[anim.property->name]; 0544 for ( auto kf : anim.keyframes ) 0545 { 0546 model::KeyframeTransition transition; /// \todo 0547 prop.keyframes.push_back({ 0548 kf->get<Float32>("frame", 0), 0549 ValueVariant(kf->get_variant("value")), 0550 transition 0551 }); 0552 } 0553 } 0554 return props; 0555 } 0556 0557 std::unique_ptr<model::Group> load_polygon(Object* object, const detail::AnimatedProperties& animations, model::PolyStar::StarType type) 0558 { 0559 auto group = std::make_unique<model::Group>(document); 0560 load_shape_group(object, group.get(), animations); 0561 0562 auto shape = std::make_unique<model::PolyStar>(document); 0563 shape->name.set(object->get<QString>("name")); 0564 shape->type.set(type); 0565 /// \todo cornerRadius 0566 load_property<VarUint>(object, shape->points, animations, "points", 5); 0567 shape->outer_radius.set(100); 0568 0569 load_property<Float32>(object, shape->inner_radius, animations, {"innerRadius"}, 0.5, [](Float32 pc){ 0570 return pc * 100; 0571 }); 0572 0573 load_property<Float32>(object, shape->points, animations, "points", 5); 0574 0575 0576 load_property<Float32, Float32, Float32, Float32>(object, group->transform->scale, animations, 0577 {"scaleX", "scaleY", "width", "height"}, 0578 1, 1, 0, 0, [](Float32 sx, Float32 sy, Float32 w, Float32 h){ 0579 return QVector2D(w / 200 * sx, h / 200 * sy); 0580 }); 0581 0582 group->shapes.insert(std::move(shape)); 0583 return group; 0584 } 0585 0586 std::unique_ptr<model::Group> load_triangle(Object* object, const detail::AnimatedProperties& animations) 0587 { 0588 auto group = std::make_unique<model::Group>(document); 0589 auto shape = std::make_unique<model::Path>(document); 0590 shape->name.set(object->get<QString>("name")); 0591 0592 0593 load_property<Float32, Float32>(object, shape->shape, animations, {"width", "height"}, 0, 0, [](Float32 w, Float32 h){ 0594 math::bezier::Bezier path; 0595 path.add_point({-w/2, h/2}); 0596 path.add_point({0, -h/2}); 0597 path.add_point({w/2, h/2}); 0598 path.close(); 0599 return path; 0600 }); 0601 0602 group->shapes.insert(std::move(shape)); 0603 load_shape_group(object, group.get(), animations); 0604 return group; 0605 } 0606 0607 std::unique_ptr<model::Path> load_path(Object* object, const detail::AnimatedProperties& animations) 0608 { 0609 auto shape = std::make_unique<model::Path>(document); 0610 shape->name.set(object->get<QString>("name")); 0611 bool closed = object->get<bool>("isClosed"); 0612 shape->closed.set(closed); 0613 0614 math::bezier::Bezier bez; 0615 for ( const auto& child : object->children() ) 0616 { 0617 math::bezier::Point p; 0618 p.pos = QPointF(child->get<Float32>("x", 0), child->get<Float32>("y", 0)); 0619 if ( child->type().id == TypeId::CubicMirroredVertex ) 0620 { 0621 p.type = math::bezier::Symmetrical; 0622 auto tangent = math::from_polar<QPointF>( 0623 child->get<Float32>("distance"), 0624 child->get<Float32>("rotation") 0625 ); 0626 p.tan_in = p.pos - tangent; 0627 p.tan_out = p.pos + tangent; 0628 } 0629 else if ( child->type().id == TypeId::CubicAsymmetricVertex ) 0630 { 0631 p.type = math::bezier::Smooth; 0632 p.tan_in = p.pos - math::from_polar<QPointF>( 0633 child->get<Float32>("inDistance"), 0634 child->get<Float32>("rotation") 0635 ); 0636 p.tan_out = p.pos + math::from_polar<QPointF>( 0637 child->get<Float32>("outDistance"), 0638 child->get<Float32>("rotation") 0639 ); 0640 } 0641 else if ( child->type().id == TypeId::CubicDetachedVertex ) 0642 { 0643 p.type = math::bezier::Corner; 0644 p.tan_in = p.pos + math::from_polar<QPointF>( 0645 child->get<Float32>("inDistance"), 0646 child->get<Float32>("inRotation") 0647 ); 0648 p.tan_out = p.pos + math::from_polar<QPointF>( 0649 child->get<Float32>("outDistance"), 0650 child->get<Float32>("outRotation") 0651 ); 0652 } 0653 else if ( child->type().id == TypeId::StraightVertex ) 0654 { 0655 p.type = math::bezier::Corner; 0656 p.tan_in = p.tan_out = p.pos; 0657 } 0658 else 0659 { 0660 continue; 0661 } 0662 0663 bez.push_back(p); 0664 } 0665 0666 bez.set_closed(closed); 0667 0668 /// \todo animation 0669 Q_UNUSED(animations); 0670 shape->shape.set(bez); 0671 0672 return shape; 0673 } 0674 0675 std::unique_ptr<model::PreCompLayer> load_precomp(Object* object, const detail::AnimatedProperties& animations) 0676 { 0677 auto shape = std::make_unique<model::PreCompLayer>(document); 0678 shape->name.set(object->get<QString>("name")); 0679 load_property<Float32>(object, shape->opacity, animations, "opacity", 1); 0680 0681 QRectF box; 0682 0683 if ( object->has("artboardId") ) 0684 { 0685 auto id = object->get<VarUint>("artboardId"); 0686 shape->size.set(artboards_id[id]->size); 0687 shape->composition.set(artboards_id[id]->comp); 0688 box.setSize(artboards_id[id]->size); 0689 } 0690 0691 load_transform(object, shape->transform.get(), animations, box); 0692 return shape; 0693 } 0694 0695 model::Bitmap* load_image_asset(Object* object) 0696 { 0697 auto image = std::make_unique<glaxnimate::model::Bitmap>(document); 0698 image->filename.set(object->get<QString>("name")); 0699 image->width.set(object->get<Float32>("width")); 0700 image->height.set(object->get<Float32>("height")); 0701 auto ptr = image.get(); 0702 document->assets()->images->values.insert(std::move(image)); 0703 return ptr; 0704 } 0705 0706 std::unique_ptr<model::Image> load_image(Object* object, const detail::AnimatedProperties& animations) 0707 { 0708 auto shape = std::make_unique<model::Image>(document); 0709 shape->name.set(object->get<QString>("name")); 0710 auto id = object->get<VarUint>("assetId"); 0711 QSizeF size; 0712 if ( auto bmp = qobject_cast<model::Bitmap*>(assets[id].asset) ) 0713 { 0714 size = bmp->size(); 0715 shape->transform->anchor_point.set(QPointF( 0716 bmp->width.get() / 2., 0717 bmp->height.get() / 2. 0718 )); 0719 shape->image.set(bmp); 0720 } 0721 load_transform(object, shape->transform.get(), animations, {QPointF(0, 0), size}); 0722 0723 return shape; 0724 } 0725 0726 model::Document* document = nullptr; 0727 std::map<Object*, Artboard> artboards; 0728 std::vector<Object> objects; 0729 Artboard* artboard = nullptr; 0730 Object* keyed_object = nullptr; 0731 PropertyAnimation* keyed_property = nullptr; 0732 RiveFormat* format = nullptr; 0733 std::vector<Artboard*> artboards_id; 0734 std::vector<Asset> assets; 0735 model::Composition* main = nullptr; 0736 }; 0737 0738 } // namespace 0739 0740 RiveLoader::RiveLoader(BinaryInputStream& stream, RiveFormat* format) 0741 : stream(stream), 0742 format(format) 0743 { 0744 extra_props = read_property_table(); 0745 QObject::connect(&types, &TypeSystem::type_not_found, [format](int type){ 0746 format->error(i18n("Unknown object of type %1", int(type))); 0747 }); 0748 0749 if ( stream.has_error() ) 0750 format->error(i18n("Could not read property table")); 0751 0752 } 0753 0754 std::vector<Object> RiveLoader::load_object_list() 0755 { 0756 if ( stream.has_error() ) 0757 return {}; 0758 0759 std::vector<Object> objects; 0760 while ( !stream.has_error() && !stream.eof() ) 0761 objects.emplace_back(read_object()); 0762 return objects; 0763 } 0764 0765 bool RiveLoader::load_document(model::Document* document) 0766 { 0767 if ( stream.has_error() ) 0768 return false; 0769 0770 LoadCotext context(format, document); 0771 0772 while ( !stream.has_error() && !stream.eof() ) 0773 if ( auto obj = read_object() ) 0774 context.objects.emplace_back(std::move(obj)); 0775 0776 for ( auto& object : context.objects ) 0777 context.preprocess_object(&object); 0778 0779 0780 for ( auto& object : context.objects ) 0781 context.process_object(&object); 0782 0783 return true; 0784 } 0785 0786 Object RiveLoader::read_object() 0787 { 0788 auto type_id = TypeId(stream.read_uint_leb128()); 0789 if ( stream.has_error() ) 0790 { 0791 format->error(i18n("Could not load object type ID")); 0792 return {}; 0793 } 0794 0795 Object obj = types.object(type_id); 0796 0797 if ( !obj ) 0798 return {}; 0799 0800 while ( true ) 0801 { 0802 Identifier prop_id = stream.read_uint_leb128(); 0803 if ( stream.has_error() ) 0804 { 0805 format->error(i18n("Could not load property ID in %1 (%2)") 0806 .arg(int(type_id)).arg(obj.definition()->name)); 0807 return {}; 0808 } 0809 0810 if ( prop_id == 0 ) 0811 break; 0812 0813 auto prop_def = obj.type().property(prop_id); 0814 if ( !prop_def ) 0815 { 0816 auto unknown_it = extra_props.find(prop_id); 0817 if ( unknown_it == extra_props.end() ) 0818 { 0819 format->error(i18n("Unknown property %1 of %2 (%3)") 0820 .arg(prop_id).arg(int(type_id)).arg(obj.definition()->name)); 0821 return {}; 0822 } 0823 else 0824 { 0825 format->warning(i18n("Skipping unknown property %1 of %2 (%3)") 0826 .arg(prop_id).arg(int(type_id)).arg(obj.definition()->name)); 0827 } 0828 } 0829 else 0830 { 0831 obj.set(prop_def, read_property_value(prop_def->type)); 0832 if ( stream.has_error() ) 0833 { 0834 format->error(i18n("Error loading property %1 (%2) of %3 (%4)") 0835 .arg(prop_id).arg(prop_def->name).arg(int(type_id)).arg(obj.definition()->name)); 0836 return {}; 0837 } 0838 } 0839 } 0840 0841 return obj; 0842 } 0843 0844 0845 QVariant RiveLoader::read_property_value(PropertyType type) 0846 { 0847 switch ( type ) 0848 { 0849 case PropertyType::Bool: 0850 return bool(stream.next()); 0851 case PropertyType::Bytes: 0852 return read_raw_string(); 0853 case PropertyType::String: 0854 return read_string_utf8(); 0855 case PropertyType::VarUint: 0856 return QVariant::fromValue(stream.read_uint_leb128()); 0857 case PropertyType::Float: 0858 return stream.read_float32_le(); 0859 case PropertyType::Color: 0860 return QColor::fromRgba(stream.read_uint32_le()); 0861 } 0862 0863 return {}; 0864 } 0865 0866 0867 PropertyTable RiveLoader::read_property_table() 0868 { 0869 std::vector<VarUint> props; 0870 while ( true ) 0871 { 0872 VarUint id = stream.read_uint_leb128(); 0873 if ( stream.has_error() ) 0874 return {}; 0875 0876 if ( id == 0 ) 0877 break; 0878 0879 props.push_back(id); 0880 } 0881 0882 quint32 current_int = 0; 0883 quint32 bit = 8; 0884 0885 PropertyTable table; 0886 0887 for ( auto id : props ) 0888 { 0889 if ( bit == 8 ) 0890 { 0891 current_int = stream.read_uint32_le(); 0892 if ( stream.has_error() ) 0893 return {}; 0894 bit = 0; 0895 } 0896 0897 int type = (current_int >> bit) & 3; 0898 if ( type == 0 ) 0899 table[id] = PropertyType::VarUint; 0900 else if ( type == 1 ) 0901 table[id] = PropertyType::String; 0902 else if ( type == 2 ) 0903 table[id] = PropertyType::Float; 0904 else if ( type == 3 ) 0905 table[id] = PropertyType::Color; 0906 0907 bit += 2; 0908 } 0909 0910 return table; 0911 } 0912 0913 void RiveLoader::skip_value(glaxnimate::io::rive::PropertyType type) 0914 { 0915 switch ( type ) 0916 { 0917 case PropertyType::Bool: 0918 case PropertyType::VarUint: 0919 stream.read_uint_leb128(); 0920 break; 0921 case PropertyType::Bytes: 0922 case PropertyType::String: 0923 read_raw_string(); 0924 break; 0925 case PropertyType::Float: 0926 stream.read_float32_le(); 0927 break; 0928 case PropertyType::Color: 0929 stream.read_uint32_le(); 0930 break; 0931 } 0932 } 0933 0934 const PropertyTable& RiveLoader::extra_properties() const 0935 { 0936 return extra_props; 0937 } 0938 0939 QByteArray RiveLoader::read_raw_string() 0940 { 0941 auto size = stream.read_uint_leb128(); 0942 if ( stream.has_error() ) 0943 return {}; 0944 0945 return stream.read(size); 0946 } 0947 0948 QString RiveLoader::read_string_utf8() 0949 { 0950 return QString::fromUtf8(read_raw_string()); 0951 }