evas map: Introduce new API for maps (Efl.Gfx.Map)
authorJean-Philippe Andre <jp.andre@samsung.com>
Wed, 26 Apr 2017 06:11:51 +0000 (15:11 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Thu, 11 May 2017 08:54:00 +0000 (17:54 +0900)
This implements an entirely new API model for Evas Map by relying
on high-level transformations on the object rather than an external
Evas_Map structure that needs to be constantly updated manually.

The implementation relies on Evas_Map.

To rotate an object all you need to do now is
  efl_gfx_map_rotate(obj, 45.0, NULL, 0.5, 0.5);

Or with a C++ syntax:
  obj.rotate(45.0, NULL, 0.5, 0.5);

Or even simply (with default arguments):
  obj.rotate(45.0);

The map transformation functions are:
 - rotate
 - rotate_3d
 - rotate_quat
 - zoom
 - translate (new!)
 - perspective_3d
 - lightning_3d

@feature

14 files changed:
src/bin/elementary/test_evas_mask.c
src/bin/elementary/test_evas_snapshot.c
src/examples/evas/evas-map-aa-eo.c
src/examples/evas/evas-map-utils-eo.c
src/lib/evas/Evas_Legacy.h
src/lib/evas/canvas/efl_canvas_object.eo
src/lib/evas/canvas/efl_gfx_map.c
src/lib/evas/canvas/efl_gfx_map.eo
src/lib/evas/canvas/evas_main.c
src/lib/evas/canvas/evas_map.c
src/lib/evas/canvas/evas_map.h
src/lib/evas/canvas/evas_render.c
src/lib/evas/include/evas_inline.x
src/lib/evas/include/evas_private.h

index a107c01..1cfba27 100644 (file)
@@ -81,18 +81,12 @@ _toggle_map(void *data, const Efl_Event *ev EINA_UNUSED)
 {
    Eo *ly = data;
 
-   if (!efl_gfx_map_enable_get(ly))
+   if (!efl_gfx_map_has(ly))
      {
-        int x, y, w, h;
-        efl_gfx_map_reset(ly);
-        efl_gfx_geometry_get(ly, &x, &y, &w, &h);
-        efl_gfx_map_zoom(ly, 0.8, 0.8, x + w / 2, y + h / 2);
-        efl_gfx_map_enable_set(ly, 1);
-     }
-   else
-     {
-        efl_gfx_map_enable_set(ly, 0);
+        efl_gfx_map_zoom(ly, 0.8, 0.8, NULL, 0.5, 0.5);
+        efl_gfx_map_rotate(ly, 45, NULL, 0.5, 0.5);
      }
+   else efl_gfx_map_reset(ly);
 }
 
 static void
index 2d5db2c..20a872d 100644 (file)
@@ -25,24 +25,6 @@ static const char *filter =
       "print ('Evaluating filter: ' .. input.width .. 'x' .. input.height)"
       ;
 
-static inline void
-_efl_key_int_set(Eo *obj, const char *key, int val)
-{
-   Eina_Value *v = eina_value_new(EINA_VALUE_TYPE_INT);
-   eina_value_set(v, val);
-   efl_key_value_set(obj, key, v);
-}
-
-static inline int
-_efl_key_int_get(Eo *obj, const char *key)
-{
-   Eina_Value *v = efl_key_value_get(obj, key);
-   int val;
-
-   if (!eina_value_get(v, &val)) return 0;
-   return val;
-}
-
 static inline Eo *
 _image_create(Eo *win, const char *path)
 {
@@ -121,46 +103,18 @@ _close_do(void *data, const Efl_Event *ev EINA_UNUSED)
 }
 
 static void
-_map_do(void *data, const Efl_Event *ev EINA_UNUSED)
-{
-   Eo *snap = data;
-   int x, y, w, h;
-
-   // Prevent recursive infinite loop :(
-   static int here = 0;
-   if (here) return;
-   here = 1;
-
-   efl_gfx_map_reset(snap);
-   efl_gfx_geometry_get(snap, &x, &y, &w, &h);
-   efl_gfx_map_zoom(snap, 0.8, 0.8, x + w/2., y + h/2.);
-   efl_gfx_map_rotate(snap, 45., x + w/2., y + h/2.);
-   efl_gfx_map_enable_set(snap, EINA_TRUE);
-
-   here = 0;
-}
-
-static void
 _toggle_map(void *data, const Efl_Event *ev EINA_UNUSED)
 {
    Eo *win = data;
    Eo *snap;
 
    snap = efl_key_wref_get(win, "snap");
-   if (!_efl_key_int_get(snap, "map"))
+   if (!efl_gfx_map_has(snap))
      {
-        _efl_key_int_set(snap, "map", 1);
-        _map_do(snap, NULL);
-        efl_event_callback_add(snap, EFL_GFX_EVENT_RESIZE, _map_do, snap);
-        efl_event_callback_add(snap, EFL_GFX_EVENT_MOVE, _map_do, snap);
-     }
-   else
-     {
-        _efl_key_int_set(snap, "map", 0);
-        efl_event_callback_del(snap, EFL_GFX_EVENT_RESIZE, _map_do, snap);
-        efl_event_callback_del(snap, EFL_GFX_EVENT_MOVE, _map_do, snap);
-        efl_gfx_map_enable_set(snap, EINA_FALSE);
+        efl_gfx_map_zoom(snap, 0.8, 0.8, NULL, 0.5, 0.5);
+        efl_gfx_map_rotate(snap, 20.0, NULL, 0.5, 0.5);
      }
+   else efl_gfx_map_reset(snap);
 }
 
 void
@@ -272,6 +226,4 @@ test_evas_snapshot(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *e
    efl_key_wref_set(win, "grid", grid);
    efl_gfx_size_set(win, 400, 400);
    efl_gfx_visible_set(win, 1);
-
-
 }
index 12bcdfe..5b4c66f 100644 (file)
@@ -58,30 +58,17 @@ static struct exemple_data d =
   EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE };
 
 static void
-update()
+update(void)
 {
-   efl_gfx_map_populate(d.target1, 0);
-
-   efl_gfx_map_point_coord_set(d.target1, 0, d.px1, d.py1, 0);
-   efl_gfx_map_point_coord_set(d.target1, 1, d.px2, d.py2, 0);
-   efl_gfx_map_point_coord_set(d.target1, 2, d.px3, d.py3, 0);
-   efl_gfx_map_point_coord_set(d.target1, 3, d.px4, d.py4, 0);
-
-   efl_gfx_map_point_image_uv_set(d.target1, 0, 0, 0);
-   efl_gfx_map_point_image_uv_set(d.target1, 1, IMAGE_SIZE_W, 0);
-   efl_gfx_map_point_image_uv_set(d.target1, 2, IMAGE_SIZE_W, IMAGE_SIZE_H);
-   efl_gfx_map_point_image_uv_set(d.target1, 3, 0, IMAGE_SIZE_H);
-
-   efl_gfx_map_enable_set(d.target1, EINA_TRUE);
-
-   efl_gfx_map_dup(d.target2, d.target1);
-
-   efl_gfx_map_point_coord_set(d.target2, 0, d.px1 + 400, d.py1, 0);
-   efl_gfx_map_point_coord_set(d.target2, 1, d.px2 + 400, d.py2, 0);
-   efl_gfx_map_point_coord_set(d.target2, 2, d.px3 + 400, d.py3, 0);
-   efl_gfx_map_point_coord_set(d.target2, 3, d.px4 + 400, d.py4, 0);
-
-   efl_gfx_map_enable_set(d.target2, EINA_TRUE);
+   efl_gfx_map_raw_coord_set(d.target1, 0, d.px1, d.py1, 0);
+   efl_gfx_map_raw_coord_set(d.target1, 1, d.px2, d.py2, 0);
+   efl_gfx_map_raw_coord_set(d.target1, 2, d.px3, d.py3, 0);
+   efl_gfx_map_raw_coord_set(d.target1, 3, d.px4, d.py4, 0);
+
+   efl_gfx_map_raw_coord_set(d.target2, 0, d.px1 + 400, d.py1, 0);
+   efl_gfx_map_raw_coord_set(d.target2, 1, d.px2 + 400, d.py2, 0);
+   efl_gfx_map_raw_coord_set(d.target2, 2, d.px3 + 400, d.py3, 0);
+   efl_gfx_map_raw_coord_set(d.target2, 3, d.px4 + 400, d.py4, 0);
 }
 
 static void
index 329bd6c..fdf000e 100644 (file)
@@ -69,96 +69,81 @@ static Eina_Bool
 _anim_cb(void *data)
 {
    App_Data *ad = data;
-   Evas_Object *o, *ref;
-   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);
+   Evas_Object *o;
+   int r, g, b, a, x, y, w, h, f;
+   int win_w, win_h, mx, my;
 
+   f = ad->frame;
    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_output_size_get(ad->canvas, &win_w, &win_h);
 
    o = evas_object_name_find(ad->canvas, "obj1");
-   evas_object_geometry_get(o, &x, &y, &w, &h);
-
-   efl_gfx_map_populate(o, 0);
-   efl_gfx_map_rotate(o, 3 * ad->frame, x + (w / 2), y + (h / 2));
+   efl_gfx_map_reset(o);
+   efl_gfx_map_rotate(o, 3 * f, NULL, 0.5, 0.5);
    efl_gfx_map_smooth_set(o, ad->smooth);
    efl_gfx_map_alpha_set(o, ad->alpha);
    efl_gfx_map_color_set(o, -1, r, g, b, a);
-   efl_gfx_map_enable_set(o, EINA_TRUE);
-   ref = o;
+
 
    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);
