1 #include "evas_common.h"
2 #include "evas_private.h"
6 _evas_map_calc_geom_change(Evas_Object *obj)
10 evas_object_change(obj);
11 evas_object_clip_dirty(obj);
12 if (obj->layer->evas->events_frozen <= 0)
14 evas_object_recalc_clippees(obj);
15 if (!obj->smart.smart)
17 is = evas_object_is_in_output_rect(obj,
18 obj->layer->evas->pointer.x,
19 obj->layer->evas->pointer.y, 1, 1);
20 if ((is ^ was) && obj->cur.visible)
21 evas_event_feed_mouse_move(obj->layer->evas,
22 obj->layer->evas->pointer.x,
23 obj->layer->evas->pointer.y,
24 obj->layer->evas->last_timestamp,
28 evas_object_inform_call_move(obj);
29 evas_object_inform_call_resize(obj);
33 _evas_map_calc_map_geometry(Evas_Object *obj)
35 Evas_Coord x1, x2, yy1, yy2;
36 const Evas_Map_Point *p, *p_end;
37 Eina_Bool ch = EINA_FALSE;
39 if (!obj->cur.map) return;
41 // WARN: Do not merge below code to SLP until it is fixed.
42 // It has an infinite loop bug.
45 // FIXME: this causes an infinite loop somewhere... hard to debug
46 if (obj->prev.map->count == obj->cur.map->count)
48 const Evas_Map_Point *p2;
50 p = obj->cur.map->points;
51 p_end = p + obj->cur.map->count;
52 p2 = obj->prev.map->points;
54 for (; p < p_end; p++, p2++)
56 if ((p->a != p2->a) ||
64 if ((p->x != p2->x) ||
79 p = obj->cur.map->points;
80 p_end = p + obj->cur.map->count;
81 x1 = x2 = lround(p->x);
82 yy1 = yy2 = lround(p->y);
84 for (; p < p_end; p++)
95 // this causes clip-out bugs now mapped objs canbe opaque!!!
96 // // add 1 pixel of fuzz around the map region to ensure updates are correct
99 if (obj->cur.map->normal_geometry.x != x1) ch = 1;
100 if (obj->cur.map->normal_geometry.y != yy1) ch = 1;
101 if (obj->cur.map->normal_geometry.w != (x2 - x1)) ch = 1;
102 if (obj->cur.map->normal_geometry.h != (yy2 - yy1)) ch = 1;
103 obj->cur.map->normal_geometry.x = x1;
104 obj->cur.map->normal_geometry.y = yy1;
105 obj->cur.map->normal_geometry.w = (x2 - x1);
106 obj->cur.map->normal_geometry.h = (yy2 - yy1);
107 if (ch) _evas_map_calc_geom_change(obj);
110 static inline Evas_Map *
111 _evas_map_new(int count)
117 /* Adjust allocation such that: at least 4 points, and always an even
118 * number: this allows the software engine to work efficiently */
119 alloc = (count < 4) ? 4 : count;
120 if (alloc & 0x1) alloc ++;
122 m = calloc(1, sizeof(Evas_Map) + (alloc * sizeof(Evas_Map_Point)));
128 m->magic = MAGIC_MAP;
129 for (i = 0; i < count; i++)
131 m->points[i].r = 255;
132 m->points[i].g = 255;
133 m->points[i].b = 255;
134 m->points[i].a = 255;
139 static inline Eina_Bool
140 _evas_map_copy(Evas_Map *dst, const Evas_Map *src)
142 if (dst->count != src->count)
144 ERR("cannot copy map of different sizes: dst=%i, src=%i", dst->count, src->count);
147 if (dst == src) return EINA_TRUE;
148 if (dst->points != src->points)
149 memcpy(dst->points, src->points, src->count * sizeof(Evas_Map_Point));
150 dst->smooth = src->smooth;
151 dst->alpha = src->alpha;
152 dst->persp = src->persp;
156 static inline Evas_Map *
157 _evas_map_dup(const Evas_Map *orig)
159 Evas_Map *copy = _evas_map_new(orig->count);
160 if (!copy) return NULL;
161 memcpy(copy->points, orig->points, orig->count * sizeof(Evas_Map_Point));
162 copy->smooth = orig->smooth;
163 copy->alpha = orig->alpha;
164 copy->persp = orig->persp;
169 _evas_map_free(Evas_Object *obj, Evas_Map *m)
174 obj->layer->evas->engine.func->image_map_surface_free
175 (obj->layer->evas->engine.data.output, m->surface);
178 obj->layer->evas->engine.func->image_map_clean(obj->layer->evas->engine.data.output, obj->spans);
187 /****************************************************************************/
188 /* util functions for manipulating maps, so you don't need to know the math */
189 /****************************************************************************/
191 _evas_map_util_points_populate(Evas_Map *m, const Evas_Coord x, const Evas_Coord y, const Evas_Coord w, const Evas_Coord h, const Evas_Coord z)
193 Evas_Map_Point *p = m->points;
220 for (i = 0; i < 4; i++)
228 evas_map_coords_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y,
229 Evas_Coord *mx, Evas_Coord *my, int grab)
231 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
235 int i, j, edges, edge[m->count][2], douv;
237 double u[2] = { 0.0, 0.0 };
238 double v[2] = { 0.0, 0.0 };
240 if (m->count < 4) return 0;
241 // FIXME need to handle grab mode and extrapolte coords outside
245 Evas_Coord ymin, ymax;
247 ymin = m->points[0].y;
248 ymax = m->points[0].y;
249 for (i = 1; i < m->count; i++)
251 if (m->points[i].y < ymin) ymin = m->points[i].y;
252 else if (m->points[i].y > ymax) ymax = m->points[i].y;
254 if (y <= ymin) y = ymin + 1;
255 if (y >= ymax) y = ymax - 1;
258 for (i = 0; i < m->count; i++)
260 j = (i + 1) % m->count;
261 if ((m->points[i].y <= y) && (m->points[j].y > y))
267 else if ((m->points[j].y <= y) && (m->points[i].y > y))
275 if ((mx) || (my)) douv = 1;
276 for (i = 0; i < (edges - 1); i+= 2)
281 yd = m->points[edge[i][1]].y - m->points[edge[i][0]].y;
284 yp = y - m->points[edge[i][0]].y;
285 xe[0] = m->points[edge[i][1]].x - m->points[edge[i][0]].x;
286 xe[0] = m->points[edge[i][0]].x + ((xe[0] * yp) / yd);
289 u[0] = m->points[edge[i][1]].u - m->points[edge[i][0]].u;
290 u[0] = m->points[edge[i][0]].u + ((u[0] * yp) / yd);
291 v[0] = m->points[edge[i][1]].v - m->points[edge[i][0]].v;
292 v[0] = m->points[edge[i][0]].v + ((v[0] * yp) / yd);
297 xe[0] = m->points[edge[i][0]].x;
300 u[0] = m->points[edge[i][0]].u;
301 v[0] = m->points[edge[i][0]].v;
304 yd = m->points[edge[j][1]].y - m->points[edge[j][0]].y;
307 yp = y - m->points[edge[j][0]].y;
308 xe[1] = m->points[edge[j][1]].x - m->points[edge[j][0]].x;
309 xe[1] = m->points[edge[j][0]].x + ((xe[1] * yp) / yd);
312 u[1] = m->points[edge[j][1]].u - m->points[edge[j][0]].u;
313 u[1] = m->points[edge[j][0]].u + ((u[1] * yp) / yd);
314 v[1] = m->points[edge[j][1]].v - m->points[edge[j][0]].v;
315 v[1] = m->points[edge[j][0]].v + ((v[1] * yp) / yd);
320 xe[1] = m->points[edge[j][0]].x;
323 u[1] = m->points[edge[j][0]].u;
324 v[1] = m->points[edge[j][0]].v;
331 ti = xe[0]; xe[0] = xe[1]; xe[1] = ti;
336 td = u[0]; u[0] = u[1]; u[1] = td;
337 td = v[0]; v[0] = v[1]; v[1] = td;
340 if ((x >= xe[0]) && (x < xe[1]))
345 *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) /
348 *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) /
358 *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) /
361 *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) /
371 evas_map_inside_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y)
373 return evas_map_coords_get(m, x, y, NULL, NULL, 0);
377 _evas_object_map_parent_check(Evas_Object *parent)
379 const Eina_Inlist *list;
380 const Evas_Object *o;
382 if (!parent) return EINA_FALSE;
384 list = evas_object_smart_members_get_direct(parent->smart.parent);
385 EINA_INLIST_FOREACH(list, o)
386 if (o->cur.usemap) break ;
387 if (o) return EINA_FALSE; /* Still some child have a map enable */
388 parent->child_has_map = EINA_FALSE;
389 _evas_object_map_parent_check(parent->smart.parent);
394 evas_object_map_enable_set(Evas_Object *obj, Eina_Bool enabled)
396 Evas_Object *parents;
397 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
400 Eina_Bool pchange = EINA_FALSE;
403 if (obj->cur.usemap == enabled) return;
404 pchange = obj->changed;
405 obj->cur.usemap = enabled;
409 obj->cur.map = _evas_map_new(4);
410 evas_object_mapped_clip_across_mark(obj);
411 // obj->cur.map->normal_geometry = obj->cur.geometry;
417 _evas_map_calc_geom_change(obj);
418 evas_object_mapped_clip_across_mark(obj);
421 _evas_map_calc_map_geometry(obj);
422 /* This is a bit heavy handed, but it fixes the case of same geometry, but
423 * changed colour or UV settings. */
424 evas_object_change(obj);
425 if (!obj->changed_pchange) obj->changed_pchange = pchange;
426 obj->changed_map = EINA_TRUE;
430 for (parents = obj->smart.parent; parents; parents = parents->smart.parent)
431 parents->child_has_map = EINA_TRUE;
435 if (_evas_object_map_parent_check(obj->smart.parent))
436 evas_object_update_bounding_box(obj);
441 evas_object_map_enable_get(const Evas_Object *obj)
443 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
446 return obj->cur.usemap;
450 evas_object_map_set(Evas_Object *obj, const Evas_Map *map)
452 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
456 if (!map || map->count < 4)
460 obj->changed_map = EINA_TRUE;
462 if (obj->cur.map->surface)
464 obj->layer->evas->engine.func->image_map_surface_free
465 (obj->layer->evas->engine.data.output,
466 obj->cur.map->surface);
467 obj->cur.map->surface = NULL;
469 obj->prev.geometry = obj->cur.map->normal_geometry;
470 _evas_map_free(obj, obj->cur.map);
475 evas_object_mapped_clip_across_mark(obj);
479 if (!obj->cur.usemap) _evas_map_calc_geom_change(obj);
480 else _evas_map_calc_map_geometry(obj);
482 evas_object_mapped_clip_across_mark(obj);
487 // We do have the same exact count of point in this map, so just copy it
488 if ((obj->cur.map) && (obj->cur.map->count == map->count))
489 _evas_map_copy(obj->cur.map, map);
492 if (obj->cur.map) _evas_map_free(obj, obj->cur.map);
493 obj->cur.map = _evas_map_dup(map);
495 evas_object_mapped_clip_across_mark(obj);
497 obj->changed_map = EINA_TRUE;
499 _evas_map_calc_map_geometry(obj);
502 EAPI const Evas_Map *
503 evas_object_map_get(const Evas_Object *obj)
505 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
513 evas_map_new(int count)
517 ERR("map point count (%i) != 4 is unsupported!", count);
521 return _evas_map_new(count);
525 evas_map_smooth_set(Evas_Map *m, Eina_Bool enabled)
527 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
535 evas_map_smooth_get(const Evas_Map *m)
537 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
545 evas_map_alpha_set(Evas_Map *m, Eina_Bool enabled)
547 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
555 evas_map_alpha_get(const Evas_Map *m)
557 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
565 evas_map_dup(const Evas_Map *m)
567 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
571 return _evas_map_dup(m);
575 evas_map_free(Evas_Map *m)
577 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
581 _evas_map_free(NULL, m);
585 evas_map_count_get(const Evas_Map *m)
587 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
595 evas_map_point_coord_set(Evas_Map *m, int idx, Evas_Coord x, Evas_Coord y, Evas_Coord z)
597 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
603 if (idx >= m->count) return;
611 evas_map_point_coord_get(const Evas_Map *m, int idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z)
613 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
617 const Evas_Map_Point *p;
619 if (idx >= m->count) goto error;
633 evas_map_point_image_uv_set(Evas_Map *m, int idx, double u, double v)
635 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
641 if (idx >= m->count) return;
648 evas_map_point_image_uv_get(const Evas_Map *m, int idx, double *u, double *v)
650 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
654 const Evas_Map_Point *p;
656 if (idx >= m->count) goto error;
668 evas_map_point_color_set(Evas_Map *m, int idx, int r, int g, int b, int a)
670 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
676 if (idx >= m->count) return;
685 evas_map_point_color_get(const Evas_Map *m, int idx, int *r, int *g, int *b, int *a)
687 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
691 const Evas_Map_Point *p;
693 if (idx >= m->count) return;
702 evas_map_util_points_populate_from_object_full(Evas_Map *m, const Evas_Object *obj, Evas_Coord z)
704 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
710 ERR("map has count=%d where 4 was expected.", m->count);
713 _evas_map_util_points_populate(m, obj->cur.geometry.x, obj->cur.geometry.y,
714 obj->cur.geometry.w, obj->cur.geometry.h, z);
718 evas_map_util_points_populate_from_object(Evas_Map *m, const Evas_Object *obj)
720 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
724 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
730 ERR("map has count=%d where 4 was expected.", m->count);
733 _evas_map_util_points_populate(m, obj->cur.geometry.x, obj->cur.geometry.y,
734 obj->cur.geometry.w, obj->cur.geometry.h, 0);
738 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)
740 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
746 ERR("map has count=%d where 4 was expected.", m->count);
749 _evas_map_util_points_populate(m, x, y, w, h, z);
753 evas_map_util_points_color_set(Evas_Map *m, int r, int g, int b, int a)
755 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
759 Evas_Map_Point *p, *p_end;
762 p_end = p + m->count;
763 for (; p < p_end; p++)
773 evas_map_util_rotate(Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy)
775 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
779 double r = (degrees * M_PI) / 180.0;
780 Evas_Map_Point *p, *p_end;
783 p_end = p + m->count;
785 for (; p < p_end; p++)
794 x = xx - (y * sin(r));
795 y = yy + (y * cos(r));
797 p->px = p->x = x + cx;
798 p->py = p->y = y + cy;
803 evas_map_util_zoom(Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy)
805 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
809 Evas_Map_Point *p, *p_end;
812 p_end = p + m->count;
814 for (; p < p_end; p++)
821 x = (((double)x) * zoomx);
822 y = (((double)y) * zoomy);
824 p->px = p->x = x + cx;
825 p->py = p->y = y + cy;
830 evas_map_util_3d_rotate(Evas_Map *m, double dx, double dy, double dz,
831 Evas_Coord cx, Evas_Coord cy, Evas_Coord cz)
833 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
837 double rz = (dz * M_PI) / 180.0;
838 double rx = (dx * M_PI) / 180.0;
839 double ry = (dy * M_PI) / 180.0;
840 Evas_Map_Point *p, *p_end;
843 p_end = p + m->count;
845 for (; p < p_end; p++)
847 double x, y, z, xx, yy, zz;
857 x = xx - (y * sin(rz));
858 y = yy + (y * cos(rz));
865 x = xx - (z * sin(ry));
866 z = zz + (z * cos(ry));
873 z = zz - (y * sin(rx));
874 y = yy + (y * cos(rx));
877 p->px = p->x = x + cx;
878 p->py = p->y = y + cy;
884 evas_map_util_3d_lighting(Evas_Map *m,
885 Evas_Coord lx, Evas_Coord ly, Evas_Coord lz,
886 int lr, int lg, int lb, int ar, int ag, int ab)
888 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
894 for (i = 0; i < m->count; i++)
897 double nx, ny, nz, x1, yy1, z1, x2, yy2, z2, ln, br;
898 int h, j, mr, mg, mb;
904 h = (i - 1 + 4) % 4 + (i & ~0x3); // prev point
905 j = (i + 1) % 4 + (i & ~0x3); // next point
907 x1 = m->points[h].x - x;
908 yy1 = m->points[h].y - y;
909 z1 = m->points[h].z - z;
911 x2 = m->points[j].x - x;
912 yy2 = m->points[j].y - y;
913 z2 = m->points[j].z - z;
914 nx = (yy1 * z2) - (z1 * yy2);
915 ny = (z1 * x2) - (x1 * z2);
916 nz = (x1 * yy2) - (yy1 * x2);
918 ln = (nx * nx) + (ny * ny) + (nz * nz);
928 // calc point -> light vector
933 ln = (x * x) + (y * y) + (z * z);
943 // brightness - tan (0.0 -> 1.0 brightness really)
944 br = (nx * x) + (ny * y) + (nz * z);
945 if (br < 0.0) br = 0.0;
947 mr = ar + ((lr - ar) * br);
948 mg = ag + ((lg - ag) * br);
949 mb = ab + ((lb - ab) * br);
950 if (m->points[i].a != 255)
952 mr = (mr * m->points[i].a) / 255;
953 mg = (mg * m->points[i].a) / 255;
954 mb = (mb * m->points[i].a) / 255;
956 m->points[i].r = (m->points[i].r * mr) / 255;
957 m->points[i].g = (m->points[i].g * mg) / 255;
958 m->points[i].b = (m->points[i].b * mb) / 255;
963 evas_map_util_3d_perspective(Evas_Map *m,
964 Evas_Coord px, Evas_Coord py,
965 Evas_Coord z0, Evas_Coord foc)
967 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
971 Evas_Map_Point *p, *p_end;
974 p_end = p + m->count;
981 if (foc <= 0) return;
983 for (; p < p_end; p++)
990 zz = ((p->z - z0) + foc);
1004 evas_map_util_clockwise_get(Evas_Map *m)
1006 MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
1013 if (m->count < 3) return EINA_FALSE;
1016 for (i = 0; i < m->count; i++)
1018 j = (i + 1) % m->count;
1019 k = (i + 2) % m->count;
1021 ((m->points[j].x - m->points[i].x) *
1022 (m->points[k].y - m->points[j].y))
1024 ((m->points[j].y - m->points[i].y) *
1025 (m->points[k].x - m->points[j].x));
1027 else if (c > 0) count++;
1029 if (count > 0) return EINA_TRUE;
1034 evas_object_map_update(Evas_Object *obj,
1036 int imagew, int imageh,
1039 const Evas_Map_Point *p, *p_end;
1040 RGBA_Map_Point *pts, *pt;
1044 if (obj->spans->x != x || obj->spans->y != y ||
1045 obj->spans->image.w != imagew || obj->spans->image.h != imageh ||
1046 obj->spans->uv.w != uvw || obj->spans->uv.h != uvh)
1047 obj->changed_map = EINA_TRUE;
1051 obj->changed_map = EINA_TRUE;
1054 if (!obj->changed_map) return ;
1056 if (obj->cur.map && obj->spans && obj->cur.map->count != obj->spans->count)
1060 // Destroy engine side spans
1067 obj->spans = calloc(1, sizeof (RGBA_Map) +
1068 sizeof (RGBA_Map_Point) * (obj->cur.map->count - 1));
1070 if (!obj->spans) return ;
1072 obj->spans->count = obj->cur.map->count;
1075 obj->spans->uv.w = uvw;
1076 obj->spans->uv.h = uvh;
1077 obj->spans->image.w = imagew;
1078 obj->spans->image.h = imageh;
1080 pts = obj->spans->pts;
1082 p = obj->cur.map->points;
1083 p_end = p + obj->cur.map->count;
1086 pts[0].px = obj->cur.map->persp.px << FP;
1087 pts[0].py = obj->cur.map->persp.py << FP;
1088 pts[0].foc = obj->cur.map->persp.foc << FP;
1089 pts[0].z0 = obj->cur.map->persp.z0 << FP;
1091 for (; p < p_end; p++, pt++)
1093 pt->x = (lround(p->x) + x) * FP1;
1094 pt->y = (lround(p->y) + y) * FP1;
1095 pt->z = (lround(p->z) ) * FP1;
1099 pt->u = ((lround(p->u) * imagew) / uvw) * FP1;
1100 pt->v = ((lround(p->v) * imageh) / uvh) * FP1;
1101 if (pt->u < 0) pt->u = 0;
1102 else if (pt->u > (imagew * FP1)) pt->u = (imagew * FP1);
1103 if (pt->v < 0) pt->v = 0;
1104 else if (pt->v > (imageh * FP1)) pt->v = (imageh * FP1);
1105 pt->col = ARGB_JOIN(p->a, p->r, p->g, p->b);
1107 if (obj->cur.map->count & 0x1)
1109 pts[obj->cur.map->count] = pts[obj->cur.map->count -1];
1112 // Request engine to update it's point