Evas Map - Overview

Down to the very bottom, Map is simple: it takes an object and transforms the way it will be shown on screen. But using it properly can be a bit troublesome.

For the most common operations there are utility functions that help in setting up the map to achieve the desired effects. Now we'll go through an overview of the map API and some of the things that can be done with it.

The full code can be found here.

To show how some functions work, this example listens to keys pressed to toggle several options.

typedef struct
{
Ecore_Evas *ee;
Evas *canvas;
struct {
int r, g, b, a;
} colors[6];
int colors_index;
int frame;
Eina_Bool alpha : 1;
Eina_Bool smooth : 1;
Eina_Bool backface_culling : 1;
Eina_Bool apply_perspective : 1;
Eina_Bool apply_lighting : 1;
} App_Data;
unsigned char Eina_Bool
Type to mimic a boolean.
Definition: eina_types.h:527
Eo Evas
An opaque handle to an Evas canvas.
Definition: Evas_Common.h:163
static const char *img1_path = PACKAGE_EXAMPLES_DIR EVAS_IMAGE_FOLDER "/cube1.png";

In this program, we divide the window in four quadrants, each holding an object that will have different map configurations applied to them in each call to an animator function.

static Eina_Bool
_anim_cb(void *data)
{
App_Data *ad = data;
Evas_Map *m;
int r, g, b, a;
int win_w, win_h, img_w, img_h;
Evas_Coord x, y, w, h;
evas_output_size_get(ad->canvas, &win_w, &win_h);
int Evas_Coord
Type used for coordinates (in pixels, int).
Definition: Evas_Common.h:116
EVAS_API void evas_output_size_get(const Evas *eo_e, int *w, int *h)
Retrieve the output size of the render engine of the given evas.
Definition: evas_main.c:1402
Efl_Canvas_Object Evas_Object
An Evas Object handle.
Definition: Evas_Common.h:185

Let's first create a map and set some of our options to it. Only four points maps are supported, so we'll stick to that magic number. We can set a color for each vertex or apply one for all of them at once

m = evas_map_new(4);
evas_map_smooth_set(m, ad->smooth);
evas_map_alpha_set(m, ad->alpha);
r = ad->colors[ad->colors_index].r;
g = ad->colors[ad->colors_index].g;
b = ad->colors[ad->colors_index].b;
a = ad->colors[ad->colors_index].a;
EVAS_API void evas_map_alpha_set(Evas_Map *m, Eina_Bool enabled)
Set the alpha flag for map rendering.
Definition: evas_map.c:690
EVAS_API void evas_map_smooth_set(Evas_Map *m, Eina_Bool enabled)
Set the smoothing for map rendering.
Definition: evas_map.c:670
EVAS_API void evas_map_util_points_color_set(Evas_Map *m, int r, int g, int b, int a)
Set color of all points to given color.
Definition: evas_map.c:922
EVAS_API Evas_Map * evas_map_new(int count)
Create map of transformation points to be later used with an Evas object.
Definition: evas_map.c:658

For the first object, we'll have a plain rectangle. At its creation, this rectangle was set to be semi-transparent, but whether its own alpha is used will be defined by the map's alpha setting. If the map's alpha is disabled, then the object will be completely opaque. The map's own color, however, will use any alpha set to it.

So we get our object, initialize our map geometry to match the rectangle and make it rotate around its own center, then apply the map to the object so it takes effect.

o = evas_object_name_find(ad->canvas, "obj1");
evas_object_geometry_get(o, &x, &y, &w, &h);
evas_map_util_rotate(m, 3 * ad->frame, x + (w / 2), y + (h / 2));
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition: eina_types.h:539
EVAS_API Efl_Canvas_Object * evas_object_name_find(const Evas_Canvas *obj, const char *name)
Retrieves the object on the given evas with the given name.
Definition: evas_canvas_eo.legacy.c:243
EVAS_API void evas_object_geometry_get(const Evas_Object *eo_obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
Retrieves the position and (rectangular) size of the given Evas object.
Definition: evas_object_main.c:1335
EVAS_API void evas_map_util_rotate(Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy)
Change the map to apply the given rotation.
Definition: evas_map.c:968
EVAS_API void evas_map_util_points_populate_from_object(Evas_Map *m, const Evas_Object *eo_obj)
Populate source and destination map points to match exactly object.
Definition: evas_map.c:885
EVAS_API void evas_object_map_set(Evas_Object *eo_obj, const Evas_Map *map)
Set current object transformation map.
Definition: evas_map.c:532
EVAS_API void evas_object_map_enable_set(Eo *eo_obj, Eina_Bool enabled)
Enable or disable the map that is set.
Definition: evas_map.c:516

The second object is an image. Here we don't have any color set for the object, but the image itself contains an alpha channel that will not be affected by the map settings, so even with alpha set to be off, the image will still be transparent. Color applied to the map will tint it though. Since setting a map copies it into the object, we can reuse the same one we created before. We initialize it to the new object while all other options are kept the same. Notice that no rotation will be done here, as that's just an utility function that takes the coordinates set for each point of the map and transforms it accordingly.

o = evas_object_name_find(ad->canvas, "obj2");
evas_object_geometry_get(o, &x, &y, &w, &h);
evas_object_image_size_get(o, &img_w, &img_h);
EVAS_API void evas_map_util_points_populate_from_object_full(Evas_Map *m, const Evas_Object *eo_obj, Evas_Coord z)
Populate source and destination map points to match exactly object.
Definition: evas_map.c:863
EVAS_API void evas_object_image_size_get(const Evas_Object *obj, int *w, int *h)
Retrieves the size of the given image object.
Definition: evas_image_legacy.c:159

This time the object is a bit farther into the screen, by using a z value higher than 0 to init the map. We also need to map the image used by the object, so Evas knows how to transform it properly. For this we use the evas_map_point_image_uv_set() to tell the map what coordinate within the image corresponds to each point of the map.

evas_map_point_image_uv_set(m, 1, img_w, 0);
evas_map_point_image_uv_set(m, 2, img_w, img_h);
evas_map_point_image_uv_set(m, 3, 0, img_h);
EVAS_API void evas_map_point_image_uv_set(Evas_Map *m, int idx, double u, double v)
Change the map point's U and V texture source point.
Definition: evas_map.c:787

This object will also be rotated, but in all three axis and around some other point, not its center, chosen mostly at random. If enabled, lighting will be applied to, from a light source at the center of the window.

evas_map_util_3d_rotate(m, ad->frame * 6, ad->frame * 6, ad->frame * 6,
x + (w / 3), y + 10, 0);
if (ad->apply_lighting)
evas_map_util_3d_lighting(m, win_w / 2, win_h / 2, -100,
255, 255, 255, 0, 0, 0);
EVAS_API void evas_map_util_3d_lighting(Evas_Map *m, Evas_Coord lx, Evas_Coord ly, Evas_Coord lz, int lr, int lg, int lb, int ar, int ag, int ab)
Perform lighting calculations on the given Map.
Definition: evas_map.c:1215
EVAS_API void evas_map_util_3d_rotate(Evas_Map *m, double dx, double dy, double dz, Evas_Coord cx, Evas_Coord cy, Evas_Coord cz)
Rotate the map around 3 axes in 3D.
Definition: evas_map.c:1077

For the third object we are doing, once more, a 3D rotation, but this time perspective will be applied to our map to make it look more realistic. The lighting source also follows the mouse cursor and it's possible to toggle backface culling, so that the object is hidden whenever we are not seeing its front face.

o = evas_object_name_find(ad->canvas, "obj3");
evas_object_geometry_get(o, &x, &y, &w, &h);
evas_object_image_size_get(o, &img_w, &img_h);
evas_map_util_points_populate_from_geometry(m, x, y + (h / 2), w, h, -20);
evas_map_point_image_uv_set(m, 1, img_w, 0);
evas_map_point_image_uv_set(m, 2, img_w, img_h);
evas_map_point_image_uv_set(m, 3, 0, img_h);
evas_map_util_3d_rotate(m, 20, ad->frame * 6, 0,
x + (w / 2), y + (w / 2), w / 2);
if (ad->apply_perspective)
evas_map_util_3d_perspective(m, x + (w / 2), y + (h / 2), 0, 256);
if (ad->apply_lighting)
{
Evas_Coord mx, my;
evas_pointer_canvas_xy_get(ad->canvas, &mx, &my);
evas_map_util_3d_lighting(m, mx, my, -256,
255, 255, 255, 0, 0, 0);
}
if (ad->backface_culling)
{
else
}
else
EVAS_API void evas_pointer_canvas_xy_get(const Evas_Canvas *obj, int *x, int *y)
This function returns the current known default pointer coordinates.
Definition: evas_canvas_eo.legacy.c:75
EVAS_API void evas_object_show(Evas_Object *eo_obj)
Makes the given Evas object visible.
Definition: evas_object_main.c:1814
EVAS_API void evas_object_hide(Evas_Object *eo_obj)
Makes the given Evas object invisible.
Definition: evas_object_main.c:1823
EVAS_API Eina_Bool evas_map_util_clockwise_get(Evas_Map *m)
Get the clockwise state of a map.
Definition: evas_map.c:1275
EVAS_API void evas_map_util_points_populate_from_geometry(Evas_Map *m, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Evas_Coord z)
Populate source and destination map points to match given geometry.
Definition: evas_map.c:907
EVAS_API void evas_map_util_3d_perspective(Evas_Map *m, Evas_Coord px, Evas_Coord py, Evas_Coord z0, Evas_Coord foc)
Apply a perspective transform to the map.
Definition: evas_map.c:1263

And we free this map, since we messed too much with it and for the last object we want something cleaner.

EVAS_API void evas_map_free(Evas_Map *m)
Free a previously allocated map.
Definition: evas_map.c:745

The last object is actually two. One image, with an image set to it, and one image proxying the first one with evas_object_image_source_set(). This way, the second object will show whatever content its source has. This time we'll be using a map more manually to simulate a simple reflection of the original image.

We know that the reflection object is placed just like the original, so we take a shortcut by just getting the geometry of our to-be-mapped object. We also need to get the image size of the source.

o = evas_object_name_find(ad->canvas, "obj4");
evas_object_geometry_get(o, &x, &y, &w, &h);
evas_object_image_size_get(o, &img_w, &img_h);

For this we'll create a map shaped so that it begins at the base of our image and it expands horizontally as it grows (downwards) in height.

m = evas_map_new(4);
evas_map_point_coord_set(m, 0, x, y + h, 0);
evas_map_point_coord_set(m, 1, x + w, y + h, 0);
evas_map_point_coord_set(m, 2, win_w - 10, win_h - 30, 0);
evas_map_point_coord_set(m, 3, (win_w / 2) + 10, win_h - 30, 0);
EVAS_API void evas_map_point_coord_set(Evas_Map *m, int idx, Evas_Coord x, Evas_Coord y, Evas_Coord z)
Change the map point's coordinate.
Definition: evas_map.c:766

Since the reflection should show the image inverted, we need to map it this way. The first point of the map (top-left) will be mapped to the mapped to the first pixel of the last row. There's no horizontal reflection and we want the full width of the image, but as we map its upper side ww will only take two thirds of the image.

evas_map_point_image_uv_set(m, 0, 0, img_h);
evas_map_point_image_uv_set(m, 1, img_w, img_h);
evas_map_point_image_uv_set(m, 2, img_w, 2 * (img_h / 3));
evas_map_point_image_uv_set(m, 3, 0, 2 * (img_h / 3));

Finally, to fade out our reflection we set the colors for each point in the map. The two at the top need to be visible, but we'll tone them down a bit and make them a bit translucent. The other two will go straight to full transparency. Evas interpolates the colors from one point to the next, so this will make them fade out.

evas_map_point_color_set(m, 0, 200, 200, 200, 150);
evas_map_point_color_set(m, 1, 200, 200, 200, 150);
evas_map_point_color_set(m, 2, 0, 0, 0, 0);
evas_map_point_color_set(m, 3, 0, 0, 0, 0);
EVAS_API void evas_map_point_color_set(Evas_Map *m, int idx, int r, int g, int b, int a)
Set the color of a vertex in the map.
Definition: evas_map.c:822

Close up by freeing the map and do some other things needed to keep stuff moving in our animations and we are done.

ad->frame = (ad->frame + 1) % 60;
return EINA_TRUE;
}

The rest of the program is setup and listening to key events. Nothing that matters within the scope of this example, so we are going to skip it. Refer to it here however to see how everything fits together.