-
-   efl_gfx_map_dup(o, ref);
-   efl_gfx_map_populate(o, 100);
-   efl_gfx_map_point_image_uv_set(o, 0, 0, 0);
-   efl_gfx_map_point_image_uv_set(o, 1, img_w, 0);
-   efl_gfx_map_point_image_uv_set(o, 2, img_w, img_h);
-   efl_gfx_map_point_image_uv_set(o, 3, 0, img_h);
-   efl_gfx_map_rotate_3d(o, ad->frame * 6, ad->frame * 6, ad->frame * 6,
-                         x + (w / 3), y + 10, 0);
+   efl_gfx_size_get(o, NULL, &h);
+   efl_gfx_map_reset(o);
+   efl_gfx_map_smooth_set(o, ad->smooth);
+   efl_gfx_map_alpha_set(o, ad->alpha);
+   efl_gfx_map_color_set(o, -1, r, g, b, a);
+   efl_gfx_map_translate(o, 0, 0, 100);
+   efl_gfx_map_rotate_3d(o, f * 6, f * 6, f * 6, NULL, 1./3., 10. / h, 0);
    if (ad->apply_lighting)
-     efl_gfx_map_lightning_3d(o, win_w / 2, win_h / 2, -100,
-                              255, 255, 255, 0, 0, 0);
-   efl_gfx_map_enable_set(o, EINA_TRUE);
+     {
+        efl_gfx_map_lightning_3d(o, ad->canvas, 0.5, 0.5, -100.,
+                                 255, 255, 255, 0, 0, 0);
+     }
 
-   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);
-
-   efl_gfx_map_dup(o, ref);
-   efl_gfx_map_populate_manual(o, x, y + (h / 2), w, h, -20);
-   efl_gfx_map_point_image_uv_set(o, 0, 0, 0);
-   efl_gfx_map_point_image_uv_set(o, 1, img_w, 0);
-   efl_gfx_map_point_image_uv_set(o, 2, img_w, img_h);
-   efl_gfx_map_point_image_uv_set(o, 3, 0, img_h);
-   efl_gfx_map_rotate_3d(o, 20, ad->frame * 6, 0,
-                         x + (w / 2), y + (w / 2), w / 2);
 
+   o = evas_object_name_find(ad->canvas, "obj3");
+   efl_gfx_size_get(o, &w, &h);
+   efl_gfx_map_reset(o);
+   efl_gfx_map_smooth_set(o, ad->smooth);
+   efl_gfx_map_alpha_set(o, ad->alpha);
+   efl_gfx_map_color_set(o, -1, r, g, b, a);
+   efl_gfx_map_translate(o, 0, h/2, -20);
+   efl_gfx_map_rotate_3d(o, 20, f * 6, 0, NULL, 0.5, 0.5, w / 2);
    if (ad->apply_perspective)
-     efl_gfx_map_perspective_3d(o, x + (w / 2), y + (h / 2), 0, 256);
+     efl_gfx_map_perspective_3d(o, NULL, 0.5, 0.5, 0, 256);
    if (ad->apply_lighting)
      {
-        Evas_Coord mx, my;
         evas_pointer_canvas_xy_get(ad->canvas, &mx, &my);
-        efl_gfx_map_lightning_3d(o, mx, my, -256, 255, 255, 255, 0, 0, 0);
+        efl_gfx_map_lightning_3d(o, ad->canvas,
+                                 (double) mx / win_w, (double) my / win_h,
+                                 -256, 255, 255, 255, 0, 0, 0);
      }
    if (ad->backface_culling)
-     {
-        if (efl_gfx_map_clockwise_get(o))
-          evas_object_show(o);
-        else
-          evas_object_hide(o);
-     }
+     efl_gfx_visible_set(o, efl_gfx_map_clockwise_get(o));
    else
-     evas_object_show(o);
-   efl_gfx_map_enable_set(o, EINA_TRUE);
+     efl_gfx_visible_set(o, 1);
+
 
    o = evas_object_name_find(ad->canvas, "obj4");
    efl_gfx_geometry_get(o, &x, &y, &w, &h);
-   efl_gfx_view_size_get(o, &img_w, &img_h);
-
-   efl_gfx_map_dup(o, ref);
-   efl_gfx_map_point_coord_set(o, 0, x, y + h, 0);
-   efl_gfx_map_point_coord_set(o, 1, x + w, y + h, 0);
-   efl_gfx_map_point_coord_set(o, 2, win_w - 10, win_h - 30, 0);
-   efl_gfx_map_point_coord_set(o, 3, (win_w / 2) + 10, win_h - 30, 0);
-   efl_gfx_map_point_image_uv_set(o, 0, 0, img_h);
-   efl_gfx_map_point_image_uv_set(o, 1, img_w, img_h);
-   efl_gfx_map_point_image_uv_set(o, 2, img_w, 2 * (img_h / 3));
-   efl_gfx_map_point_image_uv_set(o, 3, 0, 2 * (img_h / 3));
+   efl_gfx_map_reset(o);
+   efl_gfx_map_smooth_set(o, ad->smooth);
+   efl_gfx_map_alpha_set(o, ad->alpha);
+   efl_gfx_map_raw_coord_set(o, 0, x, y + h, 0);
+   efl_gfx_map_raw_coord_set(o, 1, x + w, y + h, 0);
+   efl_gfx_map_raw_coord_set(o, 2, win_w - 10, win_h - 30, 0);
+   efl_gfx_map_raw_coord_set(o, 3, (win_w / 2) + 10, win_h - 30, 0);
+   efl_gfx_map_uv_set(o, 0, 0, 1);
+   efl_gfx_map_uv_set(o, 1, 1, 1);
+   efl_gfx_map_uv_set(o, 2, 1, 2. / 3.);
+   efl_gfx_map_uv_set(o, 3, 0, 2. / 3.);
    efl_gfx_map_color_set(o, 0, 200, 200, 200, 150);
    efl_gfx_map_color_set(o, 1, 200, 200, 200, 150);
    efl_gfx_map_color_set(o, 2, 0, 0, 0, 0);
    efl_gfx_map_color_set(o, 3, 0, 0, 0, 0);
-   efl_gfx_map_enable_set(o, EINA_TRUE);
+
 
    ad->frame = (ad->frame + 1) % 60;
 
index 673cbdc..1af3be5 100644 (file)
@@ -6908,6 +6908,17 @@ EAPI const Evas_Map *evas_object_map_get(const Evas_Object *obj);
  */
 EAPI void evas_object_map_enable_set(Evas_Object *obj, Eina_Bool enabled);
 
+/**
+ * @brief Whether the map is enabled or not
+ *
+ * @param[in] obj The evas object
+ *
+ * @return The value of @c enabled as passed to evas_object_map_enable_set().
+ *
+ * @see evas_object_map_enable_set
+ */
+EAPI Eina_Bool evas_object_map_enable_get(const Evas_Object *obj);
+
 #include "canvas/efl_gfx_map.eo.legacy.h"
 
 /**
index b2569ce..61ef44e 100644 (file)
@@ -667,7 +667,6 @@ abstract Efl.Canvas.Object (Efl.Object, Efl.Gfx, Efl.Gfx.Stack, Efl.Animator,
       Efl.Gfx.Size.Hint.hint_margin { get; set; }
       Efl.Gfx.Size.Hint.hint_request { get; set; }
       Efl.Gfx.Size.Hint.hint_weight { get; set; }
-      Efl.Gfx.Map.map_enable { get; set; }
       Efl.Input.Interface.seat_event_filter { get; set; }
       Efl.Loop_User.loop { get; }
    }
index 5667a1c..2bc0e70 100644 (file)
 #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 MY_CLASS EFL_GFX_MAP_MIXIN
 
-/* Efl.Gfx.Map implementation - relies on legacy for now */
-// note: cur vs. prev is not handled
+typedef struct _Gfx_Map               Gfx_Map;
+typedef struct _Gfx_Map_Op            Gfx_Map_Op;
+typedef struct _Efl_Gfx_Map_Data      Efl_Gfx_Map_Data;
+typedef enum _Gfx_Map_Op_Type         Gfx_Map_Op_Type;
+
+enum _Gfx_Map_Op_Type {
+   GFX_MAP_ROTATE_2D,
+   GFX_MAP_ROTATE_3D,
+   GFX_MAP_ROTATE_QUAT,
+   GFX_MAP_ZOOM,
+   GFX_MAP_TRANSLATE,
+   GFX_MAP_LIGHTNING_3D,
+   GFX_MAP_PERSPECTIVE_3D,
+};
+
+struct _Gfx_Map_Op {
+   EINA_INLIST;
+
+   Gfx_Map_Op_Type op;
+   union {
+      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;
+      } lightning_3d;
+      struct {
+         double z0, foc;
+      } perspective_3d;
+   };
+   struct {
+      Eo        *eo_obj; // strong or weak ref?
+      double     cx, cy, cz;
+      Eina_Bool  event_cbs;
+      Eina_Bool  is_canvas;
+   } pivot;
+};
+
+struct _Gfx_Map {
+   Gfx_Map_Op *ops;
+
+   struct {
+      double u, v;
+      double x, y, z;
+      uint8_t r, g, b, a;
+   } point[4];
+
+   Eina_Bool alpha;
+   Eina_Bool smooth;
+   Eina_Bool absolute_xy;
+   Eina_Bool event_cbs;
+};
+
+struct _Efl_Gfx_Map_Data {
+   const Gfx_Map *cow;
+};
+
+// ----------------------------------------------------------------------------
+
+static Eina_Cow *gfx_map_cow = NULL;
+static const Gfx_Map gfx_map_cow_default = {
+   NULL,
+   {
+      { 0.0, 0.0, 0.0, 0.0, 0.0, 255, 255, 255, 255 },
+      { 1.0, 0.0, 0.0, 0.0, 0.0, 255, 255, 255, 255 },
+      { 1.0, 1.0, 0.0, 0.0, 0.0, 255, 255, 255, 255 },
+      { 0.0, 1.0, 0.0, 0.0, 0.0, 255, 255, 255, 255 }
+   },
+   EINA_TRUE,
+   EINA_TRUE,
+   EINA_FALSE,
+   EINA_FALSE
+};
+
+#define MAPCOW_BEGIN(_pd) eina_cow_write(gfx_map_cow, (const Eina_Cow_Data**)&(_pd->cow))
+#define MAPCOW_END(_mapcow, _pd) eina_cow_done(gfx_map_cow, (const Eina_Cow_Data**)&(_pd->cow), _mapcow, EINA_TRUE)
+#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(_pivot, eo_obj) : NULL)
+#define PIVOT_UNREF(_pivot) (_pivot ? efl_xunref(_pivot, eo_obj) : NULL)
+
+static inline void _map_ops_clean(Eo *eo_obj, Efl_Gfx_Map_Data *pd);
+
+// ----------------------------------------------------------------------------
+
+void
+_efl_gfx_map_init(void)
+{
+   gfx_map_cow = eina_cow_add("Efl.Gfx.Map", sizeof(Gfx_Map), 8,
+                              &gfx_map_cow_default, EINA_TRUE);
+}
 
