efl/src/lib/evas/canvas/efl_gfx_mapping.c

1020 lines
29 KiB
C

#include "evas_map.h"
// FIXME: cur vs. prev is not handled (may be an issue?)
// FIXME: some render artifacts appear when this API is used (green pixels)
#define EINA_INLIST_REMOVE(l,i) do { l = (__typeof__(l)) eina_inlist_remove(EINA_INLIST_GET(l), EINA_INLIST_GET(i)); } while (0)
#define EINA_INLIST_APPEND(l,i) do { l = (__typeof__(l)) eina_inlist_append(EINA_INLIST_GET(l), EINA_INLIST_GET(i)); } while (0)
#define EINA_INLIST_PREPEND(l,i) do { l = (__typeof__(l)) eina_inlist_prepend(EINA_INLIST_GET(l), EINA_INLIST_GET(i)); } while (0)
#define EINA_INLIST_NEXT(l) (typeof(l)) EINA_INLIST_CONTAINER_GET(EINA_INLIST_GET(l)->next, typeof(*l))
#define MY_CLASS EFL_GFX_MAPPING_MIXIN
typedef struct _Gfx_Map Gfx_Map;
typedef struct _Gfx_Map_Op Gfx_Map_Op;
typedef struct _Gfx_Map_Pivot Gfx_Map_Pivot;
typedef struct _Efl_Gfx_Mapping_Data Efl_Gfx_Mapping_Data;
typedef struct _Gfx_Map_Point Gfx_Map_Point;
typedef enum _Gfx_Map_Op_Type Gfx_Map_Op_Type;
enum _Gfx_Map_Op_Type {
GFX_MAPPING_RAW_COORD,
GFX_MAPPING_COLOR,
GFX_MAPPING_ROTATE_2D,
GFX_MAPPING_ROTATE_3D,
GFX_MAPPING_ROTATE_QUAT,
GFX_MAPPING_ZOOM,
GFX_MAPPING_TRANSLATE,
GFX_MAPPING_LIGHTING_3D,
GFX_MAPPING_PERSPECTIVE_3D,
};
struct _Gfx_Map_Op {
EINA_INLIST;
Gfx_Map_Op_Type op;
union {
struct {
int idx;
double x, y, z;
} raw_coord;
struct {
int idx;
uint8_t r, g, b, a;
} color;
struct {
double degrees;
} rotate_2d;
struct {
double dx, dy, dz;
} rotate_3d;
struct {
double qx, qy, qz, qw;
} rotate_quat;
struct {
double zx, zy;
} zoom;
struct {
double dx, dy, dz;
} translate;
struct {
uint8_t lr, lg, lb, ar, ag, ab;
} lighting_3d;
struct {
double z0, foc;
} perspective_3d;
};
struct {
Gfx_Map_Pivot *pivot;
double cx, cy, cz;
Eina_Bool is_absolute;
Eina_Bool is_self;
} pivot;
};
struct _Gfx_Map_Pivot
{
EINA_INLIST;
Evas_Object_Protected_Data *map_obj;
Eo *eo_obj; // strong or weak ref?
Eina_Rect geometry;
Eina_Bool event_cbs;
Eina_Bool is_evas;
Eina_Bool is_canvas;
Eina_Bool changed;
};
struct _Gfx_Map_Point {
double u, v;
};
struct _Gfx_Map {
Gfx_Map_Op *ops;
Gfx_Map_Point *points;
Gfx_Map_Pivot *pivots;
Evas_Map *map;
Gfx_Map_Op *last_calc_op;
int imw, imh;
int count;
// FIXME: Those need a quality vs. performance setting instead
Eina_Bool alpha;
Eina_Bool smooth;
Eina_Bool event_cbs;
};
struct _Efl_Gfx_Mapping_Data {
const Gfx_Map *cow;
};
// ----------------------------------------------------------------------------
static Eo *gfx_mapping_absolute = NULL;
static Eina_Cow *gfx_mapping_cow = NULL;
static const Gfx_Map gfx_mapping_cow_default = {
NULL,
NULL,
NULL,
NULL,
NULL,
0, 0,
4,
EINA_TRUE,
EINA_TRUE,
EINA_FALSE
};
#define MAPCOW_BEGIN(_pd) eina_cow_write(gfx_mapping_cow, (const Eina_Cow_Data**)&(_pd->cow))
#define MAPCOW_END(_mapcow, _pd) eina_cow_done(gfx_mapping_cow, (const Eina_Cow_Data**)&(_pd->cow), _mapcow, EINA_FALSE)
#define MAPCOW_WRITE(pd, name, value) do { \
if (pd->cow->name != (value)) { \
Gfx_Map *_cow = MAPCOW_BEGIN(pd); \
_cow->name = (value); \
MAPCOW_END(_cow, pd); \
}} while (0)
#define PIVOT_REF(_pivot) (_pivot ? efl_xref((Eo *) _pivot, eo_obj) : NULL)
#define PIVOT_UNREF(_pivot) (_pivot ? efl_xunref(_pivot, eo_obj) : NULL)
static inline void _map_clean(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd);
// ----------------------------------------------------------------------------
void
_efl_gfx_mapping_init(void)
{
gfx_mapping_cow = eina_cow_add("Efl.Gfx.Mapping", sizeof(Gfx_Map), 8,
&gfx_mapping_cow_default, EINA_FALSE);
}
void
_efl_gfx_mapping_shutdown(void)
{
eina_cow_del(gfx_mapping_cow);
gfx_mapping_cow = NULL;
efl_unref(gfx_mapping_absolute);
gfx_mapping_absolute = NULL;
}
// ----------------------------------------------------------------------------
EOLIAN static Efl_Object *
_efl_gfx_mapping_efl_object_constructor(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd)
{
eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
pd->cow = eina_cow_alloc(gfx_mapping_cow);
return eo_obj;
}
EOLIAN static void
_efl_gfx_mapping_efl_object_destructor(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd)
{
if (pd->cow)
{
_map_clean(eo_obj, pd);
eina_cow_free(gfx_mapping_cow, (const Eina_Cow_Data **) &pd->cow);
}
efl_destructor(efl_super(eo_obj, MY_CLASS));
}
// ----------------------------------------------------------------------------
static void
_geometry_changed_cb(void *data, const Efl_Event *ev EINA_UNUSED)
{
Evas_Object_Protected_Data *obj = data;
Efl_Gfx_Mapping_Data *pd = efl_data_scope_get(obj->object, MY_CLASS);
MAPCOW_WRITE(pd, last_calc_op, NULL);
obj->gfx_mapping_update = EINA_TRUE;
}
EFL_CALLBACKS_ARRAY_DEFINE(_geometry_changes,
{ EFL_GFX_ENTITY_EVENT_POSITION_CHANGED, _geometry_changed_cb },
{ EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _geometry_changed_cb });
static void
_pivot_changed_cb(void *data, const Efl_Event *ev EINA_UNUSED)
{
Gfx_Map_Pivot *pivot = data;
Evas_Object_Protected_Data *obj = pivot->map_obj;
obj->gfx_mapping_update = EINA_TRUE;
pivot->changed = EINA_TRUE;
}
EFL_CALLBACKS_ARRAY_DEFINE(_pivot_changes,
{ EFL_GFX_ENTITY_EVENT_POSITION_CHANGED, _pivot_changed_cb },
{ EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _pivot_changed_cb });
static inline void
_map_dirty(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd, Eina_Bool reset)
{
Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
Gfx_Map_Pivot *pivot;
obj->gfx_mapping_has = EINA_TRUE;
obj->gfx_mapping_update |= !reset;
obj->changed_map = EINA_TRUE;
evas_object_change(eo_obj, obj);
if (reset)
{
_evas_map_reset(pd->cow->map);
return;
}
// FIXME: Only add if there is a self-pivot (relative coordinates)
if (!pd->cow->event_cbs)
{
MAPCOW_WRITE(pd, event_cbs, EINA_TRUE);
efl_event_callback_array_add(eo_obj, _geometry_changes(), obj);
}
EINA_INLIST_FOREACH(pd->cow->pivots, pivot)
{
if (pivot->event_cbs) continue;
pivot->event_cbs = EINA_TRUE;
efl_event_callback_array_add(pivot->eo_obj, _pivot_changes(), pivot);
}
}
static Evas_Map *
_map_calc(const Eo *eo_obj, Evas_Object_Protected_Data *obj, Efl_Gfx_Mapping_Data *pd)
{
Gfx_Map_Op *op, *first_op = pd->cow->ops, *last_op;
Gfx_Map_Pivot *pivot;
Gfx_Map *mcow;
Evas_Map *m;
int imw, imh;
int count;
Eina_Bool map_alloc = EINA_FALSE;
if (pd->cow == &gfx_mapping_cow_default)
return NULL;
m = pd->cow->map;
if (!obj->gfx_mapping_update) return m;
last_op = pd->cow->last_calc_op;
count = pd->cow->count < 4 ? 4 : pd->cow->count;
EINA_INLIST_FOREACH(pd->cow->pivots, pivot)
{
if (!pivot->changed) continue;
last_op = NULL;
pivot->changed = EINA_FALSE;
if (!pivot->is_canvas)
{
pivot->geometry = efl_gfx_entity_geometry_get(pivot->eo_obj);
}
else
{
// Note: pivot can not be an Evas when using pure EO API
if (pivot->is_evas)
evas_output_size_get(pivot->eo_obj, &pivot->geometry.w, &pivot->geometry.h);
else
pivot->geometry.size = efl_gfx_entity_size_get(pivot->eo_obj);
pivot->geometry.x = 0;
pivot->geometry.y = 0;
}
}
if (!pd->cow->points)
{
Gfx_Map_Point *ps = calloc(1, count * sizeof(Gfx_Map_Point));
if (!ps) return m;
ps[0].u = 0.0; ps[0].v = 0.0;
ps[1].u = 1.0; ps[1].v = 0.0;
ps[2].u = 1.0; ps[2].v = 1.0;
ps[3].u = 0.0; ps[3].v = 1.0;
MAPCOW_WRITE(pd, points, ps);
}
if (m && last_op)
{
first_op = EINA_INLIST_NEXT(last_op);
imw = pd->cow->imw;
imh = pd->cow->imh;
}
else
{
if (!m)
{
m = evas_map_new(count);
if (!m) return NULL;
map_alloc = EINA_TRUE;
}
else _evas_map_reset(m);
m->alpha = pd->cow->alpha;
m->smooth = pd->cow->smooth;
m->move_sync.enabled = EINA_FALSE;
_evas_map_util_points_populate(m,
obj->cur->geometry.x, obj->cur->geometry.y,
obj->cur->geometry.w, obj->cur->geometry.h,
0);
if (obj->is_image_object)
{
// Image is a special case in terms of geometry
Eina_Size2D sz;
sz = efl_gfx_view_size_get(eo_obj);
imw = sz.w;
imh = sz.h;
}
else
{
imw = obj->cur->geometry.w;
imh = obj->cur->geometry.h;
}
last_op = NULL;
first_op = pd->cow->ops;
}
for (int k = 0; k < count; k++)
{
Evas_Map_Point *p = &(m->points[k]);
p->u = pd->cow->points[k].u * imw;
p->v = pd->cow->points[k].v * imh;
}
EINA_INLIST_FOREACH(first_op, op)
{
int k, kmin = 0, kmax = count - 1;
double cx, cy, cz;
Evas_Map_Point *p;
if (!op->pivot.is_absolute)
{
int px = 0, py = 0, pw = 1, ph = 1;
if (op->pivot.is_self)
{
px = obj->cur->geometry.x;
py = obj->cur->geometry.y;
pw = obj->cur->geometry.w;
ph = obj->cur->geometry.h;
}
else
{
if (!op->pivot.pivot)
{
EINA_SAFETY_ERROR("safety check failed: op->pivot.pivot == NULL");
if (map_alloc) evas_map_free(m);
return NULL;
}
pivot = op->pivot.pivot;
px = pivot->geometry.x;
py = pivot->geometry.y;
pw = pivot->geometry.w;
ph = pivot->geometry.h;
}
cx = (double) px + (double) pw * op->pivot.cx;
cy = (double) py + (double) ph * op->pivot.cy;
cz = op->pivot.cz;
}
else
{
cx = op->pivot.cx;
cy = op->pivot.cy;
cz = op->pivot.cz;
}
switch (op->op)
{
case GFX_MAPPING_RAW_COORD:
if (op->raw_coord.idx != -1)
kmin = kmax = op->raw_coord.idx;
for (k = kmin; k <= kmax; k++)
{
p = &(m->points[k]);
p->px = p->x = op->raw_coord.x;
p->py = p->y = op->raw_coord.y;
p->z = op->raw_coord.z;
}
break;
case GFX_MAPPING_COLOR:
if (op->raw_coord.idx != -1)
kmin = kmax = op->raw_coord.idx;
for (k = kmin; k <= kmax; k++)
{
p = &(m->points[k]);
p->r = op->color.r;
p->g = op->color.g;
p->b = op->color.b;
p->a = op->color.a;
}
break;
case GFX_MAPPING_ROTATE_2D:
_map_util_rotate(m, op->rotate_2d.degrees, cx, cy);
break;
case GFX_MAPPING_ROTATE_3D:
_map_util_3d_rotate(m, op->rotate_3d.dx, op->rotate_3d.dy,
op->rotate_3d.dz, cx, cy, cz);
break;
case GFX_MAPPING_ROTATE_QUAT:
_map_util_quat_rotate(m, op->rotate_quat.qx, op->rotate_quat.qy,
op->rotate_quat.qz, op->rotate_quat.qw,
cx, cy, cz);
break;
case GFX_MAPPING_ZOOM:
_map_util_zoom(m, op->zoom.zx, op->zoom.zy, cx, cy);
break;
case GFX_MAPPING_TRANSLATE:
_map_util_translate(m, op->translate.dx, op->translate.dy,
op->translate.dz);
break;
case GFX_MAPPING_LIGHTING_3D:
_map_util_3d_lighting(m, cx, cy, cz, op->lighting_3d.lr,
op->lighting_3d.lg, op->lighting_3d.lb,
op->lighting_3d.ar, op->lighting_3d.ag,
op->lighting_3d.ab);
break;
case GFX_MAPPING_PERSPECTIVE_3D:
_map_util_3d_perspective(m, cx, cy, op->perspective_3d.z0,
op->perspective_3d.foc);
break;
}
last_op = op;
}
mcow = MAPCOW_BEGIN(pd);
mcow->map = m;
mcow->last_calc_op = last_op;
mcow->imw = imw;
mcow->imh = imh;
MAPCOW_END(mcow, pd);
obj->gfx_mapping_update = EINA_FALSE;
return m;
}
void
_efl_gfx_mapping_update(Eo *eo_obj)
{
Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
Efl_Gfx_Mapping_Data *pd = efl_data_scope_get(eo_obj, MY_CLASS);
Evas_Map *m;
m = _map_calc(eo_obj, obj, pd);
evas_object_map_set(eo_obj, m);
_evas_object_map_enable_set(eo_obj, obj, m != NULL);
obj->gfx_mapping_has = (m != NULL);
}
static inline void
_map_clean(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd)
{
free(pd->cow->points);
if (pd->cow->map) evas_map_free(pd->cow->map);
if (pd->cow->ops)
{
Gfx_Map_Pivot *pivot;
Gfx_Map_Op *op;
Gfx_Map *mcow;
mcow = MAPCOW_BEGIN(pd);
EINA_INLIST_FREE(mcow->ops, op)
{
EINA_INLIST_REMOVE(mcow->ops, op);
free(op);
}
EINA_INLIST_FREE(mcow->pivots, pivot)
{
EINA_INLIST_REMOVE(mcow->pivots, pivot);
if (pivot->event_cbs)
efl_event_callback_array_del(pivot->eo_obj, _pivot_changes(), pivot);
PIVOT_UNREF(pivot->eo_obj);
free(pivot);
}
MAPCOW_END(mcow, pd);
}
}
EOLIAN Eina_Bool
_efl_gfx_mapping_mapping_has(Eo *eo_obj EINA_UNUSED, Efl_Gfx_Mapping_Data *pd EINA_UNUSED)
{
if (pd->cow == &gfx_mapping_cow_default) return EINA_FALSE;
if (pd->cow->ops) return EINA_TRUE;
if (pd->cow->map) return EINA_TRUE;
return EINA_FALSE;
}
EOLIAN static void
_efl_gfx_mapping_mapping_reset(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd)
{
Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
Eina_Bool alpha, smooth;
alpha = pd->cow->alpha;
smooth = pd->cow->smooth;
_map_clean(eo_obj, pd);
if (pd->cow->event_cbs)
efl_event_callback_array_del(eo_obj, _geometry_changes(), obj);
eina_cow_memcpy(gfx_mapping_cow, (const Eina_Cow_Data * const *) &pd->cow,
(const Eina_Cow_Data *) &gfx_mapping_cow_default);
_map_dirty(eo_obj, pd, EINA_TRUE);
MAPCOW_WRITE(pd, alpha, alpha);
MAPCOW_WRITE(pd, smooth, smooth);
}
EOLIAN static int
_efl_gfx_mapping_mapping_point_count_get(const Eo *eo_obj EINA_UNUSED, Efl_Gfx_Mapping_Data *pd)
{
return pd->cow->count;
}
EOLIAN static void
_efl_gfx_mapping_mapping_point_count_set(Eo *eo_obj EINA_UNUSED, Efl_Gfx_Mapping_Data *pd, int count)
{
Gfx_Map *mcow;
if ((count <= 0) || (count % 4 != 0))
{
ERR("Map point count (%d) should be multiples of 4", count);
return;
}
if (pd->cow->count == count) return;
mcow = MAPCOW_BEGIN(pd);
if (mcow->points == NULL)
{
mcow->points = calloc(1, count * sizeof(Gfx_Map_Point));
if (mcow->points)
mcow->count = count;
else
ERR("Failed to allocate memory with calloc");
}
else
{
Gfx_Map_Point *ps = realloc(mcow->points, count * sizeof(Gfx_Map_Point));
if (ps)
{
mcow->points = ps;
mcow->count = count;
memset(mcow->points, 0, count * sizeof(Gfx_Map_Point));
}
else
ERR("Failed to allocate memory with realloc");
}
MAPCOW_END(mcow, pd);
}
EOLIAN static Eina_Bool
_efl_gfx_mapping_mapping_clockwise_get(const Eo *eo_obj, Efl_Gfx_Mapping_Data *pd)
{
Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_TRUE);
Evas_Map *m;
m = _map_calc(eo_obj, obj, pd);
if (!m) return EINA_TRUE;
return evas_map_util_clockwise_get(m);
}
EOLIAN static void
_efl_gfx_mapping_mapping_smooth_set(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd, Eina_Bool smooth)
{
if (pd->cow->smooth == smooth) return;
MAPCOW_WRITE(pd, smooth, smooth);
_map_dirty(eo_obj, pd, EINA_FALSE);
}
EOLIAN static Eina_Bool
_efl_gfx_mapping_mapping_smooth_get(const Eo *eo_obj EINA_UNUSED, Efl_Gfx_Mapping_Data *pd)
{
return pd->cow->smooth;
}
EOLIAN static void
_efl_gfx_mapping_mapping_alpha_set(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd, Eina_Bool alpha)
{
if (pd->cow->alpha == alpha) return;
MAPCOW_WRITE(pd, alpha, alpha);
_map_dirty(eo_obj, pd, EINA_FALSE);
}
EOLIAN static Eina_Bool
_efl_gfx_mapping_mapping_alpha_get(const Eo *eo_obj EINA_UNUSED, Efl_Gfx_Mapping_Data *pd)
{
return pd->cow->alpha;
}
EOLIAN static void
_efl_gfx_mapping_mapping_coord_absolute_get(const Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
int idx, double *x, double *y, double *z)
{
Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
Evas_Map *m;
EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < pd->cow->count));
m = _map_calc(eo_obj, obj, pd);
if (!m)
{
int X, Y, W, H;
X = obj->cur->geometry.x;
Y = obj->cur->geometry.y;
W = obj->cur->geometry.w;
H = obj->cur->geometry.h;
if (x)
{
if ((idx == 0) || (idx == 3)) *x = X;
else *x = X + W;
}
if (y)
{
if ((idx == 0) || (idx == 1)) *y = Y;
else *y = Y + H;
}
if (z) *z = 0;
return;
}
_map_point_coord_get(m, idx, x, y, z);
}
EOLIAN static void
_efl_gfx_mapping_mapping_uv_set(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
int idx, double u, double v)
{
Gfx_Map *mcow;
EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < pd->cow->count));
if (!pd->cow->points)
{
Gfx_Map_Point *ps = calloc(1, pd->cow->count * sizeof(Gfx_Map_Point));
if (!ps) return;
MAPCOW_WRITE(pd, points, ps);
}
if (EINA_DBL_EQ(pd->cow->points[idx].u, u) &&
EINA_DBL_EQ(pd->cow->points[idx].v, v))
return;
mcow = MAPCOW_BEGIN(pd);
mcow->points[idx].u = CLAMP(0.0, u, 1.0);
mcow->points[idx].v = CLAMP(0.0, v, 1.0);
MAPCOW_END(mcow, pd);
_map_dirty(eo_obj, pd, EINA_FALSE);
}
EOLIAN static void
_efl_gfx_mapping_mapping_uv_get(const Eo *eo_obj EINA_UNUSED, Efl_Gfx_Mapping_Data *pd,
int idx, double *u, double *v)
{
EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < pd->cow->count)
&& (pd->cow->points));
if (u) *u = pd->cow->points[idx].u;
if (v) *v = pd->cow->points[idx].v;
}
EOLIAN static void
_efl_gfx_mapping_mapping_color_get(const Eo *eo_obj EINA_UNUSED, Efl_Gfx_Mapping_Data *pd,
int idx, int *r, int *g, int *b, int *a)
{
Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
Evas_Map_Point *p;
Evas_Map *m;
EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < pd->cow->count));
if (!r && !g && !b && !a) return;
m = _map_calc(eo_obj, obj, pd);
if (!m)
{
if (r) *r = 255;
if (g) *g = 255;
if (b) *b = 255;
if (a) *a = 255;
return;
}
p = &(m->points[idx]);
if (r) *r = p->r;
if (g) *g = p->g;
if (b) *b = p->b;
if (a) *a = p->a;
}
static Gfx_Map_Op *
_gfx_mapping_op_add(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd, Gfx_Map_Op_Type type,
const Efl_Gfx_Entity *eo_pivot, double cx, double cy, double cz,
Eina_Bool is_absolute)
{
Eina_Bool is_self = EINA_FALSE;
Gfx_Map_Pivot *pivot = NULL;
Gfx_Map_Op *op;
Gfx_Map *mcow;
op = calloc(1, sizeof(*op));
if (!op) return NULL;
mcow = MAPCOW_BEGIN(pd);
if (!is_absolute)
{
if ((eo_pivot == eo_obj) || !eo_pivot)
{
eo_pivot = NULL;
is_self = EINA_TRUE;
}
else
{
Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, MY_CLASS);
EINA_INLIST_FOREACH(mcow->pivots, pivot)
if (pivot->eo_obj == eo_pivot) break;
if (!pivot)
{
pivot = calloc(1, sizeof(*pivot));
pivot->eo_obj = PIVOT_REF(eo_pivot);
pivot->changed = EINA_TRUE;
if (efl_isa(eo_pivot, EVAS_CANVAS_CLASS))
{
pivot->is_evas = EINA_TRUE;
pivot->is_canvas = EINA_TRUE;
}
else if (efl_isa(eo_pivot, EFL_CANVAS_SCENE_INTERFACE))
pivot->is_canvas = EINA_TRUE;
pivot->map_obj = obj;
EINA_INLIST_APPEND(mcow->pivots, pivot);
}
}
}
op->op = type;
op->pivot.is_absolute = is_absolute;
op->pivot.is_self = is_self;
op->pivot.pivot = pivot;
op->pivot.cx = cx;
op->pivot.cy = cy;
op->pivot.cz = cz;
EINA_INLIST_APPEND(mcow->ops, op);
MAPCOW_END(mcow, pd);
_map_dirty(eo_obj, pd, EINA_FALSE);
return op;
}
EOLIAN static void
_efl_gfx_mapping_mapping_coord_absolute_set(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
int idx, double x, double y, double z)
{
Gfx_Map_Op *op;
EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < pd->cow->count));
op = _gfx_mapping_op_add(eo_obj, pd, GFX_MAPPING_RAW_COORD, NULL, 0, 0, 0, EINA_FALSE);
if (!op) return;
op->raw_coord.idx = idx;
op->raw_coord.x = x;
op->raw_coord.y = y;
op->raw_coord.z = z;
}
EOLIAN static void
_efl_gfx_mapping_mapping_color_set(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
int idx, int r, int g, int b, int a)
{
Gfx_Map_Op *op;
EINA_SAFETY_ON_FALSE_RETURN((idx >= -1) && (idx < pd->cow->count));
op = _gfx_mapping_op_add(eo_obj, pd, GFX_MAPPING_COLOR, NULL, 0, 0, 0, EINA_FALSE);
if (!op) return;
op->color.idx = idx;
op->color.r = r;
op->color.g = g;
op->color.b = b;
op->color.a = a;
}
EOLIAN static void
_efl_gfx_mapping_translate(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double dx, double dy, double dz)
{
Gfx_Map_Op *op;
op = _gfx_mapping_op_add(eo_obj, pd, GFX_MAPPING_TRANSLATE, NULL, 0, 0, 0, EINA_FALSE);
if (!op) return;
op->translate.dx = dx;
op->translate.dy = dy;
op->translate.dz = dz;
}
static inline void
_map_rotate(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double degrees, const Efl_Gfx_Entity *pivot, double cx, double cy,
Eina_Bool absolute)
{
Gfx_Map_Op *op;
op = _gfx_mapping_op_add(eo_obj, pd, GFX_MAPPING_ROTATE_2D, pivot, cx, cy, 0, absolute);
if (!op) return;
op->rotate_2d.degrees = degrees;
}
EOLIAN static void
_efl_gfx_mapping_rotate(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double degrees, const Efl_Gfx_Entity *pivot, double cx, double cy)
{
_map_rotate(eo_obj, pd, degrees, pivot, cx, cy, EINA_FALSE);
}
EOLIAN static void
_efl_gfx_mapping_rotate_absolute(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd, double degrees, double cx, double cy)
{
_map_rotate(eo_obj, pd, degrees, NULL, cx, cy, EINA_TRUE);
}
static inline void
_map_rotate_3d(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double dx, double dy, double dz,
const Efl_Gfx_Entity *pivot, double cx, double cy, double cz,
Eina_Bool absolute)
{
Gfx_Map_Op *op;
op = _gfx_mapping_op_add(eo_obj, pd, GFX_MAPPING_ROTATE_3D, pivot, cx, cy, cz, absolute);
if (!op) return;
op->rotate_3d.dx = dx;
op->rotate_3d.dy = dy;
op->rotate_3d.dz = dz;
}
EOLIAN static void
_efl_gfx_mapping_rotate_3d(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double dx, double dy, double dz,
const Efl_Gfx_Entity *pivot, double cx, double cy, double cz)
{
_map_rotate_3d(eo_obj, pd, dx, dy, dz, pivot, cx, cy, cz, EINA_FALSE);
}
EOLIAN static void
_efl_gfx_mapping_rotate_3d_absolute(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double dx, double dy, double dz, double cx, double cy, double cz)
{
_map_rotate_3d(eo_obj, pd, dx, dy, dz, NULL, cx, cy, cz, EINA_TRUE);
}
static inline void
_map_rotate_quat(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double qx, double qy, double qz, double qw,
const Efl_Gfx_Entity *pivot, double cx, double cy, double cz,
Eina_Bool absolute)
{
Gfx_Map_Op *op;
op = _gfx_mapping_op_add(eo_obj, pd, GFX_MAPPING_ROTATE_QUAT, pivot, cx, cy, cz, absolute);
if (!op) return;
op->rotate_quat.qx = qx;
op->rotate_quat.qy = qy;
op->rotate_quat.qz = qz;
op->rotate_quat.qw = qw;
}
EOLIAN static void
_efl_gfx_mapping_rotate_quat(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double qx, double qy, double qz, double qw,
const Efl_Gfx_Entity *pivot, double cx, double cy, double cz)
{
_map_rotate_quat(eo_obj, pd, qx, qy, qz, qw, pivot, cx, cy, cz, EINA_FALSE);
}
EOLIAN static void
_efl_gfx_mapping_rotate_quat_absolute(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double qx, double qy, double qz, double qw,
double cx, double cy, double cz)
{
_map_rotate_quat(eo_obj, pd, qx, qy, qz, qw, NULL, cx, cy, cz, EINA_TRUE);
}
static inline void
_map_zoom(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double zoomx, double zoomy,
const Efl_Gfx_Entity *pivot, double cx, double cy,
Eina_Bool absolute)
{
Gfx_Map_Op *op;
op = _gfx_mapping_op_add(eo_obj, pd, GFX_MAPPING_ZOOM, pivot, cx, cy, 0, absolute);
if (!op) return;
op->zoom.zx = zoomx;
op->zoom.zy = zoomy;
}
EOLIAN static void
_efl_gfx_mapping_zoom(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double zoomx, double zoomy,
const Efl_Gfx_Entity *pivot, double cx, double cy)
{
_map_zoom(eo_obj, pd, zoomx, zoomy, pivot, cx, cy, EINA_FALSE);
}
EOLIAN static void
_efl_gfx_mapping_zoom_absolute(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double zoomx, double zoomy, double cx, double cy)
{
_map_zoom(eo_obj, pd, zoomx, zoomy, NULL, cx, cy, EINA_TRUE);
}
static inline void
_map_lighting_3d(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
const Efl_Gfx_Entity *pivot, double lx, double ly, double lz,
int lr, int lg, int lb, int ar, int ag, int ab,
Eina_Bool absolute)
{
Gfx_Map_Op *op;
op = _gfx_mapping_op_add(eo_obj, pd, GFX_MAPPING_LIGHTING_3D, pivot, lx, ly, lz, absolute);
if (!op) return;
op->lighting_3d.lr = lr;
op->lighting_3d.lg = lg;
op->lighting_3d.lb = lb;
op->lighting_3d.ar = ar;
op->lighting_3d.ag = ag;
op->lighting_3d.ab = ab;
}
EOLIAN static void
_efl_gfx_mapping_lighting_3d(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
const Efl_Gfx_Entity *pivot, double lx, double ly, double lz,
int lr, int lg, int lb, int ar, int ag, int ab)
{
_map_lighting_3d(eo_obj, pd, pivot, lx, ly, lz, lr, lg, lb, ar, ag, ab, EINA_FALSE);
}
EOLIAN static void
_efl_gfx_mapping_lighting_3d_absolute(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double lx, double ly, double lz,
int lr, int lg, int lb, int ar, int ag, int ab)
{
_map_lighting_3d(eo_obj, pd, NULL, lx, ly, lz, lr, lg, lb, ar, ag, ab, EINA_TRUE);
}
static inline void
_map_perspective_3d(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
const Efl_Gfx_Entity *pivot, double px, double py,
double z0, double foc,
Eina_Bool absolute)
{
Gfx_Map_Op *op;
if (foc <= 0.0)
{
ERR("Focal length must be greater than 0!");
return;
}
op = _gfx_mapping_op_add(eo_obj, pd, GFX_MAPPING_PERSPECTIVE_3D, pivot, px, py, 0, absolute);
if (!op) return;
op->perspective_3d.z0 = z0;
op->perspective_3d.foc = foc;
}
EOLIAN static void
_efl_gfx_mapping_perspective_3d(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
const Efl_Gfx_Entity *pivot, double px, double py,
double z0, double foc)
{
_map_perspective_3d(eo_obj, pd, pivot, px, py, z0, foc, EINA_FALSE);
}
EOLIAN static void
_efl_gfx_mapping_perspective_3d_absolute(Eo *eo_obj, Efl_Gfx_Mapping_Data *pd,
double px, double py, double z0, double foc)
{
_map_perspective_3d(eo_obj, pd, NULL, px, py, z0, foc, EINA_TRUE);
}
#include "canvas/efl_gfx_mapping.eo.c"