Skip to content

Commit

Permalink
Adding support for runtime image swapping, requires marking image nod…
Browse files Browse the repository at this point in the history
…es as isDynamic in Flare. Issue #183.
  • Loading branch information
luigi-rosso committed Nov 7, 2019
1 parent 53a7c65 commit 366cdc0
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 1 deletion.
4 changes: 4 additions & 0 deletions flare_dart/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [2.2.4] - 2019-11-07 12:14:49

- Adding support for ActorImage.isDynamic which allows Flare to pacakge source UV coordinates for the image such that it can be swapped at runtime. This requires re-exporting files from Flare after marking the image as dynamic in the Flare UI.

## [2.2.3] - 2019-10-29 12:44:02

- Copy transformAffectsStroke from the source shape when instancing.
Expand Down
12 changes: 12 additions & 0 deletions flare_dart/lib/actor_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class ActorImage extends ActorDrawable with ActorSkinnable {

int _textureIndex = -1;
Float32List _vertices;
Float32List _dynamicUV;
Float32List get dynamicUV => _dynamicUV;
Uint16List _triangles;
int _vertexCount = 0;
int _triangleCount = 0;
Expand Down Expand Up @@ -141,6 +143,15 @@ class ActorImage extends ActorDrawable with ActorSkinnable {
node._vertices =
reader.readFloat32Array(numVertices * node.vertexStride, "vertices");

// In version 24 we started packing the original UV coordinates if the
// image was marked for dynamic runtime swapping.
if (artboard.actor.version >= 24) {
bool isDynamic = reader.readBool("isDynamic");
if (isDynamic) {
node._dynamicUV = reader.readFloat32Array(numVertices * 2, "uv");
}
}

int numTris = reader.readUint32("numTriangles");
node._triangles = Uint16List(numTris * 3);
node._triangleCount = numTris;
Expand Down Expand Up @@ -217,6 +228,7 @@ class ActorImage extends ActorDrawable with ActorSkinnable {
_triangleCount = node._triangleCount;
_vertices = node._vertices;
_triangles = node._triangles;
_dynamicUV = node._dynamicUV;
if (node._animationDeformedVertices != null) {
_animationDeformedVertices =
Float32List.fromList(node._animationDeformedVertices);
Expand Down
4 changes: 4 additions & 0 deletions flare_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [1.7.0] - 2019-11-07 12:16:35

- Adding support for runtime image swapping.

## [1.6.5] - 2019-11-06 17:29:43

- Fixed an issue with FlareCacheBuilder calling setState when the widget is no longer mounted.
Expand Down
62 changes: 61 additions & 1 deletion flare_flutter/lib/flare.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,67 @@ class FlutterActorImage extends ActorImage with FlutterActorDrawable {
}
}

/// Swap the image used to draw the mesh for this image node.
/// Returns true when successful.
bool changeImage(ui.Image image) {
if (triangles == null || dynamicUV == null) {
return false;
}
_uvBuffer = makeVertexUVBuffer();
int count = vertexCount;

// SKIA requires texture coordinates in full image space, not traditional
// normalized uv coordinates.
int idx = 0;
for (int i = 0; i < count; i++) {
_uvBuffer[idx] = dynamicUV[idx] * image.width;
_uvBuffer[idx + 1] = dynamicUV[idx + 1] * image.height;
idx += 2;
}

_paint.shader = image != null
? ui.ImageShader(
image, ui.TileMode.clamp, ui.TileMode.clamp, _identityMatrix)
: null;

_canvasVertices = ui.Vertices.raw(ui.VertexMode.triangles, _vertexBuffer,
indices: _indices, textureCoordinates: _uvBuffer);

onPaintUpdated(_paint);

return true;
}

/// Change the image for this node via a network url.
/// Returns true when successful.
Future<bool> changeImageFromNetwork(String url) async {
var networkImage = NetworkImage(url);
var val = await networkImage.obtainKey(const ImageConfiguration());
var load = networkImage.load(val, (Uint8List bytes,
{int cacheWidth, int cacheHeight}) {
return PaintingBinding.instance.instantiateImageCodec(bytes,
cacheWidth: cacheWidth, cacheHeight: cacheHeight);
});

final completer = Completer<bool>();
load.addListener(ImageStreamListener((ImageInfo info, bool syncCall) {
changeImage(info.image);
completer.complete(true);
}));
return completer.future;
}

/// Change the image for this node with one in an asset bundle.
/// Returns true when successful.
Future<bool> changeImageFromBundle(
AssetBundle bundle, String filename) async {
ByteData data = await bundle.load(filename);
ui.Codec codec =
await ui.instantiateImageCodec(Uint8List.view(data.buffer));
ui.FrameInfo frame = await codec.getNextFrame();
return changeImage(frame.image);
}

@override
void initializeGraphics() {
super.initializeGraphics();
Expand Down Expand Up @@ -1139,7 +1200,6 @@ class FlutterActorImage extends ActorImage with FlutterActorDrawable {
canvas.save();

clip(canvas);

_paint.color =
_paint.color.withOpacity(renderOpacity.clamp(0.0, 1.0).toDouble());

Expand Down

0 comments on commit 366cdc0

Please sign in to comment.