evas_map: more extensible and safe. add docs

change evas_map to return a structure that serves as an array of
points. This way we'll know for sure the number of points in it. Right
now it's hardcoded to 4, so check it, but in future we can just allow
more points and it should work.

added docs. I'm not sure about most of it, so it would be good to have
someone to review and fill in more, maybe that's raster? Grep for
"TODO" and you'll see the missing stuff. It would be good to add
examples in evas_map_point_coord_set() and
evas_map_point_image_uv_set()



SVN revision: 43211
This commit is contained in:
Gustavo Sverzut Barbieri 2009-10-22 20:11:33 +00:00
parent 9af68d80da
commit 6982f7b9c6
4 changed files with 315 additions and 106 deletions

View File

@ -105,6 +105,7 @@ typedef struct _Evas_Transform Evas_Transform; /**< An Evas projective or affine
typedef struct _Evas_Coord_Rectangle Evas_Coord_Rectangle; /**< A generic rectangle handle */
typedef struct _Evas_Smart_Class Evas_Smart_Class; /**< A smart object base class */
typedef struct _Evas_Map_Point Evas_Map_Point; /**< A point with attributes for x, y, z texture u & v etc. */
typedef struct _Evas_Map Evas_Map; /**< An array of map points */
typedef struct _Evas Evas; /**< An Evas canvas handle */
typedef struct _Evas_Object Evas_Object; /**< An Evas Object handle */
@ -847,22 +848,23 @@ extern "C" {
EAPI Eina_List *evas_objects_at_xy_get (const Evas *e, Evas_Coord x, Evas_Coord y, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
EAPI Eina_List *evas_objects_in_rectangle_get (const Evas *e, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
EAPI void evas_object_map_enable_set (Evas_Object *obj, Eina_Bool enabled);
EAPI Eina_Bool evas_object_map_enable_get (const Evas_Object *obj);
EAPI void evas_object_map_set (Evas_Object *obj, const Evas_Map_Point *points);
EAPI void evas_object_map_get (const Evas_Object *obj, Evas_Map_Point *points);
EAPI void evas_object_map_set (Evas_Object *obj, const Evas_Map *map);
EAPI const Evas_Map *evas_object_map_get (const Evas_Object *obj);
EAPI void evas_map_util_rotate (Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy);
EAPI void evas_map_util_zoom (Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy);
EAPI Evas_Map *evas_map_new (unsigned long count);
EAPI Evas_Map *evas_map_dup (const Evas_Map *m);
EAPI void evas_map_free (Evas_Map *m);
EAPI void evas_map_point_coord_set (Evas_Map *m, unsigned long idx, Evas_Coord x, Evas_Coord y, Evas_Coord z);
EAPI void evas_map_point_coord_get (const Evas_Map *m, unsigned long idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z);
EAPI void evas_map_point_image_uv_set (Evas_Map *m, unsigned long idx, double u, double v);
EAPI void evas_map_point_image_uv_get (const Evas_Map *m, unsigned long idx, double *u, double *v);
EAPI void evas_map_util_rotate (Evas_Map_Point *mp, double degrees, Evas_Coord cx, Evas_Coord cy);
EAPI void evas_map_util_zoom (Evas_Map_Point *mp, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy);
EAPI Evas_Map_Point *evas_map_new (int num);
EAPI void evas_map_free (Evas_Map_Point *mp);
EAPI void evas_map_point_coord_set (Evas_Map_Point *mp, int n, Evas_Coord x, Evas_Coord y, Evas_Coord z);
EAPI void evas_map_point_coord_get (const Evas_Map_Point *mp, int n, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z);
EAPI void evas_map_point_image_uv_set (Evas_Map_Point *mp, int n, double u, double v);
EAPI void evas_map_point_image_uv_get (const Evas_Map_Point *mp, int n, double *u, double *v);
/* smart objects */
EINA_DEPRECATED EAPI Evas_Smart *evas_smart_new (const char *name, void (*func_add) (Evas_Object *obj), void (*func_del) (Evas_Object *obj), void (*func_layer_set) (Evas_Object *obj, int l), void (*func_raise) (Evas_Object *obj), void (*func_lower) (Evas_Object *obj), void (*func_stack_above) (Evas_Object *obj, Evas_Object *above), void (*func_stack_below) (Evas_Object *obj, Evas_Object *below), void (*func_move) (Evas_Object *obj, Evas_Coord x, Evas_Coord y), void (*func_resize) (Evas_Object *obj, Evas_Coord w, Evas_Coord h), void (*func_show) (Evas_Object *obj), void (*func_hide) (Evas_Object *obj), void (*func_color_set) (Evas_Object *obj, int r, int g, int b, int a), void (*func_clip_set) (Evas_Object *obj, Evas_Object *clip), void (*func_clip_unset) (Evas_Object *obj), const void *data) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
EAPI void evas_smart_free (Evas_Smart *s) EINA_ARG_NONNULL(1);

View File

@ -5,21 +5,24 @@
static void
_calc_map_geometry(Evas_Object *obj)
{
int i;
int is, was = 0, pass = 0;
Evas_Coord x1, x2, y1, y2;
if (!obj->cur.mappoints) return;
x1 = obj->cur.mappoints[0].x;
x2 = obj->cur.mappoints[0].x;
y1 = obj->cur.mappoints[0].y;
y2 = obj->cur.mappoints[0].y;
for (i = 1; i < 4; i++)
const Evas_Map_Point *p, *p_end;
if (!obj->cur.map) return;
p = obj->cur.map->points;
p_end = p + 4;
x1 = p->x;
x2 = p->x;
y1 = p->y;
y2 = p->y;
p++;
for (; p < p_end; p++)
{
if (obj->cur.mappoints[i].x < x1) x1 = obj->cur.mappoints[i].x;
if (obj->cur.mappoints[i].x > x2) x2 = obj->cur.mappoints[i].x;
if (obj->cur.mappoints[i].y < y1) y1 = obj->cur.mappoints[i].y;
if (obj->cur.mappoints[i].y > y2) y2 = obj->cur.mappoints[i].y;
if (p->x < x1) x1 = p->x;
if (p->x > x2) x2 = p->x;
if (p->y < y1) y1 = p->y;
if (p->y > y2) y2 = p->y;
}
obj->cur.geometry.x = x1;
obj->cur.geometry.y = y1;
@ -70,142 +73,337 @@ evas_object_map_enable_get(const Evas_Object *obj)
return obj->cur.usemap;
}
static inline Evas_Map *
_evas_map_new(unsigned long count)
{
Evas_Map *m = malloc(sizeof(Evas_Map) + count * sizeof(Evas_Map_Point));
if (!m)
return NULL;
m->count = count;
return m;
}
static inline Evas_Map *
_evas_map_dup(const Evas_Map *orig)
{
Evas_Map *copy = _evas_map_new(orig->count);
if (!orig)
return NULL;
memcpy(copy->points, orig->points, orig->count * sizeof(Evas_Map_Point));
return copy;
}
static inline Eina_Bool
_evas_map_copy(Evas_Map *dst, const Evas_Map *src)
{
if (dst->count != src->count)
{
ERR("cannot copy map of different sizes: dst=%lu, src=%lu",
dst->count, src->count);
return EINA_FALSE;
}
memcpy(dst->points, src->points, src->count * sizeof(Evas_Map_Point));
return EINA_TRUE;
}
static inline void
_evas_map_free(Evas_Map *m)
{
free(m);
}
/**
* Set current object transformation map (or unset if it's @c NULL).
*
* @param obj object to change transformation map.
* @param map new map to use or @c NULL to unset map. This function
* will copy the given map, so it's safe to destroy it
* afterwards.
*
* @see evas_map_new()
*/
EAPI void
evas_object_map_set(Evas_Object *obj, const Evas_Map_Point *points)
evas_object_map_set(Evas_Object *obj, const Evas_Map *map)
{
MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
return;
MAGIC_CHECK_END();
if (!points)
if (!map)
{
if (obj->cur.mappoints)
if (obj->cur.map)
{
if (!obj->prev.mappoints)
if (!obj->prev.map)
{
free(obj->cur.mappoints);
obj->cur.mappoints = NULL;
_evas_map_free(obj->cur.map);
obj->cur.map = NULL;
return;
}
obj->cur.mappoints = NULL;
obj->cur.map = NULL;
}
return;
}
if (!obj->cur.mappoints)
if (!obj->cur.map)
{
obj->cur.mappoints = malloc(4 * sizeof(Evas_Map_Point));
if (obj->cur.mappoints)
{
memcpy(obj->cur.mappoints, points, 4 * sizeof(Evas_Map_Point));
}
obj->prev.mappoints = NULL;
obj->cur.map = _evas_map_dup(map);
obj->prev.map = NULL;
}
else
{
memcpy(obj->cur.mappoints, points, 4 * sizeof(Evas_Map_Point));
obj->prev.mappoints = NULL;
_evas_map_copy(obj->cur.map, map);
obj->prev.map = NULL;
}
if (obj->cur.usemap) _calc_map_geometry(obj);
}
EAPI void
evas_object_map_get(const Evas_Object *obj, Evas_Map_Point *points)
/**
* Get current object transformation map.
*
* @param obj object to query transformation map.
* @return map reference to map in use. This is an internal reference,
* don't change it anyhow. Use evas_map_dup() if you want to
* change it and use somewhere else, or even take reference
* for long time. The returned reference may go away when
* another map is set or object is destroyed.
*
* @see evas_object_map_set()
*/
EAPI const Evas_Map *
evas_object_map_get(const Evas_Object *obj)
{
MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
return;
return NULL;
MAGIC_CHECK_END();
if (obj->cur.mappoints)
if (obj->cur.map)
return obj->cur.map;
else
return NULL;
}
/**
* Creates map of transformation points to be later used with an evas object.
*
* @param count number of points in the map. So far it @b must be 4 as
* evas will use that exact number. The parameter is for
* extensibility. Giving any value other than 4 will return @c NULL.
*
* @return a newly allocated map or @c NULL on errors.
*
* @see evas_map_free()
* @see evas_map_dup()
* @see evas_map_point_coord_set()
* @see evas_map_point_image_uv_set()
*
* @see evas_object_map_set()
*/
EAPI Evas_Map *
evas_map_new(unsigned long count)
{
if (count != 4)
{
memcpy(points, obj->cur.mappoints, 4 * sizeof(Evas_Map_Point));
ERR("num (%lu) != 4 is unsupported!", count);
return NULL;
}
return _evas_map_new(count);
}
EAPI Evas_Map_Point *
evas_map_new(int num)
/**
* Copy a previously allocated map.
*
* @param m map to copy. Must not be @c NULL.
*
* @return newly allocated map with the same count and contents as @a m.
*/
EAPI Evas_Map *
evas_map_dup(const Evas_Map *m)
{
return calloc(num, sizeof(Evas_Map_Point));
if (!m) return NULL;
return _evas_map_dup(m);
}
/**
* Destroys a previously allocated map.
*
* @param m map to destroy. Must not be @c NULL.
*/
EAPI void
evas_map_free(Evas_Map_Point *mp)
evas_map_free(Evas_Map *m)
{
if (!mp) return;
free(mp);
if (!m) return;
_evas_map_free(m);
}
/**
* Change the map point's coordinate.
*
* @param m map to change point. Must not be @c NULL.
* @param idx index of point to change. Must be smaller than map size.
* @param x TODO
* @param y TODO
* @param z TODO
*
* @see evas_map_util_rotate()
* @see evas_map_util_zoom()
*/
EAPI void
evas_map_point_coord_set(Evas_Map_Point *mp, int n, Evas_Coord x, Evas_Coord y, Evas_Coord z)
evas_map_point_coord_set(Evas_Map *m, unsigned long idx, Evas_Coord x, Evas_Coord y, Evas_Coord z)
{
if (!mp) return;
mp[n].x = x;
mp[n].y = y;
mp[n].z = z;
Evas_Map_Point *p;
if (!m) return;
if (idx >= m->count) return;
p = m->points + idx;
p->x = x;
p->y = y;
p->z = z;
}
/**
* Get the map point's coordinate.
*
* @param m map to query point. Must not be @c NULL.
* @param idx index of point to query. Must be smaller than map size.
* @param x where to return TODO. If non @c NULL, it's guaranteed to
* be set (on error it's set to zero).
* @param y where to return TODO. If non @c NULL, it's guaranteed to
* be set (on error it's set to zero).
* @param z where to return TODO. If non @c NULL, it's guaranteed to
* be set (on error it's set to zero).
*/
EAPI void
evas_map_point_coord_get(const Evas_Map_Point *mp, int n, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z)
evas_map_point_coord_get(const Evas_Map *m, unsigned long idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z)
{
if (!mp) return;
if (x) *x = mp[n].x;
if (y) *y = mp[n].y;
if (z) *z = mp[n].z;
const Evas_Map_Point *p;
if (!m) goto error;
if (idx >= m->count) goto error;
p = m->points + idx;
if (x) *x = p->x;
if (y) *y = p->y;
if (z) *z = p->z;
return;
error:
if (x) *x = 0;
if (y) *y = 0;
if (z) *z = 0;
}
/**
* Change the map point's TODO.
*
* @param m map to change point. Must not be @c NULL.
* @param idx index of point to change. Must be smaller than map size.
* @param u TODO
* @param v TODO
*/
EAPI void
evas_map_point_image_uv_set(Evas_Map_Point *mp, int n, double u, double v)
evas_map_point_image_uv_set(Evas_Map *m, unsigned long idx, double u, double v)
{
if (!mp) return;
mp[n].u = u;
mp[n].v = v;
Evas_Map_Point *p;
if (!m) return;
if (idx >= m->count) return;
p = m->points + idx;
p->u = u;
p->v = v;
}
/**
* Get the map point's TODO.
*
* @param m map to query point. Must not be @c NULL.
* @param idx index of point to query. Must be smaller than map size.
* @param u where to return TODO. If non @c NULL, it's guaranteed to
* be set (on error it's set to zero).
* @param v where to return TODO. If non @c NULL, it's guaranteed to
* be set (on error it's set to zero).
*/
EAPI void
evas_map_point_image_uv_get(const Evas_Map_Point *mp, int n, double *u, double *v)
evas_map_point_image_uv_get(const Evas_Map *m, unsigned long idx, double *u, double *v)
{
if (!mp) return;
if (u) *u = mp[n].u;
if (v) *v = mp[n].v;
const Evas_Map_Point *p;
if (!m) goto error;
if (idx >= m->count) goto error;
p = m->points + idx;
if (u) *u = p->u;
if (v) *v = p->v;
return;
error:
if (u) *u = 0.0;
if (v) *v = 0.0;
}
/**
* Change the map to apply the given rotation to object.
*
* @param m map to change. Must not be @c NULL.
* @param degrees amount of degrees from 0.0 to 360.0 to rotate the
* object. This is the canonical reference, counter-clockwise. TODO
* @param cx rotation's center horizontal positon. TODO (offset from object center? left?)
* @param cy rotation's center vertical positon. TODO (offset from object center? top?)
*
* @see evas_map_point_coord_set()
*/
EAPI void
evas_map_util_rotate(Evas_Map_Point *mp, double degrees, Evas_Coord cx, Evas_Coord cy)
evas_map_util_rotate(Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy)
{
double r = (degrees * M_PI) / 180.0;
int i;
Evas_Map_Point *p, *p_end;
for (i = 0; i < 4; i++)
if (!m) return;
if (m->count != 4) return;
p = m->points;
p_end = p + 4;
for (; p < p_end; p++)
{
Evas_Coord x, y, xx, yy;
xx = x = mp[i].x - cx;
yy = y = mp[i].y - cy;
xx = x = p->x - cx;
yy = y = p->y - cy;
xx = (x * cos(r));
yy = (x * sin(r));
x = xx + (y * cos(r + (M_PI / 2.0)));
y = yy + (y * sin(r + (M_PI / 2.0)));
mp[i].x = x + cx;
mp[i].y = y + cy;
p->x = x + cx;
p->y = y + cy;
}
}
/**
* Change the map to apply the given zooming to object.
*
* @param m map to change. Must not be @c NULL.
* @param zoomx horizontal zoom to use.
* @param zoomy vertical zoom to use.
* @param cx zooming center horizontal positon. TODO (offset from object center? left?)
* @param cy zooming center vertical positon. TODO (offset from object center? top?)
*
* @see evas_map_point_coord_set()
*/
EAPI void
evas_map_util_zoom(Evas_Map_Point *mp, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy)
evas_map_util_zoom(Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy)
{
int i;
Evas_Map_Point *p, *p_end;
for (i = 0; i < 4; i++)
if (!m) return;
if (m->count != 4) return;
p = m->points;
p_end = p + 4;
for (; p < p_end; p++)
{
Evas_Coord x, y;
x = mp[i].x - cx;
y = mp[i].y - cy;
x = p->x - cx;
y = p->y - cy;
x = (((double)x) * zoomx);
y = (((double)y) * zoomy);
mp[i].x = x + cx;
mp[i].y = y + cy;
p->x = x + cx;
p->y = y + cy;
}
}

View File

@ -2327,19 +2327,23 @@ evas_object_image_render(Evas_Object *obj, void *output, void *context, void *su
}
o->dirty_pixels = 0;
}
if ((obj->cur.mappoints) && (obj->cur.usemap))
if ((obj->cur.map) && (obj->cur.map->count == 4) && (obj->cur.usemap))
{
RGBA_Map_Point pts[4];
int i;
const Evas_Map_Point *p, *p_end;
RGBA_Map_Point pts[4], *pt;
p = obj->cur.map->points;
p_end = p + 4;
pt = pts;
// draw geom +x +y
for (i = 0; i < 4; i++)
for (; p < p_end; p++, pt++)
{
pts[i].x = (obj->cur.mappoints[i].x + x) << FP;
pts[i].y = (obj->cur.mappoints[i].y + y) << FP;
pts[i].z = (obj->cur.mappoints[i].z) << FP;
pts[i].u = obj->cur.mappoints[i].u * FP1;
pts[i].v = obj->cur.mappoints[i].v * FP1;
pt->x = (p->x + x) << FP;
pt->y = (p->y + y) << FP;
pt->z = (p->z) << FP;
pt->u = p->u * FP1;
pt->v = p->v * FP1;
}
obj->layer->evas->engine.func->image_map4_draw(output,
context,
@ -2794,7 +2798,6 @@ static int
evas_object_image_is_opaque(Evas_Object *obj)
{
Evas_Object_Image *o;
int v;
/* this returns 1 if the internal object data implies that the object is */
/* currently fully opaque over the entire rectangle it occupies */
@ -2807,7 +2810,7 @@ evas_object_image_is_opaque(Evas_Object *obj)
(o->cur.border.b != 0)) &&
(!o->cur.border.fill)) return 0;
if (!o->engine_data) return 0;
if ((obj->cur.mappoints) && (obj->cur.usemap)) return 0;
if ((obj->cur.map) && (obj->cur.usemap)) return 0;
if (obj->cur.render_op == EVAS_RENDER_COPY) return 1;
if (o->cur.has_alpha) return 0;
return 1;
@ -2829,7 +2832,7 @@ evas_object_image_was_opaque(Evas_Object *obj)
(o->prev.border.b != 0)) &&
(!o->prev.border.fill)) return 0;
if (!o->engine_data) return 0;
if ((obj->prev.mappoints) && (obj->prev.usemap)) return 0;
if ((obj->prev.map) && (obj->prev.usemap)) return 0;
if (obj->prev.render_op == EVAS_RENDER_COPY) return 1;
if (o->prev.has_alpha) return 0;
if (obj->prev.render_op != EVAS_RENDER_BLEND) return 0;
@ -2973,7 +2976,7 @@ evas_object_image_has_opaque_rect(Evas_Object *obj)
Evas_Object_Image *o;
o = (Evas_Object_Image *)(obj->object_data);
if ((obj->cur.mappoints) && (obj->cur.usemap)) return 0;
if ((obj->cur.map) && (obj->cur.usemap)) return 0;
if (((o->cur.border.l | o->cur.border.r | o->cur.border.t | o->cur.border.b) != 0) &&
(o->cur.border.fill == EVAS_BORDER_FILL_SOLID) &&
(obj->cur.render_op == EVAS_RENDER_BLEND) &&

View File

@ -364,6 +364,12 @@ struct _Evas_Map_Point
// FIXME: add color?
};
struct _Evas_Map
{
unsigned long count;
Evas_Map_Point points[];
};
struct _Evas_Object
{
EINA_INLIST;
@ -389,7 +395,7 @@ struct _Evas_Object
} clip;
} cache;
double scale;
Evas_Map_Point *mappoints;
Evas_Map *map;
Evas_Coord_Rectangle geometry;
struct {
unsigned char r, g, b, a;