-#define MAP_OBJ_CHANGE() do { \
-   _evas_map_calc_map_geometry(eo_obj); \
-   evas_object_change(eo_obj, obj); \
-   obj->changed_map = EINA_TRUE; \
-   } while (0)
+void
+_efl_gfx_map_shutdown(void)
+{
+   eina_cow_del(gfx_map_cow);
+   gfx_map_cow = NULL;
+}
 
-#define MAP_POPULATE_DEFAULT(m, z) \
-   _evas_map_util_points_populate(m, obj->cur->geometry.x, obj->cur->geometry.y, \
-                                  obj->cur->geometry.w, obj->cur->geometry.h, z)
+// ----------------------------------------------------------------------------
 
-static Eina_Bool
-_map_populate(Eo *eo_obj, int z)
+EOLIAN static Efl_Object *
+_efl_gfx_map_efl_object_constructor(Eo *eo_obj, Efl_Gfx_Map_Data *pd)
 {
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
-   Evas_Map *m;
+   eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
+   pd->cow = eina_cow_alloc(gfx_map_cow);
+   return eo_obj;
+}
+
+EOLIAN static void
+_efl_gfx_map_efl_object_destructor(Eo *eo_obj, Efl_Gfx_Map_Data *pd)
+{
+   _map_ops_clean(eo_obj, pd);
+   eina_cow_free(gfx_map_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;
+
+   obj->gfx_map_update = EINA_TRUE;
+}
 
-   if (!obj->map->cur.map)
+static inline void
+_map_dirty(Eo *eo_obj, Efl_Gfx_Map_Data *pd, Eina_Bool reset)
+{
+   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
+   Gfx_Map_Op *op;
+
+   obj->gfx_map_has = EINA_TRUE;
+   obj->gfx_map_update |= !reset;
+   _evas_object_map_enable_set(eo_obj, obj, !reset);
+   evas_object_change(eo_obj, obj);
+
+   if (!reset && !pd->cow->absolute_xy)
      {
-        m = _evas_map_new(4, EINA_TRUE);
-        if (!m) return EINA_FALSE;
-        MAP_POPULATE_DEFAULT(m, z);
-        evas_object_map_set(eo_obj, m);
-        evas_map_free(m);
+        if (!pd->cow->event_cbs)
+          {
+             MAPCOW_WRITE(pd, event_cbs, EINA_TRUE);
+             efl_event_callback_add(eo_obj, EFL_GFX_EVENT_MOVE, _geometry_changed_cb, obj);
+             efl_event_callback_add(eo_obj, EFL_GFX_EVENT_RESIZE, _geometry_changed_cb, obj);
+          }
+        EINA_INLIST_FOREACH(pd->cow->ops, op)
+          {
+             if (op->pivot.eo_obj && !op->pivot.event_cbs)
+               {
+                  op->pivot.event_cbs = EINA_TRUE;
+                  if (!op->pivot.is_canvas)
+                    efl_event_callback_add(op->pivot.eo_obj, EFL_GFX_EVENT_MOVE, _geometry_changed_cb, obj);
+                  efl_event_callback_add(op->pivot.eo_obj, EFL_GFX_EVENT_RESIZE, _geometry_changed_cb, obj);
+               }
+          }
      }
+}
+
+static void
+_map_update(Eo *eo_obj, Efl_Gfx_Map_Data *pd)
+{
+   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
+   Evas_Map *m = NULL;
+   int imw, imh;
+
+   if (!obj->gfx_map_update) return;
+   if (pd->cow == &gfx_map_cow_default)
+     goto end;
+
+   m = evas_map_new(4);
+   m->alpha = pd->cow->alpha;
+   m->smooth = pd->cow->smooth;
+   m->move_sync.enabled = EINA_FALSE;
+
+   if (pd->cow->absolute_xy)
+     {
+        for (int k = 0; k < 4; k++)
+          {
+             Evas_Map_Point *p = &(m->points[k]);
+             p->px = p->x = pd->cow->point[k].x;
+             p->py = p->y = pd->cow->point[k].y;
+          }
+     }
+   else
+     {
+        _evas_map_util_points_populate(m, obj->cur->geometry.x, obj->cur->geometry.y,
+                                       obj->cur->geometry.w, obj->cur->geometry.h, 0);
+     }
+
+   if (efl_isa(eo_obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS))
+     efl_gfx_view_size_get(eo_obj, &imw, &imh);
    else
+     efl_gfx_size_get(eo_obj, &imw, &imh);
+
+   for (int k = 0; k < 4; k++)
      {
-        m = (Evas_Map *) obj->map->cur.map;
-        MAP_POPULATE_DEFAULT(m, z);
-        MAP_OBJ_CHANGE();
+        Evas_Map_Point *p = &(m->points[k]);
+        p->u = pd->cow->point[k].u * imw;
+        p->v = pd->cow->point[k].v * imh;
+        p->z = pd->cow->point[k].z;
+        p->r = pd->cow->point[k].r;
+        p->g = pd->cow->point[k].g;
+        p->b = pd->cow->point[k].b;
+        p->a = pd->cow->point[k].a;
      }
 
-   return EINA_TRUE;
+   if (!pd->cow->absolute_xy)
+     {
+        Gfx_Map_Op *op;
+
+        EINA_INLIST_FOREACH(pd->cow->ops, op)
+          {
+             int px = 0, py = 0, pw = 1, ph = 1;
+             double cx, cy, cz;
+             Efl_Gfx *pivot;
+
+             pivot = op->pivot.eo_obj ?: eo_obj;
+             if (!op->pivot.is_canvas)
+               {
+                  efl_gfx_geometry_get(pivot, &px, &py, &pw, &ph);
+               }
+             else
+               {
+                  // Note: pivot can not be an Evas when using pure EO API
+                  if (efl_isa(pivot, EVAS_CANVAS_CLASS))
+                    evas_output_size_get(pivot, &pw, &ph);
+                  else
+                    efl_gfx_size_get(pivot, &pw, &ph);
+               }
+             cx = (double) px + (double) pw * op->pivot.cx;
+             cy = (double) py + (double) ph * op->pivot.cy;
+             cz = op->pivot.cz;
+
+             switch (op->op)
+               {
+                case GFX_MAP_ROTATE_2D:
+                  _map_util_rotate(m, op->rotate_2d.degrees, cx, cy);
+                  break;
+                case GFX_MAP_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_MAP_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_MAP_ZOOM:
+                  _map_util_zoom(m, op->zoom.zx, op->zoom.zy, cx, cy);
+                  break;
+                case GFX_MAP_TRANSLATE:
+                  _map_util_translate(m, op->translate.dx, op->translate.dy,
+                                      op->translate.dz);
+                  break;
+                case GFX_MAP_LIGHTNING_3D:
+                  _map_util_3d_lighting(m, cx, cy, cz, op->lightning_3d.lr,
+                                        op->lightning_3d.lg, op->lightning_3d.lb,
+                                        op->lightning_3d.ar, op->lightning_3d.ag,
+                                        op->lightning_3d.ab);
+                  break;
+                case GFX_MAP_PERSPECTIVE_3D:
+                  _map_util_3d_perspective(m, cx, cy, op->perspective_3d.z0,
+                                           op->perspective_3d.foc);
+                  break;
+               }
+          }
+     }
+   else if (pd->cow->ops)
+     {
+        ERR("Map absolute coordinates override all high-level transformations, "
+            "such as rotate, perspective, etc...");
+     }
+
+end:
+   evas_object_map_set(eo_obj, m);
+   if (m) evas_map_free(m);
+   obj->gfx_map_update = EINA_FALSE;
 }
 
-EOLIAN static void
-_efl_gfx_map_map_reset(Eo *eo_obj, void *_pd EINA_UNUSED)
+void
+_efl_gfx_map_update(Eo *eo_obj)
 {
-   evas_object_map_set(eo_obj, NULL);
+   Efl_Gfx_Map_Data *pd = efl_data_scope_get(eo_obj, MY_CLASS);
+
+   _map_update(eo_obj, pd);
 }
 
-EOLIAN static Eina_Bool
-_efl_gfx_map_map_clockwise_get(Eo *eo_obj, void *_pd EINA_UNUSED)
+static inline void
+_map_ops_clean(Eo *eo_obj, Efl_Gfx_Map_Data *pd)
 {
-   return evas_map_util_clockwise_get((Evas_Map *) evas_object_map_get(eo_obj));
+   if (pd->cow->ops)
+     {
+        Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
+        Gfx_Map_Op *op;
+        Gfx_Map *mcow;
+
+        mcow = MAPCOW_BEGIN(pd);
+        EINA_INLIST_FREE(mcow->ops, op)
+          {
+             EINA_INLIST_REMOVE(mcow->ops, op);
+             if (op->pivot.event_cbs)
+               {
+                  op->pivot.event_cbs = EINA_FALSE;
+                  if (!op->pivot.is_canvas)
+                    efl_event_callback_del(op->pivot.eo_obj, EFL_GFX_EVENT_MOVE, _geometry_changed_cb, obj);
+                  efl_event_callback_del(op->pivot.eo_obj, EFL_GFX_EVENT_RESIZE, _geometry_changed_cb, obj);
+               }
+             PIVOT_UNREF(op->pivot.eo_obj);
+          }
+        MAPCOW_END(mcow, pd);
+     }
+}
+
+EOLIAN Eina_Bool
+_efl_gfx_map_map_has(Eo *eo_obj EINA_UNUSED, Efl_Gfx_Map_Data *pd EINA_UNUSED)
+{
+   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
+
+   if (!obj->map->cur.usemap) return EINA_FALSE;
+   if (pd->cow == &gfx_map_cow_default) return EINA_FALSE;
+   if (pd->cow->ops) return EINA_TRUE;
+   if (memcmp(&pd->cow->point, &gfx_map_cow_default.point, sizeof(pd->cow->point)))
+     return EINA_TRUE;
+   if (pd->cow->absolute_xy) return EINA_TRUE;
+   return EINA_FALSE;
 }
 
 EOLIAN static void
-_efl_gfx_map_map_smooth_set(Eo *eo_obj, void *_pd EINA_UNUSED, Eina_Bool smooth)
+_efl_gfx_map_map_reset(Eo *eo_obj, Efl_Gfx_Map_Data *pd)
 {
    Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
-   Evas_Map *m;
+   Eina_Bool alpha, smooth;
 
-   if (!obj->map->cur.map)
+   alpha = pd->cow->alpha;
+   smooth = pd->cow->smooth;
+   _map_ops_clean(eo_obj, pd);
+   if (pd->cow->event_cbs)
      {
-        if (smooth) return;
-        if (!_map_populate(eo_obj, 0))
-          return;
+        efl_event_callback_del(eo_obj, EFL_GFX_EVENT_MOVE, _geometry_changed_cb, obj);
+        efl_event_callback_del(eo_obj, EFL_GFX_EVENT_RESIZE, _geometry_changed_cb, obj);
      }
 
-   m = (Evas_Map *) obj->map->cur.map;
-   m->smooth = smooth;
-   MAP_OBJ_CHANGE();
+   eina_cow_memcpy(gfx_map_cow, (const Eina_Cow_Data * const *) &pd->cow,
+                   (const Eina_Cow_Data *) &gfx_map_cow_default);
+   _map_dirty(eo_obj, pd, EINA_TRUE);
+   MAPCOW_WRITE(pd, alpha, alpha);
+   MAPCOW_WRITE(pd, smooth, smooth);
+   obj->gfx_map_has = EINA_FALSE;
 }
 
 EOLIAN static Eina_Bool
-_efl_gfx_map_map_smooth_get(Eo *eo_obj, void *_pd EINA_UNUSED)
+_efl_gfx_map_map_clockwise_get(Eo *eo_obj, Efl_Gfx_Map_Data *pd)
 {
-   const Evas_Map *om = evas_object_map_get(eo_obj);
-   return om ? om->smooth : EINA_TRUE;
+   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_TRUE);
+
+   _map_update(eo_obj, pd);
+   if (!obj->map->cur.map) return EINA_TRUE;
+   return evas_map_util_clockwise_get(obj->map->cur.map);
 }
 
 EOLIAN static void
