afa433bb4d4f187597ee1a61a64e0868a0d1ba92
[framework/uifw/evas.git] / src / lib / canvas / evas_map.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3 #include <math.h>
4
5 static void
6 _evas_map_calc_geom_change(Evas_Object *obj)
7 {
8    int is, was = 0;
9
10    evas_object_change(obj);
11    evas_object_clip_dirty(obj);
12    if (obj->layer->evas->events_frozen <= 0)
13      {
14         evas_object_recalc_clippees(obj);
15         if (!obj->smart.smart)
16           {
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,
25                                           NULL);
26           }
27      }
28    evas_object_inform_call_move(obj);
29    evas_object_inform_call_resize(obj);
30 }
31
32 static void
33 _evas_map_calc_map_geometry(Evas_Object *obj)
34 {
35    Evas_Coord x1, x2, yy1, yy2;
36    const Evas_Map_Point *p, *p_end;
37    Eina_Bool ch = EINA_FALSE;
38
39    if (!obj->cur.map) return;
40
41    // WARN: Do not merge below code to SLP until it is fixed.
42    // It has an infinite loop bug.
43    if (obj->prev.map)
44      {
45         // FIXME: this causes an infinite loop somewhere... hard to debug
46         if (obj->prev.map->count == obj->cur.map->count)
47           {
48              const Evas_Map_Point *p2;
49
50              p = obj->cur.map->points;
51              p_end = p + obj->cur.map->count;
52              p2 = obj->prev.map->points;
53
54              for (; p < p_end; p++, p2++)
55                {
56                   if ((p->a != p2->a) ||
57                       (p->r != p2->r) ||
58                       (p->g != p2->g) ||
59                       (p->b != p2->b))
60                     {
61                        ch = 1;
62                        break;
63                     }
64                   if ((p->x != p2->x) ||
65                       (p->y != p2->y) ||
66                       (p->z != p2->z))
67                     {
68                        ch = 1;
69                        break;
70                     }
71                }
72           }
73         else
74            ch = 1;
75      }
76    else
77       ch = 1;
78
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);
83    p++;
84    for (; p < p_end; p++)
85      {
86         Evas_Coord x, y;
87         
88         x = lround(p->x);
89         y = lround(p->y);
90         if (x < x1) x1 = x;
91         if (x > x2) x2 = x;
92         if (y < yy1) yy1 = y;
93         if (y > yy2) yy2 = y;
94      }
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
97 //   x1 -= 1; yy1 -= 1;
98 //   x2 += 1; yy2 += 1;
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);
108 }
109
110 static inline Evas_Map *
111 _evas_map_new(int count)
112 {
113    int i;
114    int alloc;
115    Evas_Map *m;
116
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 ++;
121
122    m = calloc(1, sizeof(Evas_Map) + (alloc * sizeof(Evas_Map_Point)));
123    if (!m) return NULL;
124    m->count = count;
125    m->persp.foc = 0;
126    m->alpha = 1;
127    m->smooth = 1;
128    m->magic = MAGIC_MAP;
129    for (i = 0; i < count; i++)
130      {
131         m->points[i].r = 255;
132         m->points[i].g = 255;
133         m->points[i].b = 255;
134         m->points[i].a = 255;
135      }
136    return m;
137 }
138
139 static inline Eina_Bool
140 _evas_map_copy(Evas_Map *dst, const Evas_Map *src)
141 {
142    if (dst->count != src->count)
143      {
144         ERR("cannot copy map of different sizes: dst=%i, src=%i", dst->count, src->count);
145         return EINA_FALSE;
146      }
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;
153    return EINA_TRUE;
154 }
155
156 static inline Evas_Map *
157 _evas_map_dup(const Evas_Map *orig)
158 {
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;
165    return copy;
166 }
167
168 static inline void
169 _evas_map_free(Evas_Object *obj, Evas_Map *m)
170 {
171    if (obj)
172      {
173         if (m->surface)
174           obj->layer->evas->engine.func->image_map_surface_free
175             (obj->layer->evas->engine.data.output, m->surface);
176         if (obj->spans)
177           {
178              obj->layer->evas->engine.func->image_map_clean(obj->layer->evas->engine.data.output, obj->spans);
179              free(obj->spans);
180              obj->spans = NULL;
181           }      
182      }
183    m->magic = 0;
184    free(m);
185 }
186
187 /****************************************************************************/
188 /* util functions for manipulating maps, so you don't need to know the math */
189 /****************************************************************************/
190 static inline void
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)
192 {
193    Evas_Map_Point *p = m->points;
194    int i;
195
196    p[0].x = x;
197    p[0].y = y;
198    p[0].z = z;
199    p[0].u = 0.0;
200    p[0].v = 0.0;
201
202    p[1].x = x + w;
203    p[1].y = y;
204    p[1].z = z;
205    p[1].u = w;
206    p[1].v = 0.0;
207
208    p[2].x = x + w;
209    p[2].y = y + h;
210    p[2].z = z;
211    p[2].u = w;
212    p[2].v = h;
213
214    p[3].x = x;
215    p[3].y = y + h;
216    p[3].z = z;
217    p[3].u = 0.0;
218    p[3].v = h;
219
220    for (i = 0; i < 4; i++)
221      {
222         p[i].px = p[i].x;
223         p[i].py = p[i].y;
224      }
225 }
226
227 Eina_Bool
228 evas_map_coords_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y,
229                     Evas_Coord *mx, Evas_Coord *my, int grab)
230 {
231    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
232    return EINA_FALSE;
233    MAGIC_CHECK_END();
234
235    int i, j, edges, edge[m->count][2], douv;
236    Evas_Coord xe[2];
237    double u[2] = { 0.0, 0.0 };
238    double v[2] = { 0.0, 0.0 };
239
240    if (m->count < 4) return 0;
241    // FIXME need to handle grab mode and extrapolte coords outside
242    // map
243    if (grab)
244      {
245         Evas_Coord ymin, ymax;
246
247         ymin = m->points[0].y;
248         ymax = m->points[0].y;
249         for (i = 1; i < m->count; i++)
250           {
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;
253           }
254         if (y <= ymin) y = ymin + 1;
255         if (y >= ymax) y = ymax - 1;
256      }
257    edges = 0;
258    for (i = 0; i < m->count; i++)
259      {
260         j = (i + 1) % m->count;
261         if ((m->points[i].y <= y) && (m->points[j].y > y))
262           {
263              edge[edges][0] = i;
264              edge[edges][1] = j;
265              edges++;
266           }
267         else if ((m->points[j].y <= y) && (m->points[i].y > y))
268           {
269              edge[edges][0] = j;
270              edge[edges][1] = i;
271              edges++;
272           }
273      }
274    douv = 0;
275    if ((mx) || (my)) douv = 1;
276    for (i = 0; i < (edges - 1); i+= 2)
277      {
278         Evas_Coord yp, yd;
279
280         j = i + 1;
281         yd = m->points[edge[i][1]].y - m->points[edge[i][0]].y;
282         if (yd > 0)
283           {
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);
287              if (douv)
288                {
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);
293                }
294           }
295         else
296           {
297              xe[0] = m->points[edge[i][0]].x;
298              if (douv)
299                {
300                   u[0] = m->points[edge[i][0]].u;
301                   v[0] = m->points[edge[i][0]].v;
302                }
303           }
304         yd = m->points[edge[j][1]].y - m->points[edge[j][0]].y;
305         if (yd > 0)
306           {
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);
310              if (douv)
311                {
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);
316                }
317           }
318         else
319           {
320              xe[1] = m->points[edge[j][0]].x;
321              if (douv)
322                {
323                   u[1] = m->points[edge[j][0]].u;
324                   v[1] = m->points[edge[j][0]].v;
325                }
326           }
327         if (xe[0] > xe[1])
328           {
329              int ti;
330
331              ti = xe[0]; xe[0] = xe[1]; xe[1] = ti;
332              if (douv)
333                {
334                   double td;
335
336                   td = u[0]; u[0] = u[1]; u[1] = td;
337                   td = v[0]; v[0] = v[1]; v[1] = td;
338                }
339           }
340         if ((x >= xe[0]) && (x < xe[1]))
341           {
342              if (douv)
343                {
344                   if (mx)
345                     *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) /
346                                   (xe[1] - xe[0]));
347                  if (my)
348                     *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) /
349                                   (xe[1] - xe[0]));
350                }
351              return EINA_TRUE;
352           }
353         if (grab)
354           {
355              if (douv)
356                {
357                   if (mx)
358                     *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) /
359                                   (xe[1] - xe[0]));
360                   if (my)
361                     *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) /
362                                   (xe[1] - xe[0]));
363                }
364              return EINA_TRUE;
365           }
366      }
367    return EINA_FALSE;
368 }
369
370 Eina_Bool
371 evas_map_inside_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y)
372 {
373    return evas_map_coords_get(m, x, y, NULL, NULL, 0);
374 }
375
376 static Eina_Bool
377 _evas_object_map_parent_check(Evas_Object *parent)
378 {
379    const Eina_Inlist *list;
380    const Evas_Object *o;
381
382    if (!parent) return EINA_FALSE;
383
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);
390    return EINA_TRUE;
391 }
392
393 EAPI void
394 evas_object_map_enable_set(Evas_Object *obj, Eina_Bool enabled)
395 {
396    Evas_Object *parents;
397    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
398    return;
399    MAGIC_CHECK_END();
400    Eina_Bool pchange = EINA_FALSE;
401
402    enabled = !!enabled;
403    if (obj->cur.usemap == enabled) return;
404    pchange = obj->changed;
405    obj->cur.usemap = enabled;
406    if (enabled)
407      {
408         if (!obj->cur.map)
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;
412      }
413    else
414      {
415         if (obj->cur.map)
416           {
417              _evas_map_calc_geom_change(obj);
418              evas_object_mapped_clip_across_mark(obj);
419           }
420      }
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;
427
428    if (enabled)
429      {
430         for (parents = obj->smart.parent; parents; parents = parents->smart.parent)
431           parents->child_has_map = EINA_TRUE;
432      }
433    else
434      {
435         if (_evas_object_map_parent_check(obj->smart.parent))
436           evas_object_update_bounding_box(obj);
437      }
438 }
439
440 EAPI Eina_Bool
441 evas_object_map_enable_get(const Evas_Object *obj)
442 {
443    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
444    return EINA_FALSE;
445    MAGIC_CHECK_END();
446    return obj->cur.usemap;
447 }
448
449 EAPI void
450 evas_object_map_set(Evas_Object *obj, const Evas_Map *map)
451 {
452    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
453    return;
454    MAGIC_CHECK_END();
455
456    if (!map || map->count < 4)
457      {
458         if (obj->cur.map)
459           {
460              obj->changed_map = EINA_TRUE;
461
462              if (obj->cur.map->surface)
463                {
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;
468                }
469              obj->prev.geometry = obj->cur.map->normal_geometry;
470              _evas_map_free(obj, obj->cur.map);
471              obj->cur.map = NULL;
472
473              if (!obj->prev.map)
474                {
475                   evas_object_mapped_clip_across_mark(obj);
476                   return;
477                }
478
479              if (!obj->cur.usemap) _evas_map_calc_geom_change(obj);
480              else _evas_map_calc_map_geometry(obj);
481              if (obj->cur.usemap)
482                evas_object_mapped_clip_across_mark(obj);
483           }
484         return;
485      }
486
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);
490    else
491      {
492         if (obj->cur.map) _evas_map_free(obj, obj->cur.map);
493         obj->cur.map = _evas_map_dup(map);
494         if (obj->cur.usemap)
495            evas_object_mapped_clip_across_mark(obj);
496      }
497    obj->changed_map = EINA_TRUE;
498
499    _evas_map_calc_map_geometry(obj);
500 }
501
502 EAPI const Evas_Map *
503 evas_object_map_get(const Evas_Object *obj)
504 {
505    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
506    return NULL;
507    MAGIC_CHECK_END();
508
509    return obj->cur.map;
510 }
511
512 EAPI Evas_Map *
513 evas_map_new(int count)
514 {
515    if (count != 4)
516      {
517         ERR("map point count (%i) != 4 is unsupported!", count);
518         return NULL;
519      }
520
521    return _evas_map_new(count);
522 }
523
524 EAPI void
525 evas_map_smooth_set(Evas_Map *m, Eina_Bool enabled)
526 {
527    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
528    return;
529    MAGIC_CHECK_END();
530
531    m->smooth = enabled;
532 }
533
534 EAPI Eina_Bool
535 evas_map_smooth_get(const Evas_Map *m)
536 {
537    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
538    return EINA_FALSE;
539    MAGIC_CHECK_END();
540
541    return m->smooth;
542 }
543
544 EAPI void
545 evas_map_alpha_set(Evas_Map *m, Eina_Bool enabled)
546 {
547    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
548    return;
549    MAGIC_CHECK_END();
550
551    m->alpha = enabled;
552 }
553
554 EAPI Eina_Bool
555 evas_map_alpha_get(const Evas_Map *m)
556 {
557    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
558    return EINA_FALSE;
559    MAGIC_CHECK_END();
560
561    return m->alpha;
562 }
563
564 EAPI Evas_Map *
565 evas_map_dup(const Evas_Map *m)
566 {
567    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
568    return NULL;
569    MAGIC_CHECK_END();
570
571    return _evas_map_dup(m);
572 }
573
574 EAPI void
575 evas_map_free(Evas_Map *m)
576 {
577    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
578    return;
579    MAGIC_CHECK_END();
580
581    _evas_map_free(NULL, m);
582 }
583
584 EAPI int
585 evas_map_count_get(const Evas_Map *m)
586 {
587    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
588    return -1;
589    MAGIC_CHECK_END();
590
591    return m->count;
592 }
593
594 EAPI void
595 evas_map_point_coord_set(Evas_Map *m, int idx, Evas_Coord x, Evas_Coord y, Evas_Coord z)
596 {
597    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
598    return;
599    MAGIC_CHECK_END();
600
601    Evas_Map_Point *p;
602
603    if (idx >= m->count) return;
604    p = m->points + idx;
605    p->x = p->px = x;
606    p->y = p->py = y;
607    p->z = z;
608 }
609
610 EAPI void
611 evas_map_point_coord_get(const Evas_Map *m, int idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z)
612 {
613    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
614    goto error;
615    MAGIC_CHECK_END();
616
617    const Evas_Map_Point *p;
618
619    if (idx >= m->count) goto error;
620    p = m->points + idx;
621    if (x) *x = p->x;
622    if (y) *y = p->y;
623    if (z) *z = p->z;
624    return;
625
626  error:
627    if (x) *x = 0;
628    if (y) *y = 0;
629    if (z) *z = 0;
630 }
631
632 EAPI void
633 evas_map_point_image_uv_set(Evas_Map *m, int idx, double u, double v)
634 {
635    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
636    return;
637    MAGIC_CHECK_END();
638
639    Evas_Map_Point *p;
640
641    if (idx >= m->count) return;
642    p = m->points + idx;
643    p->u = u;
644    p->v = v;
645 }
646
647 EAPI void
648 evas_map_point_image_uv_get(const Evas_Map *m, int idx, double *u, double *v)
649 {
650    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
651    goto error;
652    MAGIC_CHECK_END();
653
654    const Evas_Map_Point *p;
655
656    if (idx >= m->count) goto error;
657    p = m->points + idx;
658    if (u) *u = p->u;
659    if (v) *v = p->v;
660    return;
661
662  error:
663    if (u) *u = 0.0;
664    if (v) *v = 0.0;
665 }
666
667 EAPI void
668 evas_map_point_color_set(Evas_Map *m, int idx, int r, int g, int b, int a)
669 {
670    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
671    return;
672    MAGIC_CHECK_END();
673
674    Evas_Map_Point *p;
675
676    if (idx >= m->count) return;
677    p = m->points + idx;
678    p->r = r;
679    p->g = g;
680    p->b = b;
681    p->a = a;
682 }
683
684 EAPI void
685 evas_map_point_color_get(const Evas_Map *m, int idx, int *r, int *g, int *b, int *a)
686 {
687    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
688    return;
689    MAGIC_CHECK_END();
690
691    const Evas_Map_Point *p;
692
693    if (idx >= m->count) return;
694    p = m->points + idx;
695    if (r) *r = p->r;
696    if (g) *g = p->g;
697    if (b) *b = p->b;
698    if (a) *a = p->a;
699 }
700
701 EAPI void
702 evas_map_util_points_populate_from_object_full(Evas_Map *m, const Evas_Object *obj, Evas_Coord z)
703 {
704    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
705    return;
706    MAGIC_CHECK_END();
707
708    if (m->count != 4)
709      {
710         ERR("map has count=%d where 4 was expected.", m->count);
711         return;
712      }
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);
715 }
716
717 EAPI void
718 evas_map_util_points_populate_from_object(Evas_Map *m, const Evas_Object *obj)
719 {
720    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
721    return;
722    MAGIC_CHECK_END();
723
724    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
725    return;
726    MAGIC_CHECK_END();
727
728    if (m->count != 4)
729      {
730         ERR("map has count=%d where 4 was expected.", m->count);
731         return;
732      }
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);
735 }
736
737 EAPI void
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)
739 {
740    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
741    return;
742    MAGIC_CHECK_END();
743
744    if (m->count != 4)
745      {
746         ERR("map has count=%d where 4 was expected.", m->count);
747         return;
748      }
749    _evas_map_util_points_populate(m, x, y, w, h, z);
750 }
751
752 EAPI void
753 evas_map_util_points_color_set(Evas_Map *m, int r, int g, int b, int a)
754 {
755    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
756    return;
757    MAGIC_CHECK_END();
758
759    Evas_Map_Point *p, *p_end;
760
761    p = m->points;
762    p_end = p + m->count;
763    for (; p < p_end; p++)
764      {
765         p->r = r;
766         p->g = g;
767         p->b = b;
768         p->a = a;
769      }
770 }
771
772 EAPI void
773 evas_map_util_rotate(Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy)
774 {
775    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
776    return;
777    MAGIC_CHECK_END();
778
779    double r = (degrees * M_PI) / 180.0;
780    Evas_Map_Point *p, *p_end;
781
782    p = m->points;
783    p_end = p + m->count;
784
785    for (; p < p_end; p++)
786      {
787         double x, y, xx, yy;
788
789         x = p->x - cx;
790         y = p->y - cy;
791
792         xx = x * cos(r);
793         yy = x * sin(r);
794         x = xx - (y * sin(r));
795         y = yy + (y * cos(r));
796
797         p->px = p->x = x + cx;
798         p->py = p->y = y + cy;
799      }
800 }
801
802 EAPI void
803 evas_map_util_zoom(Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy)
804 {
805    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
806    return;
807    MAGIC_CHECK_END();
808
809    Evas_Map_Point *p, *p_end;
810
811    p = m->points;
812    p_end = p + m->count;
813
814    for (; p < p_end; p++)
815      {
816         double x, y;
817
818         x = p->x - cx;
819         y = p->y - cy;
820
821         x = (((double)x) * zoomx);
822         y = (((double)y) * zoomy);
823
824         p->px = p->x = x + cx;
825         p->py = p->y = y + cy;
826      }
827 }
828
829 EAPI void
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)
832 {
833    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
834    return;
835    MAGIC_CHECK_END();
836
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;
841
842    p = m->points;
843    p_end = p + m->count;
844
845    for (; p < p_end; p++)
846      {
847         double x, y, z, xx, yy, zz;
848
849         x = p->x - cx;
850         y = p->y - cy;
851         z = p->z - cz;
852
853         if (rz != 0.0)
854           {
855              xx = x * cos(rz);
856              yy = x * sin(rz);
857              x = xx - (y * sin(rz));
858              y = yy + (y * cos(rz));
859           }
860
861         if (ry != 0.0)
862           {
863              xx = x * cos(ry);
864              zz = x * sin(ry);
865              x = xx - (z * sin(ry));
866              z = zz + (z * cos(ry));
867           }
868
869         if (rx != 0.0)
870           {
871              zz = z * cos(rx);
872              yy = z * sin(rx);
873              z = zz - (y * sin(rx));
874              y = yy + (y * cos(rx));
875           }
876
877         p->px = p->x = x + cx;
878         p->py = p->y = y + cy;
879         p->z = z + cz;
880      }
881 }
882
883 EAPI void
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)
887 {
888    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
889    return;
890    MAGIC_CHECK_END();
891
892    int i;
893
894    for (i = 0; i < m->count; i++)
895      {
896         double x, y, z;
897         double nx, ny, nz, x1, yy1, z1, x2, yy2, z2, ln, br;
898         int h, j, mr, mg, mb;
899
900         x = m->points[i].x;
901         y = m->points[i].y;
902         z = m->points[i].z;
903         // calc normal
904         h = (i - 1 + 4) % 4 + (i & ~0x3); // prev point
905         j = (i + 1)     % 4 + (i & ~0x3); // next point
906
907         x1 = m->points[h].x - x;
908         yy1 = m->points[h].y - y;
909         z1 = m->points[h].z - z;
910
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);
917
918         ln = (nx * nx) + (ny * ny) + (nz * nz);
919         ln = sqrt(ln);
920
921         if (ln != 0.0)
922           {
923              nx /= ln;
924              ny /= ln;
925              nz /= ln;
926           }
927
928         // calc point -> light vector
929         x = lx - x;
930         y = ly - y;
931         z = lz - z;
932
933         ln = (x * x) + (y * y) + (z * z);
934         ln = sqrt(ln);
935
936         if (ln != 0.0)
937           {
938              x /= ln;
939              y /= ln;
940              z /= ln;
941           }
942
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;
946
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)
951           {
952              mr = (mr * m->points[i].a) / 255;
953              mg = (mg * m->points[i].a) / 255;
954              mb = (mb * m->points[i].a) / 255;
955           }
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;
959      }
960 }
961
962 EAPI void
963 evas_map_util_3d_perspective(Evas_Map *m,
964                              Evas_Coord px, Evas_Coord py,
965                              Evas_Coord z0, Evas_Coord foc)
966 {
967    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
968    return;
969    MAGIC_CHECK_END();
970
971    Evas_Map_Point *p, *p_end;
972
973    p = m->points;
974    p_end = p + m->count;
975
976    m->persp.px = px;
977    m->persp.py = py;
978    m->persp.z0 = z0;
979    m->persp.foc = foc;
980
981    if (foc <= 0) return;
982
983    for (; p < p_end; p++)
984      {
985         double x, y, zz;
986
987         x = p->x - px;
988         y = p->y - py;
989
990         zz = ((p->z - z0) + foc);
991
992         if (zz > 0)
993           {
994              x = (x * foc) / zz;
995              y = (y * foc) / zz;
996           }
997
998         p->x = px + x;
999         p->y = py + y;
1000      }
1001 }
1002
1003 EAPI Eina_Bool
1004 evas_map_util_clockwise_get(Evas_Map *m)
1005 {
1006    MAGIC_CHECK(m, Evas_Map, MAGIC_MAP);
1007    return EINA_FALSE;
1008    MAGIC_CHECK_END();
1009
1010    int i, j, k, count;
1011    long long c;
1012
1013    if (m->count < 3) return EINA_FALSE;
1014
1015    count = 0;
1016    for (i = 0; i < m->count; i++)
1017      {
1018         j = (i + 1) % m->count;
1019         k = (i + 2) % m->count;
1020         c =
1021           ((m->points[j].x - m->points[i].x) *
1022            (m->points[k].y - m->points[j].y))
1023           -
1024           ((m->points[j].y - m->points[i].y) *
1025            (m->points[k].x - m->points[j].x));
1026         if (c < 0) count--;
1027         else if (c > 0) count++;
1028      }
1029    if (count > 0) return EINA_TRUE;
1030    return EINA_FALSE;
1031 }
1032
1033 void
1034 evas_object_map_update(Evas_Object *obj,
1035                        int x, int y,
1036                        int imagew, int imageh,
1037                        int uvw, int uvh)
1038 {
1039    const Evas_Map_Point *p, *p_end;
1040    RGBA_Map_Point *pts, *pt;
1041
1042    if (obj->spans)
1043      {
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;
1048      }
1049    else
1050      {
1051         obj->changed_map = EINA_TRUE;
1052      }
1053
1054    if (!obj->changed_map) return ;
1055
1056    if (obj->cur.map && obj->spans && obj->cur.map->count != obj->spans->count)
1057      {
1058         if (obj->spans)
1059           {
1060              // Destroy engine side spans
1061              free(obj->spans);
1062           }
1063         obj->spans = NULL;
1064      }
1065
1066    if (!obj->spans)
1067      obj->spans = calloc(1, sizeof (RGBA_Map) +
1068                          sizeof (RGBA_Map_Point) * (obj->cur.map->count - 1));
1069
1070    if (!obj->spans) return ;
1071
1072    obj->spans->count = obj->cur.map->count;
1073    obj->spans->x = x;
1074    obj->spans->y = y;
1075    obj->spans->uv.w = uvw;
1076    obj->spans->uv.h = uvh;
1077    obj->spans->image.w = imagew;
1078    obj->spans->image.h = imageh;
1079
1080    pts = obj->spans->pts;
1081
1082    p = obj->cur.map->points;
1083    p_end = p + obj->cur.map->count;
1084    pt = pts;
1085              
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;
1090    // draw geom +x +y
1091    for (; p < p_end; p++, pt++)
1092      {
1093         pt->x = (lround(p->x) + x) * FP1;
1094         pt->y = (lround(p->y) + y) * FP1;
1095         pt->z = (lround(p->z)    ) * FP1;
1096         pt->fx = p->px;
1097         pt->fy = p->py;
1098         pt->fz = p->z;
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);
1106      }
1107    if (obj->cur.map->count & 0x1)
1108      {
1109         pts[obj->cur.map->count] = pts[obj->cur.map->count -1];
1110      }
1111
1112    // Request engine to update it's point
1113 }