mirror of
https://github.com/google/pebble.git
synced 2025-05-01 15:51:40 -04:00
179 lines
7.2 KiB
C
179 lines
7.2 KiB
C
/*
|
|
* Copyright 2024 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "animation.h"
|
|
#include "animation_interpolate.h"
|
|
#include "animation_private.h"
|
|
|
|
#include "applib/graphics/gtypes.h"
|
|
#include "system/passert.h"
|
|
#include "util/math.h"
|
|
#include "util/size.h"
|
|
|
|
int64_t interpolate_int64_linear(int32_t normalized, int64_t from, int64_t to) {
|
|
return from + ((normalized * (to - from)) / ANIMATION_NORMALIZED_MAX);
|
|
}
|
|
|
|
int64_t interpolate_int64(int32_t normalized, int64_t from, int64_t to) {
|
|
InterpolateInt64Function interpolate =
|
|
animation_private_current_interpolate_override() ?: interpolate_int64_linear;
|
|
return interpolate(normalized, from, to);
|
|
}
|
|
|
|
int16_t interpolate_int16(int32_t normalized, int16_t from, int16_t to) {
|
|
const int64_t interpolated = interpolate_int64(normalized, from, to);
|
|
return (int16_t)CLIP(interpolated, INT16_MIN, INT16_MAX);
|
|
}
|
|
|
|
uint32_t interpolate_uint32(int32_t normalized, uint32_t from, uint32_t to) {
|
|
const int64_t interpolated = interpolate_int64(normalized, from, to);
|
|
return (uint32_t)CLIP(interpolated, 0, UINT32_MAX);
|
|
}
|
|
|
|
Fixed_S32_16 interpolate_fixed32(int32_t normalized, Fixed_S32_16 from, Fixed_S32_16 to) {
|
|
const int64_t interpolated = interpolate_int64(normalized, from.raw_value, to.raw_value);
|
|
const int32_t raw_value =
|
|
(int32_t) CLIP(interpolated, INT32_MIN, INT32_MAX);
|
|
return Fixed_S32_16(raw_value);
|
|
}
|
|
|
|
GSize interpolate_gsize(int32_t normalized, GSize from, GSize to) {
|
|
return (GSize) {
|
|
.w = interpolate_int16(normalized, from.w, to.w),
|
|
.h = interpolate_int16(normalized, from.w, to.w),
|
|
};
|
|
}
|
|
|
|
GPoint interpolate_gpoint(int32_t normalized, GPoint from, GPoint to) {
|
|
return (GPoint) {
|
|
.x = interpolate_int16(normalized, from.x, to.x),
|
|
.y = interpolate_int16(normalized, from.y, to.y),
|
|
};
|
|
}
|
|
|
|
int16_t scale_int16(int16_t value, int16_t from, int16_t to) {
|
|
return (int16_t) ((int32_t) value * to / from);
|
|
}
|
|
|
|
int32_t scale_int32(int32_t value, int32_t from, int32_t to) {
|
|
return (int32_t) ((int64_t) value * to / from);
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
|
|
// these values are directly taken from "easing red line 001.mov"
|
|
// _in will be added to first value (easing in, anticipation)
|
|
// _out will be added to second value (overshoot, swing-back)
|
|
static const int32_t s_delta_moook_in[] = {0, 1, 20};
|
|
static const int32_t s_delta_moook_out[] = {INTERPOLATE_MOOOK_BOUNCE_BACK, 2, 1, 0};
|
|
|
|
// TODO: export these as interpolation functions as well
|
|
uint32_t interpolate_moook_in_duration() {
|
|
return ARRAY_LENGTH(s_delta_moook_in) * ANIMATION_TARGET_FRAME_INTERVAL_MS;
|
|
}
|
|
|
|
uint32_t interpolate_moook_out_duration() {
|
|
return ARRAY_LENGTH(s_delta_moook_out) * ANIMATION_TARGET_FRAME_INTERVAL_MS;
|
|
}
|
|
|
|
uint32_t interpolate_moook_duration() {
|
|
return interpolate_moook_in_duration() + interpolate_moook_out_duration();
|
|
}
|
|
|
|
uint32_t interpolate_moook_soft_duration(int32_t num_frames_mid) {
|
|
return interpolate_moook_duration() + num_frames_mid * ANIMATION_TARGET_FRAME_INTERVAL_MS;
|
|
}
|
|
|
|
uint32_t interpolate_moook_custom_duration(const MoookConfig *config) {
|
|
PBL_ASSERTN(config);
|
|
return ((config->num_frames_in + config->num_frames_mid + config->num_frames_out) *
|
|
ANIMATION_TARGET_FRAME_INTERVAL_MS);
|
|
}
|
|
|
|
static int64_t prv_interpolate_moook(
|
|
int32_t normalized, int64_t from, int64_t to, const int32_t *frames_in, int32_t num_frames_in,
|
|
const int32_t *frames_out, int32_t num_frames_out, int32_t num_frames_mid, bool bounce_back) {
|
|
const int32_t direction = ((from == to) ? 0 : ((from < to) ? 1 : -1));
|
|
if (direction == 0) {
|
|
return from;
|
|
}
|
|
|
|
const int32_t direction_out = direction * (bounce_back ? 1 : -1);
|
|
const size_t num_frames_total = num_frames_in + num_frames_mid + num_frames_out;
|
|
int32_t frame_idx =
|
|
((normalized * num_frames_total + (ANIMATION_NORMALIZED_MAX / (2 * num_frames_total))) /
|
|
ANIMATION_NORMALIZED_MAX);
|
|
frame_idx = CLIP(frame_idx, 0, (int)num_frames_total - 1);
|
|
|
|
|
|
if (normalized == ANIMATION_NORMALIZED_MAX) {
|
|
return to;
|
|
} else if (frame_idx < 0) {
|
|
return from;
|
|
} else if (frame_idx < num_frames_in) {
|
|
return from + (frames_in ? (direction * frames_in[frame_idx]) : 0);
|
|
} else if ((frame_idx < (num_frames_in + num_frames_mid)) && (num_frames_mid > 0)) {
|
|
const int64_t shifted_normalized = normalized -
|
|
(((int64_t) num_frames_in * ANIMATION_NORMALIZED_MAX) / num_frames_total);
|
|
const int32_t mid_normalized = ((int64_t) num_frames_total * shifted_normalized) /
|
|
num_frames_mid;
|
|
return interpolate_int64_linear(mid_normalized,
|
|
from + (direction * frames_in[num_frames_in - 1]),
|
|
to + (direction_out * frames_out[0]));
|
|
} else {
|
|
return to + (frames_out ? (direction_out *
|
|
frames_out[frame_idx - (num_frames_in + num_frames_mid)]) : 0);
|
|
}
|
|
}
|
|
|
|
int64_t interpolate_moook_in(int32_t normalized, int64_t from, int64_t to, int32_t num_frames_to) {
|
|
return prv_interpolate_moook(normalized, from, to, s_delta_moook_in,
|
|
ARRAY_LENGTH(s_delta_moook_in), NULL, num_frames_to, 0, true);
|
|
}
|
|
|
|
int64_t interpolate_moook_in_only(int32_t normalized, int64_t from, int64_t to) {
|
|
return prv_interpolate_moook(normalized, from, to, s_delta_moook_in,
|
|
ARRAY_LENGTH(s_delta_moook_in), NULL, 0, 0, true);
|
|
}
|
|
|
|
int64_t interpolate_moook_out(int32_t normalized, int64_t from, int64_t to,
|
|
int32_t num_frames_from, bool bounce_back) {
|
|
return prv_interpolate_moook(normalized, from, to, NULL, num_frames_from, s_delta_moook_out,
|
|
ARRAY_LENGTH(s_delta_moook_out), 0, bounce_back);
|
|
}
|
|
|
|
int64_t interpolate_moook(int32_t normalized, int64_t from, int64_t to) {
|
|
return prv_interpolate_moook(normalized, from, to,
|
|
s_delta_moook_in, ARRAY_LENGTH(s_delta_moook_in),
|
|
s_delta_moook_out, ARRAY_LENGTH(s_delta_moook_out), 0, true);
|
|
}
|
|
|
|
int64_t interpolate_moook_soft(int32_t normalized, int64_t from, int64_t to,
|
|
int32_t num_frames_mid) {
|
|
return prv_interpolate_moook(normalized, from, to,
|
|
s_delta_moook_in, ARRAY_LENGTH(s_delta_moook_in),
|
|
s_delta_moook_out, ARRAY_LENGTH(s_delta_moook_out),
|
|
num_frames_mid, true);
|
|
}
|
|
|
|
int64_t interpolate_moook_custom(int32_t normalized, int64_t from, int64_t to,
|
|
const MoookConfig *config) {
|
|
PBL_ASSERTN(config);
|
|
return prv_interpolate_moook(normalized, from, to,
|
|
config->frames_in, config->num_frames_in,
|
|
config->frames_out, config->num_frames_out,
|
|
config->num_frames_mid, !config->no_bounce_back);
|
|
}
|