-_efl_gfx_map_map_alpha_set(Eo *eo_obj, void *_pd EINA_UNUSED, Eina_Bool alpha)
+_efl_gfx_map_map_smooth_set(Eo *eo_obj, Efl_Gfx_Map_Data *pd, Eina_Bool smooth)
 {
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
-   Evas_Map *m;
+   if (pd->cow->smooth == smooth) return;
 
-   if (!obj->map->cur.map)
-     {
-        if (alpha) return;
-        if (!_map_populate(eo_obj, 0))
-          return;
-     }
+   MAPCOW_WRITE(pd, smooth, smooth);
 
-   m = (Evas_Map *) obj->map->cur.map;
-   m->alpha = alpha;
-   MAP_OBJ_CHANGE();
+   _map_dirty(eo_obj, pd, EINA_FALSE);
 }
 
 EOLIAN static Eina_Bool
-_efl_gfx_map_map_alpha_get(Eo *eo_obj, void *_pd EINA_UNUSED)
+_efl_gfx_map_map_smooth_get(Eo *eo_obj EINA_UNUSED, Efl_Gfx_Map_Data *pd)
 {
-   const Evas_Map *om = evas_object_map_get(eo_obj);
-   return om ? om->alpha : EINA_TRUE;
+   return pd->cow->smooth;
 }
 
 EOLIAN static void
-_efl_gfx_map_map_point_coord_set(Eo *eo_obj, void *_pd EINA_UNUSED, int idx, double x, double y, double z)
+_efl_gfx_map_map_alpha_set(Eo *eo_obj, Efl_Gfx_Map_Data *pd, Eina_Bool alpha)
 {
-   EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < 4));
+   if (pd->cow->alpha == alpha) return;
 
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
-   Evas_Map *m;
+   MAPCOW_WRITE(pd, alpha, alpha);
 
-   if (!obj->map->cur.map && !_map_populate(eo_obj, 0))
-     return;
-
-   m = (Evas_Map *) obj->map->cur.map;
-   _map_point_coord_set(m, idx, x, y, z);
-   MAP_OBJ_CHANGE();
+   _map_dirty(eo_obj, pd, EINA_FALSE);
 }
 
-EOLIAN static void
-_efl_gfx_map_map_point_coord_get(Eo *eo_obj, void *_pd EINA_UNUSED, int idx, double *x, double *y, double *z)
+EOLIAN static Eina_Bool
+_efl_gfx_map_map_alpha_get(Eo *eo_obj EINA_UNUSED, Efl_Gfx_Map_Data *pd)
 {
-   const Evas_Map *om = evas_object_map_get(eo_obj);
-   _map_point_coord_get(om, idx, x, y, z);
+   return pd->cow->alpha;
 }
 
 EOLIAN static void
-_efl_gfx_map_map_point_image_uv_set(Eo *eo_obj, void *_pd EINA_UNUSED, int idx, double u, double v)
+_efl_gfx_map_map_raw_coord_set(Eo *eo_obj, Efl_Gfx_Map_Data *pd,
+                               int idx, double x, double y, double z)
 {
-   EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < 4));
+   Gfx_Map *mcow;
 
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
-   Evas_Map *m;
+   EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < 4));
 
-   if (!obj->map->cur.map && !_map_populate(eo_obj, 0))
+   if (EINA_DBL_EQ(pd->cow->point[idx].x, x) &&
+       EINA_DBL_EQ(pd->cow->point[idx].y, y) &&
+       EINA_DBL_EQ(pd->cow->point[idx].z, z) &&
+       pd->cow->absolute_xy)
      return;
 
-   m = (Evas_Map *) obj->map->cur.map;
-   evas_map_point_image_uv_set(m, idx, u, v);
-   MAP_OBJ_CHANGE();
+   mcow = MAPCOW_BEGIN(pd);
+   mcow->point[idx].x = x;
+   mcow->point[idx].y = y;
+   mcow->point[idx].x = x;
+   mcow->absolute_xy = EINA_TRUE;
+   MAPCOW_END(mcow, pd);
+
+   _map_dirty(eo_obj, pd, EINA_FALSE);
 }
 
 EOLIAN static void
-_efl_gfx_map_map_point_image_uv_get(Eo *eo_obj, void *_pd EINA_UNUSED, int idx, double *u, double *v)
+_efl_gfx_map_map_raw_coord_get(Eo *eo_obj, Efl_Gfx_Map_Data *pd,
+                               int idx, double *x, double *y, double *z)
 {
-   const Evas_Map *om = evas_object_map_get(eo_obj);
+   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
+   const Evas_Map *m = obj->map->cur.map;
+
+   EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < 4));
 
-   evas_map_point_image_uv_get(om, idx, u, v);
+   if (pd->cow->absolute_xy)
+     {
+        if (x) *x = pd->cow->point[idx].x;
+        if (y) *y = pd->cow->point[idx].y;
+        if (z) *z = pd->cow->point[idx].z;
+        return;
+     }
+
+   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_map_map_color_set(Eo *eo_obj, void *_pd EINA_UNUSED, int idx, int r, int g, int b, int a)
+_efl_gfx_map_map_uv_set(Eo *eo_obj, Efl_Gfx_Map_Data *pd,
+                        int idx, double u, double v)
 {
-   EINA_SAFETY_ON_FALSE_RETURN((idx >= -1) && (idx < 4));
+   Gfx_Map *mcow;
 
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
-   Evas_Map *m;
+   EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < 4));
 
-   if (!obj->map->cur.map && !_map_populate(eo_obj, 0))
+   if (EINA_DBL_EQ(pd->cow->point[idx].u, u) &&
+       EINA_DBL_EQ(pd->cow->point[idx].v, v))
      return;
 
-   m = (Evas_Map *) obj->map->cur.map;
-   if (idx == -1)
-     evas_map_util_points_color_set(m, r, g, b, a);
-   else
-     evas_map_point_color_set(m, idx, r, g, b, a);
-   MAP_OBJ_CHANGE();
+   mcow = MAPCOW_BEGIN(pd);
+   mcow->point[idx].u = CLAMP(0.0, u, 1.0);
+   mcow->point[idx].v = CLAMP(0.0, v, 1.0);
+   MAPCOW_END(mcow, pd);
+
+   _map_dirty(eo_obj, pd, EINA_FALSE);
 }
 
 EOLIAN static void
-_efl_gfx_map_map_color_get(Eo *eo_obj, void *_pd EINA_UNUSED, int idx, int *r, int *g, int *b, int *a)
+_efl_gfx_map_map_uv_get(Eo *eo_obj EINA_UNUSED, Efl_Gfx_Map_Data *pd,
+                        int idx, double *u, double *v)
 {
-   const Evas_Map *om = evas_object_map_get(eo_obj);
+   EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < 4));
 
-   evas_map_point_color_get(om, idx, r, g, b, a);
+   if (u) *u = pd->cow->point[idx].u;
+   if (v) *v = pd->cow->point[idx].v;
 }
 
 EOLIAN static void
