Skip to content

Commit 71ff6f3

Browse files
authored
Merge pull request #5 from PlugFox/feature/dirty
Feature/dirty
2 parents 5ca8156 + addf62a commit 71ff6f3

File tree

10 files changed

+102
-41
lines changed

10 files changed

+102
-41
lines changed

.github/workflows/deploy.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: Deploy
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
tags:
7+
- "[0-9]+.[0-9]+.[0-9]+*"
8+
9+
jobs:
10+
deploy:
11+
name: "Deploy to Pub.dev"
12+
permissions:
13+
id-token: write # Required for authentication using OIDC
14+
uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.0.5
2+
3+
- **CHANGED**: `frameRate` is replaced with `needsPaint` in `RePainter` delegate.
4+
15
## 0.0.4
26

37
- **ADDED**: More examples

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
Library for creating and managing a canvas similar to CustomPaint but with more features.
1111

12-
1312
## How to
1413

1514
### Handle mouse events

example/lib/src/feature/fps/fps_screen.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,4 +356,5 @@ final class FrameRateGraph extends RePainterBase {
356356

357357
canvas.restore();
358358
}
359+
359360
}

example/lib/src/feature/sunflower/sunflower_screen.dart

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,15 +239,25 @@ class SunflowerPainter extends PerformanceOverlayPainter {
239239
final size = box.size;
240240
final radius = size.shortestSide / 2; // Радиус окружности
241241
final center = size.center(Offset.zero); // Центр окружности
242+
243+
// https://github.com/flutter/flutter/issues/160184#issuecomment-2560184639
244+
int toARGB32(Color color) {
245+
int floatToInt8(double x) => (x * 255.0).round() & 0xff;
246+
return floatToInt8(color.a) << 24 |
247+
floatToInt8(color.r) << 16 |
248+
floatToInt8(color.g) << 8 |
249+
floatToInt8(color.b) << 0;
250+
}
251+
242252
final outerDotColors = [
243-
Colors.lime.value,
244-
Colors.lightBlue.value,
245-
Colors.lightGreen.value,
253+
toARGB32(Colors.lime),
254+
toARGB32(Colors.lightBlue),
255+
toARGB32(Colors.lightGreen),
246256
];
247257
final innerDotColors = [
248-
Colors.deepOrange.value,
249-
Colors.red.value,
250-
Colors.pink.value,
258+
toARGB32(Colors.deepOrange),
259+
toARGB32(Colors.red),
260+
toARGB32(Colors.pink),
251261
];
252262

253263
// 120 градусов

lib/src/repaint.dart

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -217,24 +217,11 @@ class RePaintBox extends RenderBox with WidgetsBindingObserver {
217217
if (!attached) return;
218218
final delta = elapsed - _lastFrameTime;
219219
final deltaMs = delta.inMicroseconds / Duration.microsecondsPerMillisecond;
220-
switch (_painter.frameRate) {
221-
case null:
222-
// No frame rate limit.
223-
_lastFrameTime = elapsed;
224-
break;
225-
case <= 0:
226-
// Skip updating and rendering the game scene.
227-
_lastFrameTime = elapsed;
228-
return;
229-
case int fr when fr > 0:
230-
final targetFrameTime = 1000 / fr;
231-
if (deltaMs < targetFrameTime) return; // Limit frame rate
232-
_lastFrameTime = elapsed;
233-
break;
234-
}
220+
_lastFrameTime = elapsed;
235221
// Update game scene and prepare for rendering.
236222
_painter.update(this, elapsed, deltaMs);
237-
markNeedsPaint(); // Mark this game scene as dirty and schedule a repaint.
223+
// Mark this game scene as dirty and schedule a repaint.
224+
if (_painter.needsPaint) markNeedsPaint();
238225
}
239226

240227
@override

lib/src/repaint_inline.dart

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class RePaintInline<T extends Object?> extends StatefulWidget {
1414
this.update,
1515
this.tearDown,
1616
this.frameRate,
17+
this.needsPaint = true,
1718
super.key,
1819
});
1920

