/*
|
* Copyright 2018 Google Inc.
|
*
|
* Use of this source code is governed by a BSD-style license that can
|
* be found in the LICENSE file.
|
*
|
*/
|
|
#include "transform_stack.h"
|
|
//
|
//
|
//
|
|
#include <stdlib.h>
|
#include <math.h>
|
|
//
|
//
|
//
|
|
#undef NDEBUG
|
#include <assert.h>
|
|
//
|
//
|
//
|
|
#define TS_TRANSFORM_SUFFIX_EVAL(a) a
|
|
#define TS_TRANSFORM_SUFFIX_CONCAT(func) \
|
TS_TRANSFORM_SUFFIX_EVAL(func)##TS_TRANSFORM_SUFFIX_EVAL(TS_TRANSFORM_FLOAT_SUFFIX)
|
|
//
|
//
|
//
|
|
#define TS_TRANSFORM_SIN(x) TS_TRANSFORM_SUFFIX_CONCAT(sin)(x)
|
#define TS_TRANSFORM_COS(x) TS_TRANSFORM_SUFFIX_CONCAT(cos)(x)
|
#define TS_TRANSFORM_TAN(x) TS_TRANSFORM_SUFFIX_CONCAT(tan)(x)
|
|
//
|
//
|
//
|
#define TS_TRANSFORM_ZERO ((ts_transform_float_t)0.0)
|
#define TS_TRANSFORM_ONE ((ts_transform_float_t)1.0)
|
#define TS_TRANSFORM_RCP(f) (TS_TRANSFORM_ONE / (f))
|
|
|
//
|
//
|
//
|
|
union ts_transform_stack_3x3_u
|
{
|
ts_transform_float_t a8[8];
|
|
struct {
|
ts_transform_float_t sx;
|
ts_transform_float_t shx;
|
ts_transform_float_t tx;
|
|
ts_transform_float_t shy;
|
ts_transform_float_t sy;
|
ts_transform_float_t ty;
|
|
ts_transform_float_t w0;
|
ts_transform_float_t w1;
|
// w2 is always 1.0
|
};
|
|
struct {
|
ts_transform_float_t a;
|
ts_transform_float_t b;
|
ts_transform_float_t c;
|
|
ts_transform_float_t d;
|
ts_transform_float_t e;
|
ts_transform_float_t f;
|
|
ts_transform_float_t g;
|
ts_transform_float_t h;
|
// i is always 1.0
|
};
|
};
|
|
//
|
//
|
//
|
|
struct ts_transform_stack
|
{
|
uint32_t size;
|
uint32_t count;
|
|
ts_transform_weakref_t * weakrefs;
|
union ts_transform_stack_3x3_u * transforms;
|
};
|
|
//
|
//
|
//
|
|
static
|
void
|
ts_transform_stack_resize(struct ts_transform_stack * const ts, uint32_t const size)
|
{
|
ts->size = size;
|
ts->weakrefs = realloc(ts->weakrefs, size * sizeof(*ts->weakrefs));
|
ts->transforms = realloc(ts->transforms,size * sizeof(*ts->transforms));
|
}
|
|
static
|
void
|
ts_transform_stack_ensure(struct ts_transform_stack * const ts)
|
{
|
if (ts->count < ts->size)
|
return;
|
|
// increase by 50% and by at least 8
|
ts_transform_stack_resize(ts,ts->size + max(ts->size/2,8));
|
}
|
|
//
|
//
|
//
|
|
struct ts_transform_stack *
|
ts_transform_stack_create(uint32_t const size)
|
{
|
struct ts_transform_stack * ts = malloc(sizeof(*ts));
|
|
ts->size = size;
|
ts->count = 0;
|
|
ts->transforms = NULL;
|
ts->weakrefs = NULL;
|
|
ts_transform_stack_resize(ts,size);
|
|
return ts;
|
}
|
|
void
|
ts_transform_stack_release(struct ts_transform_stack * const ts)
|
{
|
free(ts->transforms);
|
free(ts->weakrefs);
|
|
free(ts);
|
}
|
|
//
|
//
|
//
|
|
uint32_t
|
ts_transform_stack_save(struct ts_transform_stack * const ts)
|
{
|
return ts->count;
|
}
|
|
void
|
ts_transform_stack_restore(struct ts_transform_stack * const ts,
|
uint32_t const restore)
|
{
|
ts->count = restore;
|
}
|
|
//
|
//
|
//
|
|
static
|
union ts_transform_stack_3x3_u *
|
ts_transform_stack_tos(struct ts_transform_stack * const ts)
|
{
|
return ts->transforms + ts->count - 1;
|
}
|
|
//
|
//
|
//
|
|
static
|
void
|
ts_transform_stack_3x3_u_copy(union ts_transform_stack_3x3_u * const __restrict dst,
|
union ts_transform_stack_3x3_u const * const __restrict src)
|
{
|
*dst = *src;
|
}
|
|
//
|
// C = A * B
|
//
|
// FIXME -- can save affine vs. projective flags and save a few ops
|
//
|
|
#define TS_TRANSFORM_MULTIPLY(A,B) \
|
A->sx * B->sx + A->shx * B->shy + A->tx * B->w0, \
|
A->sx * B->shx + A->shx * B->sy + A->tx * B->w1, \
|
A->sx * B->tx + A->shx * B->ty + A->tx, \
|
A->shy * B->sx + A->sy * B->shy + A->ty * B->w0, \
|
A->shy * B->shx + A->sy * B->sy + A->ty * B->w1, \
|
A->shy * B->tx + A->sy * B->ty + A->ty, \
|
A->w0 * B->sx + A->w1 * B->shy + B->w0, \
|
A->w0 * B->shx + A->w1 * B->sy + B->w1, \
|
A->w0 * B->tx + A->w1 * B->ty + TS_TRANSFORM_ONE
|
|
//
|
//
|
//
|
|
#define TS_IS_AFFINE(t) ((t->w0 == TS_TRANSFORM_ZERO) && (t->w1 == TS_TRANSFORM_ZERO))
|
|
static
|
ts_transform_type_e
|
ts_transform_stack_classify(struct ts_transform_stack * const ts)
|
{
|
union ts_transform_stack_3x3_u const * const t = ts_transform_stack_tos(ts);
|
|
if (TS_IS_AFFINE(t))
|
return TS_TRANSFORM_TYPE_AFFINE;
|
else
|
return TS_TRANSFORM_TYPE_PROJECTIVE;
|
}
|
|
//
|
//
|
//
|
|
ts_transform_float_t *
|
ts_transform_stack_top_transform(struct ts_transform_stack * const ts)
|
{
|
return ts_transform_stack_tos(ts)->a8;
|
}
|
|
ts_transform_weakref_t *
|
ts_transform_stack_top_weakref(struct ts_transform_stack * const ts)
|
{
|
return ts->weakrefs + ts->count - 1;
|
}
|
|
//
|
//
|
//
|
|
void
|
ts_transform_stack_dup(struct ts_transform_stack * const ts)
|
{
|
ts_transform_stack_ensure(ts);
|
|
union ts_transform_stack_3x3_u * const tos = ts_transform_stack_tos(ts);
|
|
ts_transform_stack_3x3_u_copy(tos+1,tos);
|
|
ts->weakrefs[ts->count] = ts->weakrefs[ts->count-1];
|
|
ts->count += 1;
|
}
|
|
void
|
ts_transform_stack_drop(struct ts_transform_stack * const ts)
|
{
|
assert(ts->count >= 1);
|
|
ts->count -= 1;
|
}
|
|
//
|
//
|
//
|
|
static
|
void
|
ts_transform_stack_swap_drop(struct ts_transform_stack * const ts)
|
{
|
assert(ts->count >= 2);
|
|
union ts_transform_stack_3x3_u * const tos = ts_transform_stack_tos(ts);
|
|
ts_transform_stack_3x3_u_copy(tos-1,tos);
|
|
ts->weakrefs[ts->count-2] = ts->weakrefs[ts->count-1];
|
|
ts->count -= 1;
|
}
|
|
//
|
//
|
//
|
|
static
|
void
|
ts_transform_stack_store_matrix_8(struct ts_transform_stack * const ts,
|
uint32_t const idx,
|
ts_transform_float_t const sx,
|
ts_transform_float_t const shx,
|
ts_transform_float_t const tx,
|
ts_transform_float_t const shy,
|
ts_transform_float_t const sy,
|
ts_transform_float_t const ty,
|
ts_transform_float_t const w0,
|
ts_transform_float_t const w1)
|
{
|
union ts_transform_stack_3x3_u * t = ts->transforms + idx;
|
|
t->sx = sx;
|
t->shx = shx;
|
t->tx = tx;
|
|
t->shy = shy;
|
t->sy = sy;
|
t->ty = ty;
|
|
t->w0 = w0;
|
t->w1 = w1;
|
|
ts->weakrefs[idx] = TS_TRANSFORM_WEAKREF_INVALID;
|
}
|
|
//
|
//
|
//
|
|
static
|
void
|
ts_transform_stack_store_matrix(struct ts_transform_stack * const ts,
|
uint32_t const idx,
|
ts_transform_float_t const sx,
|
ts_transform_float_t const shx,
|
ts_transform_float_t const tx,
|
ts_transform_float_t const shy,
|
ts_transform_float_t const sy,
|
ts_transform_float_t const ty,
|
ts_transform_float_t const w0,
|
ts_transform_float_t const w1,
|
ts_transform_float_t const w2)
|
{
|
if (w2 == TS_TRANSFORM_ONE)
|
{
|
ts_transform_stack_store_matrix_8(ts,idx,
|
sx, shx,tx,
|
shy,sy, ty,
|
w0, w1);
|
}
|
else
|
{
|
// normalize
|
ts_transform_float_t d = TS_TRANSFORM_RCP(w2);
|
|
ts_transform_stack_store_matrix_8(ts,idx,
|
sx * d, shx * d, tx * d,
|
shy * d, sy * d, ty * d,
|
w0 * d, w1 * d);
|
}
|
}
|
|
//
|
//
|
//
|
|
static
|
void
|
ts_transform_stack_push_matrix_8(struct ts_transform_stack * const ts,
|
ts_transform_float_t const sx,
|
ts_transform_float_t const shx,
|
ts_transform_float_t const tx,
|
ts_transform_float_t const shy,
|
ts_transform_float_t const sy,
|
ts_transform_float_t const ty,
|
ts_transform_float_t const w0,
|
ts_transform_float_t const w1)
|
{
|
ts_transform_stack_ensure(ts);
|
|
ts_transform_stack_store_matrix_8(ts,ts->count++,
|
sx, shx,tx,
|
shy,sy, ty,
|
w0, w1);
|
}
|
|
//
|
//
|
//
|
|
void
|
ts_transform_stack_push_matrix(struct ts_transform_stack * const ts,
|
ts_transform_float_t const sx,
|
ts_transform_float_t const shx,
|
ts_transform_float_t const tx,
|
ts_transform_float_t const shy,
|
ts_transform_float_t const sy,
|
ts_transform_float_t const ty,
|
ts_transform_float_t const w0,
|
ts_transform_float_t const w1,
|
ts_transform_float_t const w2)
|
{
|
if (w2 == TS_TRANSFORM_ONE)
|
{
|
ts_transform_stack_push_matrix_8(ts,
|
sx, shx,tx,
|
shy,sy, ty,
|
w0, w1);
|
}
|
else
|
{
|
// normalize
|
ts_transform_float_t d = TS_TRANSFORM_RCP(w2);
|
|
ts_transform_stack_push_matrix_8(ts,
|
sx * d, shx * d, tx * d,
|
shy * d, sy * d, ty * d,
|
w0 * d, w1 * d);
|
}
|
}
|
|
//
|
//
|
//
|
|
void
|
ts_transform_stack_push_identity(struct ts_transform_stack * const ts)
|
{
|
ts_transform_stack_push_matrix_8(ts,
|
1.0, 0.0, 0.0,
|
0.0, 1.0, 0.0,
|
0.0, 0.0);
|
}
|
|
void
|
ts_transform_stack_push_affine(struct ts_transform_stack * const ts,
|
ts_transform_float_t const sx,
|
ts_transform_float_t const shx,
|
ts_transform_float_t const tx,
|
ts_transform_float_t const shy,
|
ts_transform_float_t const sy,
|
ts_transform_float_t const ty)
|
{
|
ts_transform_stack_push_matrix_8(ts,
|
sx, shx, tx,
|
shy, sy, ty,
|
0.0, 0.0);
|
}
|
|
void
|
ts_transform_stack_push_translate(struct ts_transform_stack * const ts,
|
ts_transform_float_t const tx,
|
ts_transform_float_t const ty)
|
{
|
ts_transform_stack_push_matrix_8(ts,
|
1.0, 0.0, tx,
|
0.0, 1.0, ty,
|
0.0, 0.0);
|
}
|
|
void
|
ts_transform_stack_push_scale(struct ts_transform_stack * const ts,
|
ts_transform_float_t const sx,
|
ts_transform_float_t const sy)
|
{
|
ts_transform_stack_push_matrix_8(ts,
|
sx, 0.0, 0.0,
|
0.0, sy, 0.0,
|
0.0, 0.0);
|
}
|
|
void
|
ts_transform_stack_push_shear(struct ts_transform_stack * const ts,
|
ts_transform_float_t const shx,
|
ts_transform_float_t const shy)
|
{
|
ts_transform_stack_push_matrix_8(ts,
|
1.0, shx, 0.0,
|
shy, 1.0, 0.0,
|
0.0, 0.0);
|
}
|
|
void
|
ts_transform_stack_push_skew_x(struct ts_transform_stack * const ts,
|
ts_transform_float_t const theta)
|
{
|
ts_transform_float_t const tan_theta = TS_TRANSFORM_TAN(theta); // replace with tanpi if available
|
|
ts_transform_stack_push_matrix_8(ts,
|
1.0, tan_theta,0.0,
|
0.0, 1.0, 0.0,
|
0.0, 0.0);
|
}
|
|
void
|
ts_transform_stack_push_skew_y(struct ts_transform_stack * const ts,
|
ts_transform_float_t const theta)
|
{
|
ts_transform_float_t const tan_theta = TS_TRANSFORM_TAN(theta); // replace with tanpi if available
|
|
ts_transform_stack_push_matrix_8(ts,
|
1.0, 0.0, 0.0,
|
tan_theta, 1.0, 0.0,
|
0.0, 0.0);
|
}
|
|
void
|
ts_transform_stack_push_rotate(struct ts_transform_stack * const ts,
|
ts_transform_float_t const theta)
|
{
|
ts_transform_float_t const cos_theta = TS_TRANSFORM_COS(theta); // replace with cospi if available
|
ts_transform_float_t const sin_theta = TS_TRANSFORM_SIN(theta); // replace with sinpi if available
|
|
ts_transform_stack_push_matrix_8(ts,
|
cos_theta,-sin_theta, 0.0,
|
sin_theta, cos_theta, 0.0,
|
0.0, 0.0);
|
}
|
|
void
|
ts_transform_stack_push_rotate_xy2(struct ts_transform_stack * const ts,
|
ts_transform_float_t const theta,
|
ts_transform_float_t const cx,
|
ts_transform_float_t const cy,
|
ts_transform_float_t const tx,
|
ts_transform_float_t const ty)
|
{
|
ts_transform_float_t const cos_theta = TS_TRANSFORM_COS(theta); // replace with cospi if available
|
ts_transform_float_t const sin_theta = TS_TRANSFORM_SIN(theta); // replace with sinpi if available
|
|
ts_transform_stack_push_matrix_8(ts,
|
cos_theta,-sin_theta, tx - (cx * cos_theta) + (cy * sin_theta),
|
sin_theta, cos_theta, ty - (cx * sin_theta) - (cy * cos_theta),
|
0.0, 0.0);
|
}
|
|
void
|
ts_transform_stack_push_rotate_xy(struct ts_transform_stack * const ts,
|
ts_transform_float_t const theta,
|
ts_transform_float_t const cx,
|
ts_transform_float_t const cy)
|
{
|
ts_transform_stack_push_rotate_xy2(ts,theta,cx,cy,cx,cy);
|
}
|
|
void
|
ts_transform_stack_push_rotate_scale_xy(struct ts_transform_stack * const ts,
|
ts_transform_float_t const theta,
|
ts_transform_float_t const sx,
|
ts_transform_float_t const sy,
|
ts_transform_float_t const cx,
|
ts_transform_float_t const cy)
|
{
|
ts_transform_float_t const cos_theta = TS_TRANSFORM_COS(theta); // replace with cospi if available
|
ts_transform_float_t const sin_theta = TS_TRANSFORM_SIN(theta); // replace with sinpi if available
|
|
ts_transform_stack_push_matrix_8(ts,
|
sx*cos_theta,-sx*sin_theta, cx - cx*sx*cos_theta + cy*sy*sin_theta,
|
sy*sin_theta, sy*cos_theta, cy - cy*sy*cos_theta - cx*sx*sin_theta,
|
0.0, 0.0);
|
}
|
|
//
|
// See: "Fundamentals of Texture Mapping and Image Warping" by Paul S. Heckbert (1989)
|
//
|
|
#define DET(a,b,c,d) (a * d - b * c)
|
|
#define X(v,i) v[i*2]
|
#define Y(v,i) v[i*2+1]
|
|
//
|
//
|
//
|
|
ts_transform_type_e
|
ts_transform_stack_adjoint(struct ts_transform_stack * const ts)
|
{
|
union ts_transform_stack_3x3_u * const t = ts_transform_stack_tos(ts);
|
|
#if 0
|
// save for determinant
|
ts_transform_float_t const a = t->a;
|
ts_transform_float_t const b = t->b;
|
ts_transform_float_t const c = t->c;
|
#endif
|
|
ts_transform_stack_store_matrix(ts,ts->count-1,
|
|
+DET(t->e, t->f, t->h, TS_TRANSFORM_ONE),
|
-DET(t->b, t->c, t->h, TS_TRANSFORM_ONE),
|
+DET(t->b, t->c, t->e, t->f),
|
|
-DET(t->d, t->f, t->g, TS_TRANSFORM_ONE),
|
+DET(t->a, t->c, t->g, TS_TRANSFORM_ONE),
|
-DET(t->a, t->c, t->d, t->f),
|
|
+DET(t->d, t->e, t->g, t->h),
|
-DET(t->a, t->b, t->g, t->h),
|
+DET(t->a, t->b, t->d, t->e));
|
|
#if 0
|
// determinant of t
|
ts_transform_float_t const det = a * t->a + b * t->d + c * t->g;
|
#endif
|
|
return ts_transform_stack_classify(ts);
|
}
|
|
//
|
//
|
//
|
|
ts_transform_type_e
|
ts_transform_stack_push_unit_to_quad(struct ts_transform_stack * const ts,
|
ts_transform_float_t const quad[8])
|
{
|
ts_transform_float_t const x0 = X(quad,0);
|
ts_transform_float_t const y0 = Y(quad,0);
|
|
ts_transform_float_t const x1 = X(quad,1);
|
ts_transform_float_t const y1 = Y(quad,1);
|
|
ts_transform_float_t const x2 = X(quad,2);
|
ts_transform_float_t const y2 = Y(quad,2);
|
|
ts_transform_float_t const x3 = X(quad,3);
|
ts_transform_float_t const y3 = Y(quad,3);
|
|
ts_transform_float_t sx = x1 - x0;
|
ts_transform_float_t shy = y1 - y0;
|
|
ts_transform_float_t const dx2 = x3 - x2;
|
ts_transform_float_t const dy2 = y3 - y2;
|
|
ts_transform_float_t const dx3 = -sx - dx2;
|
ts_transform_float_t const dy3 = -shy - dy2;
|
|
// if both zero then quad_dst is a parallelogram and affine
|
if ((dx3 == TS_TRANSFORM_ZERO) && (dy3 == TS_TRANSFORM_ZERO))
|
{
|
ts_transform_float_t const shx = x2 - x1;
|
ts_transform_float_t const sy = y2 - y1;
|
|
ts_transform_stack_push_matrix_8(ts,
|
sx, shx, x0,
|
shy, sy, y0,
|
0.0, 0.0);
|
|
return TS_TRANSFORM_TYPE_AFFINE;
|
}
|
else
|
{
|
ts_transform_float_t const dx1 = x1 - x2;
|
ts_transform_float_t const dy1 = y1 - y2;
|
|
ts_transform_float_t const wx_den = dx1 * dy2 - dx2 * dy1;
|
|
if (wx_den == TS_TRANSFORM_ZERO)
|
return TS_TRANSFORM_TYPE_INVALID;
|
|
ts_transform_float_t const w0_num = dx3 * dy2 - dx2 * dy3;
|
ts_transform_float_t const w1_num = dx1 * dy3 - dx3 * dy1;
|
|
ts_transform_float_t const w0 = w0_num / wx_den;
|
ts_transform_float_t const w1 = w1_num / wx_den;
|
|
sx += w0 * x1;
|
ts_transform_float_t const shx = x3 - x0 + w1 * x3;
|
|
shy += w0 * y1;
|
ts_transform_float_t const sy = y3 - y0 + w1 * y3;
|
|
ts_transform_stack_push_matrix_8(ts,
|
sx, shx, x0,
|
shy, sy, y0,
|
w0, w1);
|
|
return TS_TRANSFORM_TYPE_PROJECTIVE;
|
}
|
}
|
|
//
|
//
|
//
|
|
ts_transform_type_e
|
ts_transform_stack_push_quad_to_unit(struct ts_transform_stack * const ts,
|
float const quad[8])
|
{
|
if (ts_transform_stack_push_unit_to_quad(ts,quad) == TS_TRANSFORM_TYPE_INVALID)
|
return TS_TRANSFORM_TYPE_INVALID;
|
|
return ts_transform_stack_adjoint(ts);
|
}
|
|
//
|
//
|
//
|
|
ts_transform_type_e
|
ts_transform_stack_push_quad_to_quad(struct ts_transform_stack * const ts,
|
ts_transform_float_t const quad_src[8],
|
ts_transform_float_t const quad_dst[8])
|
{
|
if (ts_transform_stack_push_unit_to_quad(ts,quad_dst) == TS_TRANSFORM_TYPE_INVALID)
|
return TS_TRANSFORM_TYPE_INVALID;
|
|
if (ts_transform_stack_push_quad_to_unit(ts,quad_src) == TS_TRANSFORM_TYPE_INVALID)
|
return TS_TRANSFORM_TYPE_INVALID;
|
|
ts_transform_stack_multiply(ts);
|
|
return ts_transform_stack_classify(ts);
|
}
|
|
//
|
//
|
//
|
|
ts_transform_type_e
|
ts_transform_stack_push_rect_to_quad(struct ts_transform_stack * const ts,
|
ts_transform_float_t const x0,
|
ts_transform_float_t const y0,
|
ts_transform_float_t const x1,
|
ts_transform_float_t const y1,
|
ts_transform_float_t const quad_dst[8])
|
{
|
if (ts_transform_stack_push_unit_to_quad(ts,quad_dst) == TS_TRANSFORM_TYPE_INVALID)
|
return TS_TRANSFORM_TYPE_INVALID;
|
|
ts_transform_stack_push_matrix_8(ts,
|
TS_TRANSFORM_RCP(x1-x0),
|
0.0,
|
-x0,
|
0.0,
|
TS_TRANSFORM_RCP(y1-y0),
|
-y0,
|
0.0,
|
0.0);
|
|
ts_transform_stack_multiply(ts);
|
|
return ts_transform_stack_classify(ts);
|
}
|
|
//
|
// The second matrix on the stack (TOS[-1]) is post-multiplied by the
|
// top matrix on the stack (TOS[0]).
|
//
|
// The result replaces TOS[0] and TOS[-1] is unmodified.
|
//
|
// The stack effect of concat is:
|
//
|
// | B | | A*B |
|
// | A | | A |
|
// | . | => | . |
|
// | . | | . |
|
// | . | | . |
|
//
|
void
|
ts_transform_stack_concat(struct ts_transform_stack * const ts)
|
{
|
assert(ts->count >= 2);
|
|
// get A and B
|
union ts_transform_stack_3x3_u const * const B = ts_transform_stack_tos(ts);
|
union ts_transform_stack_3x3_u const * const A = B - 1;
|
|
ts_transform_stack_store_matrix(ts,ts->count-1,TS_TRANSFORM_MULTIPLY(A,B));
|
}
|
|
//
|
// The second matrix on the stack (TOS[-1]) is post-multiplied by the
|
// top matrix on the stack (TOS[0]).
|
//
|
// The result replaces both matrices.
|
//
|
// The stack effect of multiply is:
|
//
|
// | B | | A*B |
|
// | A | | . |
|
// | . | => | . |
|
// | . | | . |
|
// | . | | . |
|
//
|
void
|
ts_transform_stack_multiply(struct ts_transform_stack * const ts)
|
{
|
assert(ts->count >= 2);
|
|
// get A and B
|
union ts_transform_stack_3x3_u const * const B = ts_transform_stack_tos(ts);
|
union ts_transform_stack_3x3_u const * const A = B - 1;
|
|
ts_transform_stack_store_matrix(ts,ts->count-- - 2,TS_TRANSFORM_MULTIPLY(A,B));
|
}
|
|
//
|
//
|
//
|
|
void
|
ts_transform_stack_transform_xy(struct ts_transform_stack * const ts,
|
ts_transform_float_t const x,
|
ts_transform_float_t const y,
|
ts_transform_float_t * const xp,
|
ts_transform_float_t * const yp)
|
{
|
union ts_transform_stack_3x3_u const * const t = ts_transform_stack_tos(ts);
|
|
*xp = x * t->sx + y * t->shx + t->tx;
|
*yp = x * t->shy + y * t->sy + t->ty;
|
|
if (!TS_IS_AFFINE(t))
|
{
|
ts_transform_float_t const d = TS_TRANSFORM_RCP(x * t->w0 + y * t->w1 + TS_TRANSFORM_ONE);
|
|
*xp *= d;
|
*yp *= d;
|
}
|
}
|
|
//
|
// test it!
|
//
|
|
#ifdef TS_DEBUG
|
|
#include <stdio.h>
|
|
#define TS_DEBUG_SCALE 32.0
|
|
//
|
//
|
//
|
|
void
|
ts_transform_stack_tos_debug(struct ts_transform_stack * const ts)
|
{
|
union ts_transform_stack_3x3_u const * const t = ts_transform_stack_tos(ts);
|
|
printf("{ { %13.5f, %13.5f, %13.5f },\n"
|
" { %13.5f, %13.5f, %13.5f },\n"
|
" { %13.5f, %13.5f, %13.5f } }\n",
|
t->a8[0],
|
t->a8[1],
|
t->a8[2],
|
t->a8[3],
|
t->a8[4],
|
t->a8[5],
|
t->a8[6],
|
t->a8[7],
|
TS_TRANSFORM_ONE);
|
}
|
|
//
|
//
|
//
|
|
void
|
ts_debug(struct ts_transform_stack * const ts,
|
ts_transform_float_t const quad[8])
|
{
|
ts_transform_stack_tos_debug(ts);
|
|
for (int ii=0; ii<8; ii+=2)
|
{
|
ts_transform_float_t xp,yp;
|
|
ts_transform_stack_transform_xy(ts,
|
quad[ii],quad[ii+1],
|
&xp,&yp);
|
|
printf("( %13.2f, %13.2f ) \t-> ( %13.2f, %13.2f )\n",
|
xp,yp,xp/TS_DEBUG_SCALE,yp/TS_DEBUG_SCALE);
|
}
|
}
|
|
//
|
//
|
//
|
|
int
|
main(int argc, char * argv[])
|
{
|
struct ts_transform_stack * const ts = ts_transform_stack_create(32);
|
|
ts_transform_float_t const w = 1000;
|
ts_transform_float_t const h = 1000;
|
|
#if 1
|
ts_transform_stack_push_scale(ts,TS_DEBUG_SCALE,TS_DEBUG_SCALE);
|
|
// OpenGL'ism
|
ts_transform_stack_push_affine(ts,
|
1.0f, 0.0f,0.0f,
|
0.0f,-1.0f,h);
|
// multiply
|
ts_transform_stack_concat(ts);
|
#else
|
ts_transform_stack_push_identity(ts);
|
#endif
|
|
uint32_t const restore = ts_transform_stack_save(ts);
|
|
//
|
//
|
//
|
ts_transform_float_t const quad_src[8] = { 0.0f,0.0f,
|
w, 0.0f,
|
w, h,
|
0.0f,h };
|
|
ts_transform_float_t const quad_dst[8] = { 300.0f, 0.0f,
|
w-300.0f, 0.0f,
|
w, h,
|
0.0f, h };
|
|
ts_transform_float_t const quad_tst[8] = { 50, 50,
|
1550, 50,
|
1550, 1550,
|
50, 1550 };
|
//
|
// RECT TO QUAD
|
//
|
printf("type = %d\n",
|
ts_transform_stack_push_rect_to_quad(ts,
|
0.0, 0.0,
|
w, h,
|
quad_dst));
|
ts_transform_stack_concat(ts);
|
|
ts_debug(ts,quad_src);
|
|
//
|
// QUAD TO QUAD
|
//
|
ts_transform_stack_restore(ts,restore);
|
|
printf("type = %d\n",
|
ts_transform_stack_push_quad_to_quad(ts,
|
quad_src,
|
quad_dst));
|
ts_transform_stack_concat(ts);
|
|
ts_debug(ts,quad_src);
|
|
//
|
// DIRECT
|
//
|
ts_transform_stack_restore(ts,restore);
|
|
ts_transform_stack_push_matrix(ts,
|
0.87004626f, -0.35519487f, 72.14745f,
|
0.0f, 0.2600208f, 86.16314f,
|
0.0f, -0.0029599573f, 1.0f);
|
|
ts_transform_stack_concat(ts);
|
|
ts_transform_float_t const quad_foo[8] = { -10, 10,
|
130, 10,
|
130, 110,
|
-10, 110 };
|
|
ts_debug(ts,quad_foo);
|
|
return EXIT_SUCCESS;
|
}
|
|
#endif
|
|
//
|
//
|
//
|