-_efl_gfx_map_map_move_sync_set(Eo *eo_obj, void *_pd EINA_UNUSED, Eina_Bool enable)
+_efl_gfx_map_map_color_set(Eo *eo_obj, Efl_Gfx_Map_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 *m;
+   int kmin = 0, kmax = 3;
+   Gfx_Map *mcow;
+
+   EINA_SAFETY_ON_FALSE_RETURN((idx >= -1) && (idx < 4));
+
+   if ((idx != -1) &&
+       (pd->cow->point[idx].r == r) && (pd->cow->point[idx].g == g) &&
+       (pd->cow->point[idx].b == b) && (pd->cow->point[idx].a == a))
+     return;
+
+   if (idx >= 0)
+     kmin = kmax = idx;
 
-   if (!obj->map->cur.map)
+   mcow = MAPCOW_BEGIN(pd);
+   for (int k = kmin; k <= kmax; k++)
      {
-        if (enable) return;
-        if (!_map_populate(eo_obj, 0))
-          return;
+        mcow->point[k].r = r;
+        mcow->point[k].g = g;
+        mcow->point[k].b = b;
+        mcow->point[k].a = a;
      }
+   MAPCOW_END(mcow, pd);
 
-   m = (Evas_Map *) obj->map->cur.map;
-   m->move_sync.enabled = enable;
-   MAP_OBJ_CHANGE();
+   _map_dirty(eo_obj, pd, EINA_FALSE);
 }
 
-EOLIAN static Eina_Bool
-_efl_gfx_map_map_move_sync_get(Eo *eo_obj, void *_pd EINA_UNUSED)
+EOLIAN static void
+_efl_gfx_map_map_color_get(Eo *eo_obj EINA_UNUSED, Efl_Gfx_Map_Data *pd,
+                           int idx, int *r, int *g, int *b, int *a)
 {
-   const Evas_Map *om = evas_object_map_get(eo_obj);
+   EINA_SAFETY_ON_FALSE_RETURN((idx >= 0) && (idx < 4));
 
-   return om ? om->move_sync.enabled : EINA_TRUE;
+   if (r) *r = pd->cow->point[idx].r;
+   if (g) *g = pd->cow->point[idx].g;
+   if (b) *b = pd->cow->point[idx].b;
+   if (a) *a = pd->cow->point[idx].a;
 }
 
-EOLIAN static Eina_Bool
-_efl_gfx_map_map_rotate(Eo *eo_obj, void *_pd EINA_UNUSED, double degrees, double cx, double cy)
+static Gfx_Map_Op *
+_gfx_map_op_add(Eo *eo_obj, Efl_Gfx_Map_Data *pd, Gfx_Map_Op_Type type,
+                Efl_Gfx *pivot, double cx, double cy, double cz)
 {
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
-   Evas_Map *m;
+   Gfx_Map_Op *op;
+   Gfx_Map *mcow;
 
-   if (!obj->map->cur.map)
-     {
-        if (!_map_populate(eo_obj, 0))
-          return EINA_FALSE;
-     }
+   op = calloc(1, sizeof(*op));
+   if (!op) return NULL;
 
-   m = (Evas_Map *) obj->map->cur.map;
-   _map_util_rotate(m, degrees, cx, cy);
-   MAP_OBJ_CHANGE();
+   if (pivot == eo_obj)
+     pivot = NULL;
 
-   return EINA_TRUE;
-}
+   op->op = type;
+   op->pivot.eo_obj = PIVOT_REF(pivot);
+   op->pivot.cx = cx;
+   op->pivot.cy = cy;
+   op->pivot.cz = cz;
 
-EOLIAN static Eina_Bool
-_efl_gfx_map_map_zoom(Eo *eo_obj, void *_pd EINA_UNUSED, double zoomx, double zoomy, double cx, double cy)
-{
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
-   Evas_Map *m;
+   if (pivot && efl_isa(pivot, EFL_CANVAS_INTERFACE))
+     op->pivot.is_canvas = EINA_TRUE;
 
-   if (!obj->map->cur.map)
-     {
-        if (!_map_populate(eo_obj, 0))
-          return EINA_FALSE;
-     }
+   mcow = MAPCOW_BEGIN(pd);
+   EINA_INLIST_APPEND(mcow->ops, op);
+   MAPCOW_END(mcow, pd);
 
-   m = (Evas_Map *) obj->map->cur.map;
-   _map_util_zoom(m, zoomx, zoomy, cx, cy);
-   MAP_OBJ_CHANGE();
+   _map_dirty(eo_obj, pd, EINA_FALSE);
 
-   return EINA_TRUE;
+   return op;
 }
 
-EOLIAN static Eina_Bool
-_efl_gfx_map_map_rotate_3d(Eo *eo_obj, void *_pd EINA_UNUSED, double dx, double dy, double dz, double cx, double cy, double cz)
+EOLIAN static void
+_efl_gfx_map_rotate(Eo *eo_obj, Efl_Gfx_Map_Data *pd,
+                    double degrees, Efl_Gfx *pivot, double cx, double cy)
 {
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
-   Evas_Map *m;
+   Gfx_Map_Op *op;
 
-   if (!obj->map->cur.map)
-     {
-        if (!_map_populate(eo_obj, 0))
-          return EINA_FALSE;
-     }
+   op = _gfx_map_op_add(eo_obj, pd, GFX_MAP_ROTATE_2D, pivot, cx, cy, 0);
+   if (!op) return;
+
+   op->rotate_2d.degrees = degrees;
+}
 
-   m = (Evas_Map *) obj->map->cur.map;
-   _map_util_3d_rotate(m, dx, dy, dz, cx, cy, cz);
-   MAP_OBJ_CHANGE();
+EOLIAN static void
+_efl_gfx_map_rotate_3d(Eo *eo_obj, Efl_Gfx_Map_Data *pd,
+                       double dx, double dy, double dz,
+                       Efl_Gfx *pivot, double cx, double cy, double cz)
+{
+   Gfx_Map_Op *op;
 
-   return EINA_TRUE;
+   op = _gfx_map_op_add(eo_obj, pd, GFX_MAP_ROTATE_3D, pivot, cx, cy, cz);
+   if (!op) return;
+
+   op->rotate_3d.dx = dx;
+   op->rotate_3d.dy = dy;
+   op->rotate_3d.dz = dz;
 }
 
-EOLIAN static Eina_Bool
-_efl_gfx_map_map_quat_rotate(Eo *eo_obj, void *_pd EINA_UNUSED, double qx, double qy, double qz, double qw, double cx, double cy, double cz)
+EOLIAN static void
+_efl_gfx_map_rotate_quat(Eo *eo_obj, Efl_Gfx_Map_Data *pd,
+                         double qx, double qy, double qz, double qw,
+                         Efl_Gfx *pivot, double cx, double cy, double cz)
 {
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
-   Evas_Map *m;
+   Gfx_Map_Op *op;
 
-   if (!obj->map->cur.map)
-     {
-        if (!_map_populate(eo_obj, 0))
-          return EINA_FALSE;
-     }
+   op = _gfx_map_op_add(eo_obj, pd, GFX_MAP_ROTATE_QUAT, pivot, cx, cy, cz);
+   if (!op) return;
+
+   op->rotate_quat.qx = qx;
+   op->rotate_quat.qy = qy;
+   op->rotate_quat.qz = qz;
+   op->rotate_quat.qw = qw;
+}
 
-   m = (Evas_Map *) obj->map->cur.map;
-   evas_map_util_quat_rotate(m, qx, qy, qz, qw, cx, cy, cz);
-   MAP_OBJ_CHANGE();
+EOLIAN static void
+_efl_gfx_map_zoom(Eo *eo_obj, Efl_Gfx_Map_Data *pd,
+                  double zoomx, double zoomy,
+                  Efl_Gfx *pivot, double cx, double cy)
+{
+   Gfx_Map_Op *op;
 
-   return EINA_TRUE;
+   op = _gfx_map_op_add(eo_obj, pd, GFX_MAP_ZOOM, pivot, cx, cy, 0);
+   if (!op) return;
+
+   op->zoom.zx = zoomx;
+   op->zoom.zy = zoomy;
 }
 
-EOLIAN static Eina_Bool
-_efl_gfx_map_map_lightning_3d(Eo *eo_obj, void *_pd EINA_UNUSED, double lx, double ly, double lz, int lr, int lg, int lb, int ar, int ag, int ab)
+EOLIAN static void
+_efl_gfx_map_translate(Eo *eo_obj, Efl_Gfx_Map_Data *pd,
+                       double dx, double dy, double dz)
 {
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
-   Evas_Map *m;
+   Gfx_Map_Op *op;
 
-   if (!obj->map->cur.map)
-     {
-        if (!_map_populate(eo_obj, 0))
-          return EINA_FALSE;
-     }
+   op = _gfx_map_op_add(eo_obj, pd, GFX_MAP_TRANSLATE, NULL, 0, 0, 0);
+   if (!op) return;
+
+   op->translate.dx = dx;
+   op->translate.dy = dy;
+   op->translate.dz = dz;
+}
+
+EOLIAN static void
+_efl_gfx_map_lightning_3d(Eo *eo_obj, Efl_Gfx_Map_Data *pd,
+                          Efl_Gfx *pivot, double lx, double ly, double lz,
+                          int lr, int lg, int lb, int ar, int ag, int ab)
+{
+   Gfx_Map_Op *op;
 
-   m = (Evas_Map *) obj->map->cur.map;
-   _map_util_3d_lighting(m, lx, ly, lz, lr, lg, lb, ar, ag, ab);
-   MAP_OBJ_CHANGE();
+   op = _gfx_map_op_add(eo_obj, pd, GFX_MAP_LIGHTNING_3D, pivot, lx, ly, lz);
+   if (!op) return;
 
-   return EINA_TRUE;
+   op->lightning_3d.lr = lr;
+   op->lightning_3d.lg = lg;
+   op->lightning_3d.lb = lb;
+   op->lightning_3d.ar = ar;
+   op->lightning_3d.ag = ag;
+   op->lightning_3d.ab = ab;
 }
 