@@ -40,6 +41,25 @@ class RePaintInline<T extends Object?> extends StatefulWidget {
4041
/// 120 - 120 frames per second.
4142
final int? frameRate;
4243

44+
/// The controller needs to be repainted after the update.
45+
///
46+
/// If `true`, the controller will be repainted.
47+
/// That means the [paint] method will be called after the [update] method.
48+
///
49+
/// If `false`, the controller will not be repainted.
50+
/// That means the [paint] method
51+
/// will not be called after the [update] method.
52+
///
53+
/// This is useful when the controller does not need to be repainted
54+
/// after the update if the scene is static and does not changed over time.
55+
///
56+
/// You can use this flag to optimize the rendering process.
57+
/// For example, implement a frame skipper or a frame limiter.
58+
///
59+
/// If you want to skip the [update] method too,
60+
/// just check it in the [update] method and return immediately.
61+
final bool needsPaint;
62+
4363
@override
4464
State<RePaintInline<T>> createState() => _RePaintInlineState<T>();
4565
}
@@ -72,17 +92,40 @@ final class _InlinePainter<T> extends RePainterBase {
7292

7393
T? state;
7494

95+
double _delta = 0;
96+
7597
@override
76-
int? get frameRate => widget?.frameRate;
98+
bool get needsPaint => _allowFrame && (widget?.needsPaint ?? true);
99+
bool _allowFrame = false;
77100

78101
@override
79102
void mount(RePaintBox box, PipelineOwner owner) {
80103
state = widget?.setUp?.call(box);
104+
_delta = .0;
81105
}
82106

83107
@override
84108
void update(RePaintBox box, Duration elapsed, double delta) {
85-
state = widget?.update?.call(box, state as T, delta) ?? state;
109+
_delta += delta;
110+
switch (widget?.frameRate) {
111+
case null:
112+
// No frame rate limit.
113+
_allowFrame = true;
114+
case <= 0:
115+
// Skip updating and rendering the game scene.
116+
_allowFrame = false;
117+
return;
118+
case int fr when fr > 0:
119+
final targetFrameTime = 1000 / fr;
120+
if (_delta < targetFrameTime) {
121+
_allowFrame = false;
122+
return; // Limit frame rate
123+
}
124+
_allowFrame = true;
125+
}
126+
final dt = _delta;
127+
_delta = .0; // Reset delta
128+
state = widget?.update?.call(box, state as T, dt) ?? state;
86129
}
87130

88131
@override
@@ -92,6 +135,7 @@ final class _InlinePainter<T> extends RePainterBase {
92135

93136
@override
94137
void unmount() {
138+
_delta = .0;
95139
widget?.tearDown?.call(state as T);
96140
}
97141
}

lib/src/repainter_base.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ abstract /* base */ class RePainterBase implements RePainter {
1313
const RePainterBase();
1414

1515
@override
16-
int? get frameRate => null;
16+
bool get needsPaint => true;
1717

1818
@override
1919
void lifecycle(AppLifecycleState state) {

lib/src/repainter_interface.dart

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@ import 'repaint.dart';
66

77
/// The interface for a custom scene painter.
88
abstract interface class RePainter {
9-
/// The [frameRate] is used to limit the frame rate, (limitter and throttler).
9+
/// The controller needs to be repainted after the update.
1010
///
11-
/// If `null`, the frame rate is not limited.
12-
/// 0 - Do not render the scene.
13-
/// 30 - 30 frames per second.
14-
/// 60 - 60 frames per second.
15-
/// 120 - 120 frames per second.
11+
/// If `true`, the controller will be repainted.
12+
/// That means the [paint] method will be called after the [update] method.
1613
///
17-
/// After the [frameRate] is set, the real frame rate will be lower.
18-
/// Before the frame rate, updates are limited by the flutter ticker,
19-
/// so the resulting frame rate will be noticeably lower.
20-
/// Because calling the [update] does not immediately cause a redraw,
21-
/// but only marks the render object as needing a redraw with
22-
/// [RenderObject.markNeedsPaint],
23-
/// thats why the frame rate is lower than expected.
24-
int? get frameRate;
14+
/// If `false`, the controller will not be repainted.
15+
/// That means the [paint] method
16+
/// will not be called after the [update] method.
17+
///
18+
/// This is useful when the controller does not need to be repainted
19+
/// after the update if the scene is static and does not changed over time.
20+
///
21+
/// You can use this flag to optimize the rendering process.
22+
/// For example, implement a frame skipper or a frame limiter.
23+
///
24+
/// If you want to skip the [update] method too,
25+
/// just check it in the [update] method and return immediately.
26+
bool get needsPaint;
2527

2628
/// Mount the controller.
2729
/// Called when the controller is attached to the render box.

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: repaint
33
description: >
44
Library for creating and managing a canvas similar to CustomPaint but with more features.
55
6-
version: 0.0.4
6+
version: 0.0.5
77

88
homepage: https://github.com/PlugFox/repaint
99

0 commit comments

Comments
 (0)