mirror of
https://github.com/google/pebble.git
synced 2025-04-30 15:21:41 -04:00
256 lines
7.8 KiB
C
256 lines
7.8 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 "gtypes.h"
|
|
#include "gtransform.h"
|
|
#include "util/trig.h"
|
|
|
|
#include <string.h>
|
|
|
|
//////////////////////////////////////
|
|
/// Creating Transforms
|
|
//////////////////////////////////////
|
|
// Note that int64_t casting is required since cos/sin values are already in a 32-bit fixed point
|
|
// representation and when passed to this function. They need to be scaled by the
|
|
// Fixed_S32_16 precision (16-bits) before dividing by the TRIG_MAX_RATIO. This multiply is what
|
|
// makes the int64_t casting necessary to avoid overflowing across 32-bits.
|
|
GTransform gtransform_init_rotation(int32_t angle) {
|
|
if (angle != 0) {
|
|
int32_t cosine = cos_lookup(angle);
|
|
int32_t sine = sin_lookup(angle);
|
|
int64_t cosine_val = (cosine * ((int64_t)GTransformNumberOne.raw_value)) / TRIG_MAX_RATIO;
|
|
int64_t sine_val = (sine * ((int64_t)GTransformNumberOne.raw_value)) / TRIG_MAX_RATIO;
|
|
GTransformNumber a = (GTransformNumber) { .raw_value = cosine_val };
|
|
GTransformNumber b = (GTransformNumber) { .raw_value = -sine_val };
|
|
GTransformNumber c = (GTransformNumber) { .raw_value = sine_val };
|
|
GTransformNumber d = (GTransformNumber) { .raw_value = cosine_val };
|
|
return GTransform(a, b, c, d, GTransformNumberZero, GTransformNumberZero);
|
|
} else {
|
|
return GTransformIdentity();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
/// Evaluating Transforms
|
|
//////////////////////////////////////
|
|
bool gtransform_is_identity(const GTransform * const t) {
|
|
if (!t) {
|
|
return false;
|
|
}
|
|
|
|
GTransform t_c = GTransformIdentity();
|
|
|
|
if (memcmp(t, &t_c, sizeof(GTransform)) == 0) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool gtransform_is_only_scale(const GTransform * const t) {
|
|
if (!t) {
|
|
return false;
|
|
}
|
|
|
|
if ((t->b.raw_value == GTransformNumberZero.raw_value) &&
|
|
(t->c.raw_value == GTransformNumberZero.raw_value) &&
|
|
(t->tx.raw_value == GTransformNumberZero.raw_value) &&
|
|
(t->ty.raw_value == GTransformNumberZero.raw_value)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool gtransform_is_only_translation(const GTransform * const t) {
|
|
if (!t) {
|
|
return false;
|
|
}
|
|
|
|
if ((t->a.raw_value == GTransformNumberOne.raw_value) &&
|
|
(t->b.raw_value == GTransformNumberZero.raw_value) &&
|
|
(t->c.raw_value == GTransformNumberZero.raw_value) &&
|
|
(t->d.raw_value == GTransformNumberOne.raw_value)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool gtransform_is_only_scale_or_translation(const GTransform * const t) {
|
|
if (!t) {
|
|
return false;
|
|
}
|
|
|
|
if ((t->b.raw_value != GTransformNumberZero.raw_value) ||
|
|
(t->c.raw_value != GTransformNumberZero.raw_value)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool gtransform_is_equal(const GTransform * const t1, const GTransform * const t2) {
|
|
if ((!t1) || (!t2)) {
|
|
return false;
|
|
}
|
|
|
|
return memcmp(t1, t2, sizeof(GTransform)) == 0;
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
/// Modifying Transforms
|
|
//////////////////////////////////////
|
|
// Note that t_new can be set to either of t1 or t2 safely to do in place multiplication
|
|
// Note this operation is not commutative. The operation is as follows t_new = t1 * t2
|
|
void gtransform_concat(GTransform *t_new, const GTransform *t1, const GTransform * t2) {
|
|
if ((!t_new) || (!t1) || (!t2)) {
|
|
return;
|
|
}
|
|
|
|
Fixed_S32_16 a_a = Fixed_S32_16_mul(t1->a, t2->a);
|
|
Fixed_S32_16 b_c = Fixed_S32_16_mul(t1->b, t2->c);
|
|
|
|
Fixed_S32_16 a_b = Fixed_S32_16_mul(t1->a, t2->b);
|
|
Fixed_S32_16 b_d = Fixed_S32_16_mul(t1->b, t2->d);
|
|
|
|
Fixed_S32_16 c_a = Fixed_S32_16_mul(t1->c, t2->a);
|
|
Fixed_S32_16 d_c = Fixed_S32_16_mul(t1->d, t2->c);
|
|
|
|
Fixed_S32_16 c_b = Fixed_S32_16_mul(t1->c, t2->b);
|
|
Fixed_S32_16 d_d = Fixed_S32_16_mul(t1->d, t2->d);
|
|
|
|
Fixed_S32_16 tx_a = Fixed_S32_16_mul(t1->tx, t2->a);
|
|
Fixed_S32_16 ty_c = Fixed_S32_16_mul(t1->ty, t2->c);
|
|
|
|
Fixed_S32_16 tx_b = Fixed_S32_16_mul(t1->tx, t2->b);
|
|
Fixed_S32_16 ty_d = Fixed_S32_16_mul(t1->ty, t2->d);
|
|
|
|
t_new->a = Fixed_S32_16_add(a_a, b_c);
|
|
t_new->b = Fixed_S32_16_add(a_b, b_d);
|
|
t_new->c = Fixed_S32_16_add(c_a, d_c);
|
|
t_new->d = Fixed_S32_16_add(c_b, d_d);
|
|
t_new->tx = Fixed_S32_16_add3(tx_a, ty_c, t2->tx);
|
|
t_new->ty = Fixed_S32_16_add3(tx_b, ty_d, t2->ty);
|
|
}
|
|
|
|
void gtransform_scale(GTransform *t_new, GTransform *t, GTransformNumber sx, GTransformNumber sy) {
|
|
if ((!t_new) || (!t)) {
|
|
return;
|
|
}
|
|
|
|
// Copy over t to t_new and update as necessary
|
|
if (t_new != t) {
|
|
memcpy(t_new, t, sizeof(GTransform));
|
|
}
|
|
|
|
// t_new = ts*t
|
|
|
|
// Scale X vector (a and b)
|
|
t_new->a = Fixed_S32_16_mul(sx, t->a);
|
|
t_new->b = Fixed_S32_16_mul(sx, t->b);
|
|
|
|
// Scale Y vector (c and d)
|
|
t_new->c = Fixed_S32_16_mul(sy, t->c);
|
|
t_new->d = Fixed_S32_16_mul(sy, t->d);
|
|
}
|
|
|
|
void gtransform_translate(GTransform *t_new, GTransform *t,
|
|
GTransformNumber tx, GTransformNumber ty) {
|
|
if ((!t_new) || (!t)) {
|
|
return;
|
|
}
|
|
|
|
// Copy over t to t_new and update as necessary
|
|
if (t_new != t) {
|
|
memcpy(t_new, t, sizeof(GTransform));
|
|
}
|
|
|
|
// t_new = tt*t
|
|
Fixed_S32_16 tx_a = Fixed_S32_16_mul(tx, t->a);
|
|
Fixed_S32_16 ty_c = Fixed_S32_16_mul(ty, t->c);
|
|
|
|
Fixed_S32_16 tx_b = Fixed_S32_16_mul(tx, t->b);
|
|
Fixed_S32_16 ty_d = Fixed_S32_16_mul(ty, t->d);
|
|
|
|
t_new->tx = Fixed_S32_16_add3(tx_a, ty_c, t->tx);
|
|
t_new->ty = Fixed_S32_16_add3(tx_b, ty_d, t->ty);
|
|
}
|
|
|
|
void gtransform_rotate(GTransform *t_new, GTransform *t, int32_t angle) {
|
|
if ((!t_new) || (!t)) {
|
|
return;
|
|
}
|
|
|
|
// t_new = tr*t
|
|
GTransform tR = gtransform_init_rotation(angle);
|
|
gtransform_concat(t_new, &tR, t);
|
|
}
|
|
|
|
bool gtransform_invert(GTransform *t_new, GTransform *t) {
|
|
if ((!t_new) || (!t)) {
|
|
return false;
|
|
}
|
|
|
|
memcpy(t_new, t, sizeof(GTransform));
|
|
// FIXME: NYI - copy original into t_new for now
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////
|
|
/// Applying Transformations
|
|
//////////////////////////////////////
|
|
GPointPrecise gpoint_transform(GPoint point, const GTransform * const t) {
|
|
GPointPrecise pointP = GPointPreciseFromGPoint(point);
|
|
|
|
if (!t) {
|
|
return pointP;
|
|
}
|
|
|
|
Fixed_S16_3 x_a = Fixed_S16_3_S32_16_mul(pointP.x, t->a);
|
|
Fixed_S16_3 y_c = Fixed_S16_3_S32_16_mul(pointP.y, t->c);
|
|
Fixed_S16_3 one_tx = Fixed_S16_3_S32_16_mul(FIXED_S16_3_ONE, t->tx);
|
|
|
|
Fixed_S16_3 x_b = Fixed_S16_3_S32_16_mul(pointP.x, t->b);
|
|
Fixed_S16_3 y_d = Fixed_S16_3_S32_16_mul(pointP.y, t->d);
|
|
Fixed_S16_3 one_ty = Fixed_S16_3_S32_16_mul(FIXED_S16_3_ONE, t->ty);
|
|
|
|
Fixed_S16_3 sum_x = Fixed_S16_3_add3(x_a, y_c, one_tx);
|
|
Fixed_S16_3 sum_y = Fixed_S16_3_add3(x_b, y_d, one_ty);
|
|
|
|
return GPointPrecise(sum_x.raw_value, sum_y.raw_value);
|
|
}
|
|
|
|
GVectorPrecise gvector_transform(GVector vector, const GTransform * const t) {
|
|
GVectorPrecise vectorP = GVectorPreciseFromGVector(vector);
|
|
|
|
if (!t) {
|
|
return vectorP;
|
|
}
|
|
|
|
Fixed_S16_3 x_a = Fixed_S16_3_S32_16_mul(vectorP.dx, t->a);
|
|
Fixed_S16_3 y_c = Fixed_S16_3_S32_16_mul(vectorP.dy, t->c);
|
|
Fixed_S16_3 one_tx = Fixed_S16_3_S32_16_mul(FIXED_S16_3_ONE, t->tx);
|
|
|
|
Fixed_S16_3 x_b = Fixed_S16_3_S32_16_mul(vectorP.dx, t->b);
|
|
Fixed_S16_3 y_d = Fixed_S16_3_S32_16_mul(vectorP.dy, t->d);
|
|
Fixed_S16_3 one_ty = Fixed_S16_3_S32_16_mul(FIXED_S16_3_ONE, t->ty);
|
|
|
|
Fixed_S16_3 sum_x = Fixed_S16_3_add3(x_a, y_c, one_tx);
|
|
Fixed_S16_3 sum_y = Fixed_S16_3_add3(x_b, y_d, one_ty);
|
|
|
|
return GVectorPrecise(sum_x.raw_value, sum_y.raw_value);
|
|
}
|