Skip to content

Commit 81b5e8b

Browse files
Ink Open Sourcecopybara-github
authored andcommitted
Add BrushBehavior::Target::kAnimationFrameOffset
This CL adds the necessary boilerplate and plumbing for a new brush behavior target for controlling the starting animation frame of animated particles. Such a target can be wired up to e.g. a noise node to make particles start on a random frame, or a distance-traveled source to make a series of particles that cycle through starting frames in order, or whatever else is desired. The actual extruder change to use the new field in the `BrushTipState` to alter the particle's texture UV coordinates is left as a TODO for the next CL. PiperOrigin-RevId: 720180903
1 parent d0de0c3 commit 81b5e8b

File tree

11 files changed

+53
-0
lines changed

11 files changed

+53
-0
lines changed

ink/brush/brush_behavior.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ bool IsValidBehaviorTarget(BrushBehavior::Target target) {
296296
case BrushBehavior::Target::kPositionOffsetYInMultiplesOfBrushSize:
297297
case BrushBehavior::Target::kPositionOffsetForwardInMultiplesOfBrushSize:
298298
case BrushBehavior::Target::kPositionOffsetLateralInMultiplesOfBrushSize:
299+
case BrushBehavior::Target::kAnimationFrameOffset:
299300
case BrushBehavior::Target::kHueOffsetInRadians:
300301
case BrushBehavior::Target::kSaturationMultiplier:
301302
case BrushBehavior::Target::kLuminosity:
@@ -650,6 +651,8 @@ std::string ToFormattedString(BrushBehavior::Target target) {
650651
return "kPositionOffsetForwardInMultiplesOfBrushSize";
651652
case BrushBehavior::Target::kPositionOffsetLateralInMultiplesOfBrushSize:
652653
return "kPositionOffsetLateralInMultiplesOfBrushSize";
654+
case BrushBehavior::Target::kAnimationFrameOffset:
655+
return "kAnimationFrameOffset";
653656
case BrushBehavior::Target::kHueOffsetInRadians:
654657
return "kHueOffsetInRadians";
655658
case BrushBehavior::Target::kSaturationMultiplier:

ink/brush/brush_behavior.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ struct BrushBehavior {
286286
// Y-axis (and a negative value moves the brush tip center towards the
287287
// negative Y-axis).
288288
kPositionOffsetLateralInMultiplesOfBrushSize,
289+
// Adds the target modifier to the initial animation frame number of the
290+
// current particle (which is relevant only for strokes with an animated
291+
// texture). The final frame number offset will be rounded to the nearest
292+
// integer after all behaviors have been applied.
293+
kAnimationFrameOffset,
289294

290295
// The following are targets for tip color adjustments, including opacity.
291296
// Renderers can apply them to the brush color when a stroke is drawn to

ink/brush/brush_behavior_test.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,22 @@ TEST(BrushBehaviorTest, StringifyTarget) {
161161
"kRotationOffsetInRadians");
162162
EXPECT_EQ(absl::StrCat(BrushBehavior::Target::kCornerRoundingOffset),
163163
"kCornerRoundingOffset");
164+
EXPECT_EQ(absl::StrCat(
165+
BrushBehavior::Target::kPositionOffsetXInMultiplesOfBrushSize),
166+
"kPositionOffsetXInMultiplesOfBrushSize");
167+
EXPECT_EQ(absl::StrCat(
168+
BrushBehavior::Target::kPositionOffsetYInMultiplesOfBrushSize),
169+
"kPositionOffsetYInMultiplesOfBrushSize");
170+
EXPECT_EQ(
171+
absl::StrCat(
172+
BrushBehavior::Target::kPositionOffsetForwardInMultiplesOfBrushSize),
173+
"kPositionOffsetForwardInMultiplesOfBrushSize");
174+
EXPECT_EQ(
175+
absl::StrCat(
176+
BrushBehavior::Target::kPositionOffsetLateralInMultiplesOfBrushSize),
177+
"kPositionOffsetLateralInMultiplesOfBrushSize");
178+
EXPECT_EQ(absl::StrCat(BrushBehavior::Target::kAnimationFrameOffset),
179+
"kAnimationFrameOffset");
164180
EXPECT_EQ(absl::StrCat(BrushBehavior::Target::kHueOffsetInRadians),
165181
"kHueOffsetInRadians");
166182
EXPECT_EQ(absl::StrCat(BrushBehavior::Target::kSaturationMultiplier),

ink/brush/fuzz_domains.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ Domain<BrushBehavior::Target> ArbitraryBrushBehaviorTarget() {
232232
BrushBehavior::Target::kPositionOffsetYInMultiplesOfBrushSize,
233233
BrushBehavior::Target::kPositionOffsetForwardInMultiplesOfBrushSize,
234234
BrushBehavior::Target::kPositionOffsetLateralInMultiplesOfBrushSize,
235+
BrushBehavior::Target::kAnimationFrameOffset,
235236
BrushBehavior::Target::kHueOffsetInRadians,
236237
BrushBehavior::Target::kSaturationMultiplier,
237238
BrushBehavior::Target::kLuminosity,

ink/storage/brush.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,8 @@ proto::BrushBehavior::Target EncodeBrushBehaviorTarget(
389389
case BrushBehavior::Target::kPositionOffsetLateralInMultiplesOfBrushSize:
390390
return proto::BrushBehavior::
391391
TARGET_POSITION_OFFSET_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE;
392+
case BrushBehavior::Target::kAnimationFrameOffset:
393+
return proto::BrushBehavior::TARGET_ANIMATION_FRAME_OFFSET;
392394
case BrushBehavior::Target::kHueOffsetInRadians:
393395
return proto::BrushBehavior::TARGET_HUE_OFFSET_IN_RADIANS;
394396
case BrushBehavior::Target::kSaturationMultiplier:
@@ -440,6 +442,8 @@ absl::StatusOr<BrushBehavior::Target> DecodeBrushBehaviorTarget(
440442
TARGET_POSITION_OFFSET_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE:
441443
return BrushBehavior::Target::
442444
kPositionOffsetLateralInMultiplesOfBrushSize;
445+
case proto::BrushBehavior::TARGET_ANIMATION_FRAME_OFFSET:
446+
return BrushBehavior::Target::kAnimationFrameOffset;
443447
default:
444448
return absl::InvalidArgumentError(absl::StrCat(
445449
"invalid ink.proto.BrushBehavior.Target value: ", target_proto));

ink/storage/proto/brush.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ message BrushBehavior {
293293
TARGET_POSITION_OFFSET_FORWARD_IN_MULTIPLES_OF_BRUSH_SIZE = 14;
294294
TARGET_POSITION_OFFSET_LATERAL_IN_MULTIPLES_OF_BRUSH_SIZE = 15;
295295
reserved 16;
296+
TARGET_ANIMATION_FRAME_OFFSET = 17;
296297
}
297298
// LINT.ThenChange(../../brush/brush_behavior.h:target)
298299

ink/strokes/internal/brush_tip_extruder.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ AffineTransform ComputeParticleSurfaceUvTransform(
388388
const BrushTipState& tip_state) {
389389
// This transform takes tip size, position, and rotation into account, but
390390
// deliberately ignores tip slant, pinch, and corner rounding.
391+
// TODO: b/373651450 - Use `tip_state.animation_frame_offset` here.
391392
return AffineTransform::Translate({0.5, 0.5}) *
392393
AffineTransform::Scale(1.0f / tip_state.width,
393394
1.0f / tip_state.height) *

ink/strokes/internal/brush_tip_modeler.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ float InitialTargetModifierValue(BrushBehavior::Target target) {
5555
case BrushBehavior::Target::kPositionOffsetYInMultiplesOfBrushSize:
5656
case BrushBehavior::Target::kPositionOffsetForwardInMultiplesOfBrushSize:
5757
case BrushBehavior::Target::kPositionOffsetLateralInMultiplesOfBrushSize:
58+
case BrushBehavior::Target::kAnimationFrameOffset:
5859
case BrushBehavior::Target::kHueOffsetInRadians:
5960
case BrushBehavior::Target::kLuminosity:
6061
return 0.f;

ink/strokes/internal/brush_tip_modeler_helpers.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ struct BrushTipStateModifiers {
539539
float corner_rounding_offset = 0;
540540
Angle rotation_offset;
541541
float pinch_offset = 0;
542+
int animation_frame_offset = 0;
542543
Angle hue_offset;
543544
float saturation_multiplier = 1;
544545
float luminosity = 0;
@@ -597,6 +598,9 @@ void ApplyModifierToTarget(float modifier, BrushBehavior::Target target,
597598
modifier * brush_size);
598599
}
599600
break;
601+
case BrushBehavior::Target::kAnimationFrameOffset:
602+
tip_state_modifiers.animation_frame_offset += modifier;
603+
break;
600604
case BrushBehavior::Target::kHueOffsetInRadians:
601605
tip_state_modifiers.hue_offset += Angle::Radians(modifier);
602606
break;
@@ -637,6 +641,7 @@ void ApplyModifiersToTipState(const BrushTipStateModifiers& modifiers,
637641
tip_state.percent_radius = std::clamp(
638642
tip_state.percent_radius + modifiers.corner_rounding_offset, 0.f, 1.f);
639643
}
644+
tip_state.animation_frame_offset += modifiers.animation_frame_offset;
640645
if (modifiers.hue_offset != Angle()) {
641646
tip_state.hue_offset_in_full_turns =
642647
modifiers.hue_offset.Normalized() / kFullTurn;

ink/strokes/internal/brush_tip_modeler_helpers_test.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,6 +1535,17 @@ TEST(CreateTipStateTest, WithBehaviorTargetingCornerRounding) {
15351535
{clamp_offset});
15361536
EXPECT_FLOAT_EQ(state.percent_radius, /**clamped to 0*/ 0);
15371537
}
1538+
1539+
TEST(CreateTipStateTest, WithBehaviorTargetingAnimationFrame) {
1540+
BrushTip brush_tip = MakeBaseBrushTip();
1541+
float brush_size = 2.5f;
1542+
float animation_frame_offset = 3;
1543+
BrushTipState state = CreateTipState(
1544+
{0, 0}, Angle(), brush_tip, brush_size,
1545+
{BrushBehavior::Target::kAnimationFrameOffset}, {animation_frame_offset});
1546+
EXPECT_FLOAT_EQ(state.animation_frame_offset, animation_frame_offset);
1547+
}
1548+
15381549
TEST(CreateTipStateTest, WithBehaviorTargetingHue) {
15391550
BrushTip brush_tip = MakeBaseBrushTip();
15401551
float brush_size = 2.5f;

0 commit comments

Comments
 (0)