Tizen Native API  4.0
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;

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;
   Evas_Object *o;
   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);

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_map_util_points_color_set(m, r, g, b, a);

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_points_populate_from_object(m, o);
   evas_map_util_rotate(m, 3 * ad->frame, x + (w / 2), y + (h / 2));
   evas_object_map_set(o, m);
   evas_object_map_enable_set(o, EINA_TRUE);

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_map_util_points_populate_from_object_full(m, o, 100);

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, 0, 0, 0);
   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);

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_object_map_set(o, m);
   evas_object_map_enable_set(o, EINA_TRUE);

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, 0, 0, 0);
   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)
     {
        if (evas_map_util_clockwise_get(m))
          evas_object_show(o);
        else
          evas_object_hide(o);
     }
   else
     evas_object_show(o);
   evas_object_map_set(o, m);
   evas_object_map_enable_set(o, EINA_TRUE);

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

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(evas_object_image_source_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);

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_object_map_set(o, m);
   evas_object_map_enable_set(o, EINA_TRUE);

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

   evas_map_free(m);

   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.