Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .lfsconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[lfs]
fetchexclude = *
33 changes: 29 additions & 4 deletions lib/src/widgets/inherited_widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,49 @@ class SharedRenderTexture {
final List<SharedTexturePainter> painters = [];
final GlobalKey panelKey;

bool _dirty = true;
bool _scheduled = false;

/// When true, [_paintShared] skips the clear→paint→flush cycle if no
/// painter called [markDirty] since the last flush. When false (default),
/// every scheduled paint runs the full cycle — identical to upstream.
bool dirtyTrackingEnabled = false;

/// Called every frame by the render object's ticker with the frame's
/// elapsed seconds. Listeners can accumulate time and call [markDirty]
/// when a state-machine advance is needed.
void Function(double elapsedSeconds)? onFrameTick;

SharedRenderTexture({
required this.texture,
required this.devicePixelRatio,
required this.backgroundColor,
required this.panelKey,
});

/// Mark the texture as needing a repaint on the next scheduled frame.
void markDirty() {
_dirty = true;
}

/// Paint the shared render texture.
///
/// When [dirtyTrackingEnabled] is true and the texture is clean, the entire
/// clear→paint→flush cycle is skipped. The render-object ticker stays alive
/// independently and invokes [onFrameTick] each frame so external code can
/// call [markDirty] when a state-machine advance is needed.
void _paintShared(_) {
_scheduled = false;
if (dirtyTrackingEnabled && !_dirty) return;

texture.clear(backgroundColor);
for (final painter in painters) {
painter.paintIntoSharedTexture(texture);
}
texture.flush(devicePixelRatio);

_scheduled = false;
_dirty = false;
}

bool _scheduled = false;

/// Schedule a paint of the shared render texture.
void schedulePaint() {
if (_scheduled) {
Expand All @@ -52,11 +75,13 @@ class SharedRenderTexture {
void addPainter(SharedTexturePainter painter) {
painters.add(painter);
painters.sort((a, b) => a.sharedDrawOrder.compareTo(b.sharedDrawOrder));
markDirty();
}

/// Remove a painter from the shared render texture.
void removePainter(SharedTexturePainter painter) {
painters.remove(painter);
markDirty();
}
}

Expand Down
14 changes: 13 additions & 1 deletion lib/src/widgets/shared_texture_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ class SharedTextureViewRenderObject extends RiveNativeRenderBox

int drawOrder = 1;

/// Accumulated elapsed seconds across frames while dirty tracking skips
/// the paint cycle. Reset to 0 after each [paintIntoSharedTexture] call.
double _accumulatedElapsed = 0;

SharedRenderTexture get shared => _shared;
set shared(SharedRenderTexture value) {
if (_shared == value) {
Expand Down Expand Up @@ -182,6 +186,12 @@ class SharedTextureViewRenderObject extends RiveNativeRenderBox
Offset panelPosition = renderBox.localToGlobal(Offset.zero);
Offset globalPosition = localToGlobal(Offset.zero) - panelPosition;

// When dirty tracking is enabled, use accumulated elapsed time so the
// controller receives the full wall-clock delta since the last advance.
final effectiveElapsed =
_shared.dirtyTrackingEnabled ? _accumulatedElapsed : elapsedSeconds;
_accumulatedElapsed = 0;

final renderer = texture.renderer;

renderer.save();
Expand All @@ -195,7 +205,7 @@ class SharedTextureViewRenderObject extends RiveNativeRenderBox
texture,
devicePixelRatio,
size,
elapsedSeconds,
effectiveElapsed,
) ??
false;
if (_shouldAdvance) {
Expand All @@ -220,6 +230,8 @@ class SharedTextureViewRenderObject extends RiveNativeRenderBox
@override
void frameCallback(Duration duration) {
super.frameCallback(duration);
_accumulatedElapsed += elapsedSeconds;
_shared.onFrameTick?.call(elapsedSeconds);
_shared.schedulePaint();
}

Expand Down