-EOLIAN static Eina_Bool
-_efl_gfx_map_map_perspective_3d(Eo *eo_obj, void *_pd EINA_UNUSED, double px, double py, double z0, double foc)
+EOLIAN static void
+_efl_gfx_map_perspective_3d(Eo *eo_obj, Efl_Gfx_Map_Data *pd,
+                            Efl_Gfx *pivot, double px, double py,
+                            double z0, double foc)
 {
-   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
-   Evas_Map *m;
+   Gfx_Map_Op *op;
 
-   if (!obj->map->cur.map)
+   if (foc <= 0.0)
      {
-        if (!_map_populate(eo_obj, 0))
-          return EINA_FALSE;
+        ERR("Focal length must be greater than 0!");
+        return;
      }
 
-   m = (Evas_Map *) obj->map->cur.map;
-   _map_util_3d_perspective(m, px, py, z0, foc);
-   MAP_OBJ_CHANGE();
+   op = _gfx_map_op_add(eo_obj, pd, GFX_MAP_PERSPECTIVE_3D, pivot, px, py, 0);
+   if (!op) return;
 
-   return EINA_TRUE;
-}
-
-EOLIAN static Eina_Bool
-_efl_gfx_map_map_dup(Eo *eo_obj, void *_pd EINA_UNUSED, const Efl_Gfx_Map *other)
-{
-   evas_object_map_set(eo_obj, evas_object_map_get(other));
-   return EINA_TRUE;
+   op->perspective_3d.z0 = z0;
+   op->perspective_3d.foc = foc;
 }
 
 #include "canvas/efl_gfx_map.eo.c"
index 720a972..15f7449 100644 (file)
@@ -9,55 +9,37 @@ mixin Efl.Gfx.Map (Efl.Interface, Efl.Object)
      positioning at target. This allows rotation, perspective, scale and
      lots of other effects, depending on the map that is used.
 
-     Each map point may carry a multiplier color. If properly
-     calculated, these can do shading effects on the object, producing
-     3D effects.
+     Each map point may carry a multiplier color. If properly calculated,
+     these can do shading effects on the object, producing 3D effects.
 
      At the moment of writing, maps can only have 4 points (no more, no less).
 
-     Note: For now this mixin is only compatible with $Efl.Canvas.Object and
-     shouldn't be used anywhere else.
+     @since 1.20
    ]]
