diff --git a/src/bindings/wasm/meson.build b/src/bindings/wasm/meson.build index 49ee8d92..cde36704 100644 --- a/src/bindings/wasm/meson.build +++ b/src/bindings/wasm/meson.build @@ -1,5 +1,5 @@ if (cc.get_id() == 'emscripten') - source_file = files('tvgWasm.cpp') + source_file = files('tvgWasmLottieAnimation.cpp') thorvg_wasm_dep = declare_dependency(include_directories : include_directories('.'), sources : source_file) diff --git a/src/bindings/wasm/tvgWasm.cpp b/src/bindings/wasm/tvgWasmLottieAnimation.cpp similarity index 51% rename from src/bindings/wasm/tvgWasm.cpp rename to src/bindings/wasm/tvgWasmLottieAnimation.cpp index 8b04b80f..b18373e7 100644 --- a/src/bindings/wasm/tvgWasm.cpp +++ b/src/bindings/wasm/tvgWasmLottieAnimation.cpp @@ -29,28 +29,18 @@ using namespace tvg; static const char* NoError = "None"; -class __attribute__((visibility("default"))) TvgWasm +class __attribute__((visibility("default"))) TvgLottieAnimation { - //This structure data should be aligned with the ThorVG Viewer implementation. - struct Layer - { - uint32_t paint; //cast of a paint pointer - uint32_t depth; - uint32_t type; - uint8_t opacity; - CompositeMethod method; - }; - public: - ~TvgWasm() + ~TvgLottieAnimation() { free(buffer); Initializer::term(CanvasEngine::Sw); } - static unique_ptr create() + static unique_ptr create() { - return unique_ptr(new TvgWasm()); + return unique_ptr(new TvgLottieAnimation()); } string error() @@ -58,7 +48,32 @@ public: return errorMsg; } - bool load(string data, string mimetype, int width, int height) + // Getter methods + val size() + { + return val(typed_memory_view(2, psize)); + } + + val duration() + { + if (!canvas || !animation) return val(0); + return val(animation->duration()); + } + + val totalFrame() + { + if (!canvas || !animation) return val(0); + return val(animation->totalFrame()); + } + + val curFrame() + { + if (!canvas || !animation) return val(0); + return val(animation->curFrame()); + } + + // Render methods + bool load(string data, string mimetype, int width, int height, string rpath = "") { errorMsg = NoError; @@ -96,20 +111,6 @@ public: return true; } - bool update() - { - if (!updated) return true; - - errorMsg = NoError; - - if (canvas->update() != Result::Success) { - errorMsg = "update() fail"; - return false; - } - - return true; - } - val render() { errorMsg = NoError; @@ -130,21 +131,18 @@ public: return val(typed_memory_view(width * height * 4, buffer)); } - val size() + bool update() { - return val(typed_memory_view(2, psize)); - } + if (!updated) return true; - val duration() - { - if (!canvas || !animation) return val(0); - return val(animation->duration()); - } + errorMsg = NoError; - val totalFrame() - { - if (!canvas || !animation) return val(0); - return val(animation->totalFrame()); + if (canvas->update() != Result::Success) { + errorMsg = "update() fail"; + return false; + } + + return true; } bool frame(float no) @@ -183,35 +181,7 @@ public: updated = true; } - bool save2Tvg() - { - errorMsg = NoError; - - if (!animation) return false; - - auto duplicate = cast(animation->picture()->duplicate()); - - if (!duplicate) { - errorMsg = "duplicate(), fail"; - return false; - } - - auto saver = Saver::gen(); - if (!saver) { - errorMsg = "Invalid saver"; - return false; - } - - if (saver->save(std::move(duplicate), "output.tvg") != tvg::Result::Success) { - errorMsg = "save(), fail"; - return false; - } - - saver->sync(); - - return true; - } - + // Saver methods bool save2Gif(string data, string mimetype, int width, int height, int fps) { errorMsg = NoError; @@ -257,62 +227,10 @@ public: return true; } - val layers() - { - if (!canvas || !animation) return val(nullptr); - - //returns an array of a structure Layer: [id] [depth] [type] [composite] - children.reset(); - sublayers(&children, animation->picture(), 0); - - return val(typed_memory_view(children.count * sizeof(Layer) / sizeof(uint32_t), (uint32_t *)(children.data))); - } - - bool opacity(uint32_t id, uint8_t opacity) - { - if (!canvas || !animation) return false; - - auto paint = findPaintById(animation->picture(), id, nullptr); - if (!paint) return false; - const_cast(paint)->opacity(opacity); - return true; - } - - val geometry(uint32_t id) - { - if (!canvas || !animation) return val(typed_memory_view(0, nullptr)); - - Array parents; - auto paint = findPaintById(animation->picture(), id, &parents); - if (!paint) return val(typed_memory_view(0, nullptr)); - paint->bounds(&bounds[0], &bounds[1], &bounds[2], &bounds[3], false); - - float points[8] = { //clockwise points - bounds[0], bounds[1], //(x1, y1) - bounds[0] + bounds[2], bounds[1], //(x2, y1) - bounds[0] + bounds[2], bounds[1] + bounds[3], //(x2, y2) - bounds[0], bounds[1] + bounds[3], //(x1, y2) - }; - - for (auto paint = parents.data; paint < parents.end(); ++paint) { - auto m = const_cast(*paint)->transform(); - for (int i = 0; i < 8; i += 2) { - float x = points[i] * m.e11 + points[i+1] * m.e12 + m.e13; - points[i] = x; - points[i + 1] = points[i] * m.e21 + points[i + 1] * m.e22 + m.e23; - } - } - - bounds[0] = points[0]; //x(p1) - bounds[1] = points[3]; //y(p2) - bounds[2] = points[4] - bounds[0]; //x(p3) - bounds[3] = points[7] - bounds[1]; //y(p4) - - return val(typed_memory_view(4, bounds)); - } + // TODO: Advanced APIs wrt Interactivty & theme methods... private: - explicit TvgWasm() + explicit TvgLottieAnimation() { errorMsg = NoError; @@ -328,90 +246,30 @@ private: if (!animation) errorMsg = "Invalid animation"; } - void sublayers(Array* layers, const Paint* paint, uint32_t depth) - { - //paint - if (paint->identifier() != Shape::identifier()) { - auto it = IteratorAccessor::iterator(paint); - if (it->count() > 0) { - it->begin(); - layers->grow(it->count()); - while (auto child = it->next()) { - uint32_t type = child->identifier(); - layers->push({.paint = reinterpret_cast(child), .depth = depth + 1, .type = type, .opacity = child->opacity(), .method = CompositeMethod::None}); - sublayers(layers, child, depth + 1); - } - } - } - //composite - const Paint* target = nullptr; - CompositeMethod method = paint->composite(&target); - if (target && method != CompositeMethod::None) { - layers->push({.paint = reinterpret_cast(target), .depth = depth, .type = target->identifier(), .opacity = target->opacity(), .method = method}); - sublayers(layers, target, depth); - } - } - - const Paint* findPaintById(const Paint* parent, uint32_t id, Array* parents) { - //validate paintId is correct and exists in the picture - if (reinterpret_cast(parent) == id) { - if (parents) parents->push(parent); - return parent; - } - //paint - if (parent->identifier() != Shape::identifier()) { - auto it = IteratorAccessor::iterator(parent); - if (it->count() > 0) { - it->begin(); - while (auto child = it->next()) { - if (auto paint = findPaintById(child, id, parents)) { - if (parents) parents->push(parent); - return paint; - } - } - } - } - //composite - const Paint* target = nullptr; - CompositeMethod method = parent->composite(&target); - if (target && method != CompositeMethod::None) { - if (auto paint = findPaintById(target, id, parents)) { - if (parents) parents->push(parent); - return paint; - } - } - return nullptr; - } - private: string errorMsg; unique_ptr canvas = nullptr; unique_ptr animation = nullptr; uint8_t* buffer = nullptr; - Array children; uint32_t width = 0; uint32_t height = 0; - float bounds[4]; float psize[2]; //picture size bool updated = false; }; - -EMSCRIPTEN_BINDINGS(thorvg_bindings) { - class_("TvgWasm") - .constructor(&TvgWasm::create) - .function("error", &TvgWasm::error, allow_raw_pointers()) - .function("load", &TvgWasm::load) - .function("update", &TvgWasm::update) - .function("resize", &TvgWasm::resize) - .function("render", &TvgWasm::render) - .function("size", &TvgWasm::size) - .function("duration", &TvgWasm::duration) - .function("totalFrame", &TvgWasm::totalFrame) - .function("frame", &TvgWasm::frame) - .function("save2Tvg", &TvgWasm::save2Tvg) - .function("save2Gif", &TvgWasm::save2Gif) - .function("layers", &TvgWasm::layers) - .function("geometry", &TvgWasm::geometry) - .function("opacity", &TvgWasm::opacity); -} \ No newline at end of file +EMSCRIPTEN_BINDINGS(thorvg_bindings) +{ + class_("TvgLottieAnimation") + .constructor(&TvgLottieAnimation ::create) + .function("error", &TvgLottieAnimation ::error, allow_raw_pointers()) + .function("size", &TvgLottieAnimation ::size) + .function("duration", &TvgLottieAnimation ::duration) + .function("totalFrame", &TvgLottieAnimation ::totalFrame) + .function("curFrame", &TvgLottieAnimation ::curFrame) + .function("render", &TvgLottieAnimation::render) + .function("load", &TvgLottieAnimation ::load) + .function("update", &TvgLottieAnimation ::update) + .function("frame", &TvgLottieAnimation ::frame) + .function("resize", &TvgLottieAnimation ::resize) + .function("save2Gif", &TvgLottieAnimation ::save2Gif); +}