-   data: null;
    methods {
-      @property map_enable @pure_virtual {
-         [[Whether map transformation is enabled on this object.
+      map_has {
+         [[Read-only property indicating whether an object is mapped.
 
-           The default map enable state is off ($false). The other
-           properties and methods in this class have no effect until
-           this property is enabled.
+           This will be $true if any transformation is applied to this object.
          ]]
-         set {
-            [[Enable or disable the use of map for this object. On
-              enable, the object geometry will be saved, and the new
-              geometry will change (position and size) to reflect the
-              map geometry set.
-            ]]
-         }
-         get {
-            legacy: evas_object_map_enable_get;
-         }
-         values {
-            enabled: bool; [[Enabled state.]]
-         }
+         return: bool; [[$true if the object is mapped.]]
       }
       map_reset {
          [[Resets the map transformation to its default state.
 
            This will reset all transformations to identity, meaning the points'
            colors, positions and UV coordinates will be reset to their default
-           values. This does not reset the @.map_enable flag.
-
-           @since 1.20
+           values. @.map_has will then return $false. This function will
+           not modify the values of @.map_smooth or @.map_alpha.
          ]]
       }
       @property map_clockwise {
          [[Clockwise state of a map (read-only).
 
            This determines if the output points (X and Y. Z is not used) are
-           clockwise or counter-clockwise. This can be used for "back-face culling". This
-           is where you hide objects that "face away" from you. In this case objects
-           that are not clockwise.
+           clockwise or counter-clockwise. This can be used for "back-face
+           culling". This is where you hide objects that "face away" from you.
+           In this case objects that are not clockwise.
          ]]
          get {}
          values {
@@ -78,18 +60,22 @@ mixin Efl.Gfx.Map (Efl.Interface, Efl.Object)
       @property map_alpha {
          [[Alpha flag for map rendering.
 
-           This sets alpha flag for map rendering. If the object is a type that has
-           its own alpha settings, then this will take precedence. Only image objects
-           have this currently ($Efl.Canvas.Image and its friends).
-           Setting this off stops alpha blending of the map area, and is
-           useful if you know the object and/or all sub-objects is 100% solid.
+           This sets alpha flag for map rendering. If the object is a type that
+           has its own alpha settings, then this will take precedence. Only
+           image objects support this currently ($Efl.Canvas.Image and its
+           friends). Setting this off stops alpha blending of the map area,
+           and is useful if you know the object and/or all sub-objects is 100%
+           solid.
+
+           Note that this may conflict with @.map_smooth depending on which
+           algorithm is used for anti-aliasing.
          ]]
          values {
             alpha: bool; [[$true by default.]]
          }
       }
-      @property map_point_coord {
-         [[Map point's coordinate.
+      @property map_raw_coord {
+         [[A point's absolute coordinate on the canvas.
 
            This sets/gets the fixed point's coordinate in the map. Note that points
            describe the outline of a quadrangle and are ordered either clockwise
@@ -105,31 +91,39 @@ mixin Efl.Gfx.Map (Efl.Interface, Efl.Object)
 
            Remember all coordinates are canvas global ones like with move and resize
            in the canvas.
+
+           This function should rarely be used as it overrides any other
+           transformation set. This property can be read to get the 4 points
+           positions on the canvas, or set to manually place them.
          ]]
          keys {
             idx: int; [[ID of the point, from 0 to 3 (included).]]
          }
          values {
-            x: double; [[Point X Coordinate.]]
-            y: double; [[Point Y Coordinate.]]
-            z: double; [[Point Z Coordinate hint (pre-perspective transform).]]
+            x: double; [[Point X coordinate in absolute pixel coordinates.]]
+            y: double; [[Point Y coordinate in absolute pixel coordinates.]]
+            z: double; [[Point Z coordinate hint (pre-perspective transform).]]
          }
       }
-      @property map_point_image_uv {
+      @property map_uv {
          [[Map point's U and V texture source point.
 
-           This sets/gets the U and V coordinates for the point. This determines which
-           coordinate in the source image is mapped to the given point, much like
-           OpenGL and textures. Notes that these points do select the pixel, but
-           are double floating point values to allow for accuracy and sub-pixel
-           selection.
+           This sets/gets the U and V coordinates for the point. This determines
+           which coordinate in the source image is mapped to the given point,
+           much like OpenGL and textures. Valid values range from 0.0 to 1.0.
+
+           By default the points are set in a clockwise order, as such:
+           - 0: top-left, i.e. (0.0, 0.0),
+           - 1: top-right, i.e. (1.0, 0.0),
+           - 2: bottom-right, i.e. (1.0, 1.0),
+           - 3: bottom-left, i.e. (0.0, 1.0).
          ]]
          keys {
             idx: int; [[ID of the point, from 0 to 3 (included).]]
          }
          values {
-            u: double; [[X coordinate within the image/texture source.]]
-            v: double; [[Y coordinate within the image/texture source.]]
+            u: double; [[Relative X coordinate within the image, from 0 to 1.]]
+            v: double; [[Relative Y coordinate within the image, from 0 to 1.]]
          }
       }
       @property map_color {
@@ -155,102 +149,131 @@ mixin Efl.Gfx.Map (Efl.Interface, Efl.Object)
             a: int; [[Alpha (0 - 255)]]
          }
       }
-      @property map_move_sync {
-         [[Status of object move synchronization for map rendering.
+      // FIXME: pivot & center need to be optional, but double(0.5) doesn't work!
+      rotate {
+         [[Apply a rotation to the object.
 
-           If the flag is set as enabled, the map will be moved as the object
-           is moved.
-         ]]
-         values {
-            enable: bool; [[$true by default.]]
-         }
-      }
-      map_rotate {
-         [[Change the map to apply the given rotation.
-
-           This rotates the indicated map's coordinates around the center coordinate
-           given by $cx and $cy as the rotation center. The points will have their
-           X and Y coordinates rotated clockwise by $degrees degrees (360.0 is a
-           full rotation). Negative values for degrees will rotate counter-clockwise
-           by that amount. All coordinates are canvas global coordinates.
+           This rotates the object clockwise by $degrees degrees, around the
+           center specified by the relative position ($cx, $cy) in the $pivot
+           object. If $pivot is $null then this object is used as its own pivot
+           center. 360 degrees is a full rotation, equivalent to no rotation.
+           Negative values for $degrees will rotate clockwise by that amount.
+
+           The coordinates are set relative to the given $pivot object. If its
+           geometry changes, then the absolute position of the rotation center
+           will change accordingly.
+
+           By default, the center is at (0.5, 0.5). 0.0 means left or top while
+           1.0 means right or bottom of the $pivot object.
          ]]
          params {
             degrees: double; [[CCW rotation in degrees.]]
-            cx: double; [[X coordinate of the rotation center.]]
-            cy: double; [[Y coordinate of the rotation center.]]
+            pivot: Efl.Gfx; [[A pivot object for the center point, can be $null.]]
+            cx: double; [[X relative coordinate of the center point.]]
+            cy: double; [[y relative coordinate of the center point.]]
          }
-         return: bool; [[$false in case of error.]]
       }
-      map_zoom {
-         [[Change the map to apply the given zooming.
+      rotate_3d {
+         [[Rotate the object around 3 axes in 3D.
 
-           Like evas_map_util_rotate(), this zooms the points of the map from a center
-           point. That center is defined by $cx and $cy. The $zoomx and $zoomy
-           parameters specify how much to zoom in the X and Y direction respectively.
-           A value of 1.0 means "don't zoom". 2.0 means "double the size". 0.5 is
-           "half the size" etc. All coordinates are canvas global coordinates.
-         ]]
-         params {
-            zoomx: double; [[Zoom in X direction]]
-            zoomy: double; [[Zoom in Y direction]]
-            cx: double; [[X coordinate of the center point.]]
-            cy: double; [[Y coordinate of the center point.]]
-         }
-         return: bool; [[$false in case of error.]]
-      }
-      map_rotate_3d {
-         [[Rotate the map around 3 axes in 3D
-
-           This will rotate not just around the "Z" axis as in evas_map_util_rotate()
-           (which is a convenience call for those only wanting 2D). This will rotate
-           around the X, Y and Z axes. The Z axis points "into" the screen with low
-           values at the screen and higher values further away. The X axis runs from
-           left to right on the screen and the Y axis from top to bottom. Like with
-           evas_map_util_rotate() you provide a center point to rotate around (in 3D).
+           This will rotate in 3D and not just around the "Z" axis as the case
+           with @.rotate. This will rotate around the X, Y and Z axes. The
+           Z axis points "into" the screen with low values at the screen and
+           higher values further away. The X axis runs from left to right on
+           the screen and the Y axis from top to bottom.
+
+           As with @.rotate, you provide a pivot and center point to rotate
+           around (in 3D). The Z coordinate of this center point is an absolute
+           value, and not a relative one like X and Y, as objects are flat in a
+           2D space.
          ]]
          params {
             dx: double; [[Rotation in degrees around X axis (0 to 360).]]
             dy: double; [[Rotation in degrees around Y axis (0 to 360).]]
             dz: double; [[Rotation in degrees around Z axis (0 to 360).]]
-            cx: double; [[Rotation's center X position.]]
-            cy: double; [[Rotation's center Y position.]]
-            cz: double; [[Rotation's center Z position.]]
+            pivot: Efl.Gfx; [[A pivot object for the center point, can be $null.]]
+            cx: double; [[X relative coordinate of the center point.]]
+            cy: double; [[y relative coordinate of the center point.]]
+            cz: double; [[Z absolute coordinate of the center point.]]
          }
-         return: bool; [[$false in case of error.]]
       }
-      map_quat_rotate {
-         [[Rotate the map in 3D using a unit quaternion.
+      rotate_quat {
+         [[Rotate the object in 3D using a unit quaternion.
+
+           This is similar to @.rotate_3d but uses a unit quaternion (also
+           known as versor) rather than a direct angle-based rotation around a
+           center point. Use this to avoid gimbal locks.
 
-           This will rotate in 3D using a unit quaternion. Like with
-           evas_map_util_3d_rotate() you provide a center point
-           to rotate around (in 3D).
+           As with @.rotate, you provide a pivot and center point to rotate
+           around (in 3D). The Z coordinate of this center point is an absolute
+           value, and not a relative one like X and Y, as objects are flat in a
+           2D space.
          ]]
          params {
             qx: double; [[The x component of the imaginary part of the quaternion.]]
             qy: double; [[The y component of the imaginary part of the quaternion.]]
             qz: double; [[The z component of the imaginary part of the quaternion.]]
             qw: double; [[The w component of the real part of the quaternion.]]
-            cx: double; [[Rotation's center x.]]
-            cy: double; [[Rotation's center y.]]
-            cz: double; [[Rotation's center z.]]
+            pivot: Efl.Gfx; [[A pivot object for the center point, can be $null.]]
+            cx: double; [[X relative coordinate of the center point.]]
+            cy: double; [[y relative coordinate of the center point.]]
+            cz: double; [[Z absolute coordinate of the center point.]]
          }
-         return: bool; [[$false in case of error.]]
       }
-      map_lightning_3d {
-         [[Perform lighting calculations on the given Map
-
-           This is used to apply lighting calculations (from a single light source)
-           to a given map. The R, G and B values of each vertex will be modified to
-           reflect the lighting based on the light point coordinates, the light
-           color and the ambient color, and at what angle the map is facing the
-           light source. A surface should have its points be declared in a
-           clockwise fashion if the face is "facing" towards you (as opposed to
-           away from you) as faces have a "logical" side for lighting.
+      zoom {
+         [[Apply a zoom to the object.
+
+           This zooms the points of the map from a center point. That center is
+           defined by $cx and $cy. The $zoomx and $zoomy parameters specify how
+           much to zoom in the X and Y direction respectively.
+           A value of 1.0 means "don't zoom". 2.0 means "double the size". 0.5 is
+           "half the size" etc.
+
+           By default, the center is at (0.5, 0.5). 0.0 means left or top while
+           1.0 means right or bottom.
+         ]]
+         params {
+            zoomx: double; [[Zoom in X direction]]
+            zoomy: double; [[Zoom in Y direction]]
+            pivot: Efl.Gfx; [[A pivot object for the center point, can be $null.]]
+            cx: double; [[X relative coordinate of the center point.]]
+            cy: double; [[y relative coordinate of the center point.]]
+         }
+      }
+      translate {
+         [[Apply a translation to the object using map.
+
+           This does not change the real geometry of the object but will affect
+           its visible position.
          ]]
          params {
-            lx: double; [[X coordinate in space of light point.]]
-            ly: double; [[Y coordinate in space of light point.]]
-            lz: double; [[Z coordinate in space of light point.]]
+            dx: double; [[Distance in pixels along the X axis.]]
+            dy: double; [[Distance in pixels along the Y axis.]]
+            dz: double; [[Distance in pixels along the Z axis.]]
+         }
+      }
+      lightning_3d {
+         [[Apply a lightning effect on the object.
+
+           This is used to apply lighting calculations (from a single light
+           source) to a given mapped object. The R, G and B values of each
+           vertex will be modified to reflect the lighting based on the light
+           point coordinates, the light color and the ambient color, and at
+           what angle the map is facing the light source. A surface should have
+           its points be declared in a clockwise fashion if the face is
+           "facing" towards you (as opposed to away from you) as faces have a
+           "logical" side for lighting.
+
+           The coordinates are set relative to the given $pivot object. If its
+           geometry changes, then the absolute position of the rotation center
+           will change accordingly. The Z position is absolute. If the $pivot
+           is $null then this object will be its own pivot.
+         ]]
+         params {
+            pivot: Efl.Gfx; [[A pivot object for the light point, can be $null.]]
+            lx: double; [[X relative coordinate in space of light point.]]
+            ly: double; [[Y relative coordinate in space of light point.]]
+            lz: double; [[Z absolute coordinate in space of light point.]]
             lr: int; [[Light red value (0 - 255).]]
             lg: int; [[Light green value (0 - 255).]]
             lb: int; [[Light blue value (0 - 255).]]
@@ -258,9 +281,8 @@ mixin Efl.Gfx.Map (Efl.Interface, Efl.Object)
             ag: int; [[Ambient color green value (0 - 255).]]
             ab: int; [[Ambient color blue value (0 - 255).]]
          }
-         return: bool; [[$false in case of error.]]
       }
-      map_perspective_3d {
+      perspective_3d {
          [[Apply a perspective transform to the map
 
            This applies a given perspective (3D) to the map coordinates. X, Y and Z
@@ -275,29 +297,23 @@ mixin Efl.Gfx.Map (Efl.Interface, Efl.Object)
            between the camera lens plane itself (at or closer than this rendering
            results are undefined) and the "z0" z value. This allows for some "depth"
            control and $foc must be greater than 0.
+
+           The coordinates are set relative to the given $pivot object. If its
+           geometry changes, then the absolute position of the rotation center
+           will change accordingly. The Z position is absolute. If the $pivot
+           is $null then this object will be its own pivot.
          ]]
          params {
-            px: double; [[The perspective distance X coordinate]]
-            py: double; [[The perspective distance Y coordinate]]
-            z0: double; [[The "0" z plane value]]
-            foc: double; [[The focal distance]]
+            pivot: Efl.Gfx; [[A pivot object for the infinite point, can be $null.]]
+            px: double; [[The perspective distance X relative coordinate.]]
+            py: double; [[The perspective distance Y relative coordinate.]]
+            z0: double; [[The "0" Z plane value.]]
+            foc: double; [[The focal distance, must be greater than 0.]]
          }
-         return: bool; [[$false in case of error.]]
-      }
-      map_dup {
-         [[Duplicate the map information from another object.]]
-         params {
-            other: const(Efl.Gfx.Map); [[Map object to duplicate]]
-         }
-         return: bool; [[$false in case of error.]]
       }
    }
    implements {
+      Efl.Object.constructor;
+      Efl.Object.destructor;
    }
 }
-
-
-// Porting notes:
-
-// Skipped APIs:
-// evas_map_util_object_move_sync_{set,get}
index 6af60da..91757c5 100644 (file)
@@ -88,6 +88,8 @@ evas_init(void)
    if (!evas_thread_init())
      goto shutdown_filter;
 
+   _efl_gfx_map_init();
+
    eina_log_timing(_evas_log_dom_global,
                   EINA_LOG_STATE_STOP,
                   EINA_LOG_STATE_INIT);
@@ -141,6 +143,8 @@ evas_shutdown(void)
      evas_cserve2_shutdown();
 #endif
 
+   _efl_gfx_map_shutdown();
+
    evas_font_path_global_clear();
    eina_cow_del(evas_object_proxy_cow);
    eina_cow_del(evas_object_map_cow);
index 820c0da..fab6331 100644 (file)
@@ -137,16 +137,15 @@ evas_object_map_move_sync(Evas_Object *eo_obj)
 Evas_Map *
 _evas_map_new(int count, Eina_Bool sync)
 {
-   int i;
-   int alloc;
    Evas_Map *m;
+   int alloc;
 
    /* Adjust allocation such that: at least 4 points, and always an even
     * number: this allows the software engine to work efficiently */
    alloc = (count < 4) ? 4 : count;
    if (alloc & 0x1) alloc ++;
 
-   m = calloc(1, sizeof(Evas_Map) + (alloc * sizeof(Evas_Map_Point)));
+   m = malloc(sizeof(Evas_Map) + (alloc * sizeof(Evas_Map_Point)));
    if (!m) return NULL;
    m->move_sync.enabled = sync;
    m->count = count;
@@ -154,7 +153,7 @@ _evas_map_new(int count, Eina_Bool sync)
    m->alpha = 1;
    m->smooth = 1;
    m->magic = MAGIC_MAP;
-   for (i = 0; i < count; i++)
+   for (int i = 0; i < count; i++)
      {
         m->points[i].r = 255;
         m->points[i].g = 255;
@@ -416,9 +415,9 @@ _evas_object_map_parent_check(Evas_Object *eo_parent)
 }
 #endif
 
-static void
-_map_map_enable_set(Eo *eo_obj, Evas_Object_Protected_Data *obj,
-                    Eina_Bool enabled, Eina_Bool default_move_sync)
+void
+_evas_object_map_enable_set(Eo *eo_obj, Evas_Object_Protected_Data *obj,
+                            Eina_Bool enabled)
 {
    Eina_Bool pchange = EINA_FALSE;
 
@@ -436,7 +435,7 @@ _map_map_enable_set(Eo *eo_obj, Evas_Object_Protected_Data *obj,
         if (!obj->map->cur.map)
           {
              EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
-               map_write->cur.map = _evas_map_new(4, default_move_sync);
+               map_write->cur.map = _evas_map_new(4, EINA_FALSE);
              EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
           }
         evas_object_mapped_clip_across_mark(eo_obj, obj);
@@ -484,26 +483,19 @@ _map_map_enable_set(Eo *eo_obj, Evas_Object_Protected_Data *obj,
      }
 }
 
-EOLIAN void
-_efl_canvas_object_efl_gfx_map_map_enable_set(Eo *eo_obj, void *_pd EINA_UNUSED, Eina_Bool enabled)
-{
-   Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
-
-   _map_map_enable_set(eo_obj, obj, enabled, EINA_TRUE);
-}
-
 EAPI void
-evas_object_map_enable_set(Efl_Gfx_Map *eo_obj, Eina_Bool enabled)
+evas_object_map_enable_set(Eo *eo_obj, Eina_Bool enabled)
 {
    Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj);
 
-   _map_map_enable_set(eo_obj, obj, enabled, EINA_FALSE);
+   _evas_object_map_enable_set(eo_obj, obj, enabled);
 }
 
-EOLIAN Eina_Bool
-_efl_canvas_object_efl_gfx_map_map_enable_get(Eo *eo_obj EINA_UNUSED, void *_pd EINA_UNUSED)
+EAPI Eina_Bool
+evas_object_map_enable_get(const Eo *eo_obj)
 {
-   Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
+   Evas_Object_Protected_Data *obj = EVAS_OBJ_GET_OR_RETURN(eo_obj, EINA_FALSE);
+
    return obj->map->cur.usemap;
 }
 
@@ -985,6 +977,22 @@ evas_map_util_zoom(Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_
 }
 
 void
+_map_util_translate(Evas_Map *m, double dx, double dy, double dz)
+{
+   Evas_Map_Point *p, *p_end;
+
+   p = m->points;
+   p_end = p + m->count;
+
+   for (; p < p_end; p++)
+     {
+        p->px = (p->x += dx);
+        p->py = (p->y += dy);
+        p->z += dz;
+     }
+}
+
+void
 _map_util_3d_rotate(Evas_Map *m, double dx, double dy, double dz,
                     double cx, double cy, double cz)
 {
@@ -1045,9 +1053,9 @@ evas_map_util_3d_rotate(Evas_Map *m, double dx, double dy, double dz,
    _map_util_3d_rotate(m, dx, dy, dz, (double) cx, (double) cy, (double) cz);
 }
 
-EAPI void
-evas_map_util_quat_rotate(Evas_Map *m, double qx, double qy, double qz,
-                          double qw, double cx, double cy, double cz)
+void
+_map_util_quat_rotate(Evas_Map *m, double qx, double qy, double qz,
+                      double qw, double cx, double cy, double cz)
 {
    Eina_Quaternion q;
    Eina_Point_3D c;
@@ -1086,6 +1094,17 @@ evas_map_util_quat_rotate(Evas_Map *m, double qx, double qy, double qz,
      }
 }
 
+EAPI void
+evas_map_util_quat_rotate(Evas_Map *m, double qx, double qy, double qz,
+                          double qw, double cx, double cy, double cz)
+{
+   MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
+   return;
+   MAGIC_CHECK_END();
+
+   _map_util_quat_rotate(m, qx, qy, qz, qw, cx, cy, cz);
+}
+
 void
 _map_util_3d_lighting(Evas_Map *m,
                       double lx, double ly, double lz,
index f1287bc..39377f6 100644 (file)
@@ -11,9 +11,12 @@ Evas_Map *_evas_map_new(int count, Eina_Bool sync);
 void _evas_map_calc_map_geometry(Evas_Object *eo_obj);
 void _map_util_rotate(Evas_Map *m, double degrees, double cx, double cy);
 void _map_util_zoom(Evas_Map *m, double zoomx, double zoomy, double cx, double cy);
+void _map_util_translate(Evas_Map *m, double dx, double dy, double dz);
 void _map_util_3d_rotate(Evas_Map *m, double dx, double dy, double dz, double cx, double cy, double cz);
 void _map_util_3d_lighting(Evas_Map *m, double lx, double ly, double lz, int lr, int lg, int lb, int ar, int ag, int ab);
 void _map_util_3d_perspective(Evas_Map *m, double px, double py, double z0, double foc);
+void _map_util_quat_rotate(Evas_Map *m, double qx, double qy, double qz, double qw, double cx, double cy, double cz);
+void _evas_object_map_enable_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Eina_Bool enabled);
 
 static inline void
 _evas_map_util_points_populate(Evas_Map *m, const double x, const double y,
@@ -85,5 +88,15 @@ error:
    if (z) *z = 0;
 }
 
+#define MAP_OBJ_CHANGE() do { \
+   _evas_map_calc_map_geometry(eo_obj); \
+   evas_object_change(eo_obj, obj); \
+   obj->changed_map = EINA_TRUE; \
+   } while (0)
+
+#define MAP_POPULATE_DEFAULT(m, z) \
+   _evas_map_util_points_populate(m, obj->cur->geometry.x, obj->cur->geometry.y, \
+                                  obj->cur->geometry.w, obj->cur->geometry.h, z)
+
 #endif // EVAS_MAP_H
 
index 7e2ab4f..7d9a138 100644 (file)
@@ -486,6 +486,8 @@ _evas_render_phase1_direct(Evas_Public_Data *e,
                     _evas_mask_redraw_set(e, obj);
                }
 
+             _evas_object_gfx_map_update(obj);
+
              RD(0, "      pre-render-done smart:%p|%p  [%p, %i] | [%p, %i] has_map:%i had_map:%i\n",
                 obj->smart.smart,
                 obj->is_smart ? evas_object_smart_members_get_direct(eo_obj) : NULL,
@@ -1121,6 +1123,7 @@ _evas_render_phase1_object_process(Phase1_Context *p1ctx,
      }
 #endif
 
+   _evas_object_gfx_map_update(obj);
    map = _evas_render_has_map(obj);
    hmap = _evas_render_had_map(obj);
    can_map = _evas_render_can_map(obj);
@@ -1243,6 +1246,7 @@ _evas_render_check_pending_objects(Eina_Array *pending_objects, Evas *eo_e EINA_
 
         if (!obj->layer) goto clean_stuff;
 
+        _evas_object_gfx_map_update(obj);
         EINA_PREFETCH(&(obj->cur->clipper));
         EINA_PREFETCH(&(obj->cur->cache.clip));
         //If the children are in active objects, They should be cleaned up.
@@ -1358,10 +1362,12 @@ _evas_render_can_use_overlay(Evas_Public_Data *e, Evas_Object *eo_obj)
    /* Check if any one is the stack make this object mapped */
    eo_tmp = eo_obj;
    tmp = efl_data_scope_get(eo_tmp, EFL_CANVAS_OBJECT_CLASS);
+   _evas_object_gfx_map_update(tmp);
    while (tmp && !(_evas_render_has_map(tmp) && !_evas_render_can_map(tmp)))
      {
         eo_tmp = tmp->smart.parent;
         tmp = efl_data_scope_get(eo_tmp, EFL_CANVAS_OBJECT_CLASS);
+        if (tmp) _evas_object_gfx_map_update(tmp);
      }
 
    if (tmp && _evas_render_has_map(tmp) && !_evas_render_can_map(tmp))
@@ -1725,6 +1731,7 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
      proxy_src_clip = proxy_render_data->source_clip;
 
    evas_object_clip_recalc(obj);
+   _evas_object_gfx_map_update(obj);
 
    /* leave early if clipper is not visible */
    if ((obj->cur->clipper) && (!obj->cur->clipper->cur->visible))
index d2b6a70..a48251a 100644 (file)
@@ -31,6 +31,13 @@ _evas_render_can_map(Evas_Object_Protected_Data *obj)
    return obj->func->can_map(obj->object);
 }
 
+static inline void
+_evas_object_gfx_map_update(Evas_Object_Protected_Data *obj)
+{
+   if (!obj->gfx_map_has) return;
+   _efl_gfx_map_update(obj->object);
+}
+
 static inline int
 _evas_object_event_new(void)
 {
index 3c7ec16..f46c928 100644 (file)
@@ -1222,6 +1222,8 @@ struct _Evas_Object_Protected_Data
 
    Eina_Bool                   snapshot_needs_redraw : 1;
    Eina_Bool                   snapshot_no_obscure : 1;
+   Eina_Bool                   gfx_map_has : 1;
+   Eina_Bool                   gfx_map_update : 1;
 
    struct  {
       Eina_Bool                pass_events : 1;
@@ -1891,6 +1893,11 @@ void _evas_canvas3d_eet_file_free(Evas_Canvas3D_File_Eet* eet_file);
 void evas_filter_init(void);
 void evas_filter_shutdown(void);
 
+/* Efl.Gfx.Map */
+void _efl_gfx_map_init(void);
+void _efl_gfx_map_shutdown(void);
+void _efl_gfx_map_update(Eo *eo_obj);
+
 /* Ector */
 Ector_Surface *evas_ector_get(Evas_Public_Data *evas, void *output);