a623912882047cdc820762d28d8465d52c18ad3f
[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, pass = 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 (!pass)
16           {
17              if (!obj->smart.smart)
18                {
19                   is = evas_object_is_in_output_rect(obj,
20                                                      obj->layer->evas->pointer.x,
21                                                      obj->layer->evas->pointer.y, 1, 1);
22                   if ((is ^ was) && obj->cur.visible)
23                     evas_event_feed_mouse_move(obj->layer->evas,
24                                                obj->layer->evas->pointer.x,
25                                                obj->layer->evas->pointer.y,
26                                                obj->layer->evas->last_timestamp,
27                                                NULL);
28                }
29           }
30      }
31    evas_object_inform_call_move(obj);
32    evas_object_inform_call_resize(obj);
33 }
34
35 static void
36 _evas_map_calc_map_geometry(Evas_Object *obj)
37 {
38    Evas_Coord x1, x2, y1, y2;
39    const Evas_Map_Point *p, *p_end;
40    int ch;
41
42    if (!obj->cur.map) return;
43    p = obj->cur.map->points;
44    p_end = p + obj->cur.map->count;
45    x1 = p->x;
46    x2 = p->x;
47    y1 = p->y;
48    y2 = p->y;
49    p++;
50    for (; p < p_end; p++)
51      {
52         if (p->x < x1) x1 = p->x;
53         if (p->x > x2) x2 = p->x;
54         if (p->y < y1) y1 = p->y;
55         if (p->y > y2) y2 = p->y;
56      }
57    ch = 0;
58    if (obj->cur.map->normal_geometry.x != x1) ch = 1;
59    if (obj->cur.map->normal_geometry.y != y1) ch = 1;
60    if (obj->cur.map->normal_geometry.w != (x2 - x1)) ch = 1;
61    if (obj->cur.map->normal_geometry.h != (y2 - y1)) ch = 1;
62    obj->cur.map->normal_geometry.x = x1;
63    obj->cur.map->normal_geometry.y = y1;
64    obj->cur.map->normal_geometry.w = (x2 - x1);
65    obj->cur.map->normal_geometry.h = (y2 - y1);
66    if (ch) _evas_map_calc_geom_change(obj);
67 }
68
69 static inline Evas_Map *
70 _evas_map_new(int count)
71 {
72    int i;
73    Evas_Map *m = calloc(1, sizeof(Evas_Map) + (count * sizeof(Evas_Map_Point)));
74    if (!m) return NULL;
75    m->count = count;
76    m->persp.foc = 0;
77    m->alpha = 1;
78    m->smooth = 1;
79    for (i = 0; i < count; i++)
80      {
81         m->points[i].r = 255;
82         m->points[i].g = 255;
83         m->points[i].b = 255;
84         m->points[i].a = 255;
85      }
86    return m;
87 }
88
89 static inline Eina_Bool
90 _evas_map_copy(Evas_Map *dst, const Evas_Map *src)
91 {
92    if (dst->count != src->count)
93      {
94         ERR("cannot copy map of different sizes: dst=%i, src=%i", dst->count, src->count);
95         return EINA_FALSE;
96      }
97    memcpy(dst->points, src->points, src->count * sizeof(Evas_Map_Point));
98    dst->smooth = src->smooth;
99    dst->alpha = src->alpha;
100    dst->persp = src->persp;
101    return EINA_TRUE;
102 }
103
104 static inline Evas_Map *
105 _evas_map_dup(const Evas_Map *orig)
106 {
107    Evas_Map *copy = _evas_map_new(orig->count);
108    if (!copy) return NULL;
109    memcpy(copy->points, orig->points, orig->count * sizeof(Evas_Map_Point));
110    copy->smooth = orig->smooth;
111    copy->alpha = orig->alpha;
112    copy->persp = orig->persp;
113    return copy;
114 }
115
116 static inline void
117 _evas_map_free(Evas_Object *obj, Evas_Map *m)
118 {
119    if (obj)
120      {
121         if (m->surface)
122           obj->layer->evas->engine.func->image_map_surface_free
123           (obj->layer->evas->engine.data.output, m->surface);
124      }
125    free(m);
126 }
127
128 Eina_Bool
129 evas_map_coords_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y,
130                     Evas_Coord *mx, Evas_Coord *my, int grab)
131 {
132    int i, j, edges, edge[4][2], douv;
133    Evas_Coord xe[2];
134    double u[2] = { 0.0, 0.0 };
135    double v[2] = { 0.0, 0.0 };
136
137    if (m->count != 4) return 0;
138    // FIXME need to handle grab mode and extrapolte coords outside
139    // map
140    if (grab)
141      {
142         Evas_Coord ymin, ymax;
143         
144         ymin = m->points[0].y;
145         ymax = m->points[0].y;
146         for (i = 1; i < m->count; i++)
147           {
148              if (m->points[i].y < ymin) ymin = m->points[i].y; 
149              else if (m->points[i].y > ymax) ymax = m->points[i].y; 
150           }
151         if (y <= ymin) y = ymin + 1;
152         if (y >= ymax) y = ymax - 1;
153      }
154    edges = 0;
155    for (i = 0; i < m->count; i++)
156      {
157         j = (i + 1) % m->count;
158         if ((m->points[i].y <= y) && (m->points[j].y > y))
159           {
160              edge[edges][0] = i;
161              edge[edges][1] = j;
162              edges++;
163           }
164         else if ((m->points[j].y <= y) && (m->points[i].y > y))
165           {
166              edge[edges][0] = j;
167              edge[edges][1] = i;
168              edges++;
169           }
170      }
171    douv = 0;
172    if ((mx) || (my)) douv = 1;
173    for (i = 0; i < (edges - 1); i+= 2)
174      {
175         Evas_Coord yp, yd;
176
177         j = i + 1;
178         yd = m->points[edge[i][1]].y - m->points[edge[i][0]].y;
179         if (yd > 0)
180           {
181              yp = y - m->points[edge[i][0]].y;
182              xe[0] = m->points[edge[i][1]].x - m->points[edge[i][0]].x;
183              xe[0] = m->points[edge[i][0]].x + ((xe[0] * yp) / yd);
184              if (douv)
185                {
186                   u[0] = m->points[edge[i][1]].u - m->points[edge[i][0]].u;
187                   u[0] = m->points[edge[i][0]].u + ((u[0] * yp) / yd);
188                   v[0] = m->points[edge[i][1]].v - m->points[edge[i][0]].v;
189                   v[0] = m->points[edge[i][0]].v + ((v[0] * yp) / yd);
190                }
191           }
192         else
193           {
194              xe[0] = m->points[edge[i][0]].x;
195              if (douv)
196                {
197                   u[0] = m->points[edge[i][0]].u;
198                   v[0] = m->points[edge[i][0]].v;
199                }
200           }
201         yd = m->points[edge[j][1]].y - m->points[edge[j][0]].y;
202         if (yd > 0)
203           {
204              yp = y - m->points[edge[j][0]].y;
205              xe[1] = m->points[edge[j][1]].x - m->points[edge[j][0]].x;
206              xe[1] = m->points[edge[j][0]].x + ((xe[1] * yp) / yd);
207              if (douv)
208                {
209                   u[1] = m->points[edge[j][1]].u - m->points[edge[j][0]].u;
210                   u[1] = m->points[edge[j][0]].u + ((u[1] * yp) / yd);
211                   v[1] = m->points[edge[j][1]].v - m->points[edge[j][0]].v;
212                   v[1] = m->points[edge[j][0]].v + ((v[1] * yp) / yd);
213                }
214           }
215         else
216           {
217              xe[1] = m->points[edge[j][0]].x;
218              if (douv)
219                {
220                   u[1] = m->points[edge[j][0]].u;
221                   v[1] = m->points[edge[j][0]].v;
222                }
223           }
224         if (xe[0] > xe[1])
225           {
226              int ti;
227              
228              ti = xe[0]; xe[0] = xe[1]; xe[1] = ti;
229              if (douv)
230                {
231                   double td;
232                   
233                   td = u[0]; u[0] = u[1]; u[1] = td;
234                   td = v[0]; v[0] = v[1]; v[1] = td;
235                }
236           }
237         if ((x >= xe[0]) && (x < xe[1]))
238           {
239              if (douv)
240                {
241                   if (mx) 
242                     *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) / 
243                                   (xe[1] - xe[0]));
244                  if (my)
245                     *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) / 
246                                   (xe[1] - xe[0]));
247                }
248              return 1;
249           }
250         if (grab)
251           {
252              if (douv)
253                {
254                   if (mx) 
255                     *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) / 
256                                   (xe[1] - xe[0]));
257                   if (my)
258                     *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) / 
259                                   (xe[1] - xe[0]));
260                }
261              return 1;
262           }
263      }
264    return 0;
265 }
266
267 Eina_Bool
268 evas_map_inside_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y)
269 {
270    return evas_map_coords_get(m, x, y, NULL, NULL, 0);
271 }
272
273
274 /**
275  * Enable or disable the map that is set.
276  * 
277  * This enables the map that is set or disables it. On enable, the object
278  * geometry will be saved, and the new geometry will change (position and
279  * size) to reflect the map geometry set. If none is set yet, this may be
280  * an undefined geometry, unless you have already set the map with
281  * evas_object_map_set(). It is suggested you first set a map with
282  * evas_object_map_set() with valid useful coordinates then enable and
283  * disable the map with evas_object_map_enable_set() as needed.
284  * 
285  * @param obj object to enable the map on
286  * @param enabled enabled state
287  */
288 EAPI void
289 evas_object_map_enable_set(Evas_Object *obj, Eina_Bool enabled)
290 {
291    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
292    return;
293    MAGIC_CHECK_END();
294    enabled = !!enabled;
295    if (obj->cur.usemap == enabled) return;
296    obj->cur.usemap = enabled;
297    if (enabled)
298      {
299         if (!obj->cur.map)
300           obj->cur.map = _evas_map_new(4);
301         evas_object_mapped_clip_across_mark(obj);
302 //        obj->cur.map->normal_geometry = obj->cur.geometry;
303      }
304    else
305      {
306         if (obj->cur.map)
307           {
308              _evas_map_calc_geom_change(obj);
309              evas_object_mapped_clip_across_mark(obj);
310           }
311      }
312    _evas_map_calc_map_geometry(obj);
313    /* This is a bit heavy handed, but it fixes the case of same geometry, but
314     * changed colour or UV settings. */
315    evas_object_change(obj);
316 }
317
318 /**
319  * Get the map enabled state
320  * 
321  * This returns the currently enabled state of the map on the object indicated.
322  * The default map enable state is off. You can enable and disable it with
323  * evas_object_map_enable_set().
324  * 
325  * @param obj object to get the map enabled state from
326  * @return the map enabled state
327  */
328 EAPI Eina_Bool
329 evas_object_map_enable_get(const Evas_Object *obj)
330 {
331    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
332    return 0;
333    MAGIC_CHECK_END();
334    return obj->cur.usemap;
335 }
336
337
338 /**
339  * Set the map source object
340  * 
341  * This sets the object from which the map is taken - can be any object that
342  * has map enabled on it.
343  * 
344  * Currently not implemented. for future use.
345  * 
346  * @param obj object to set the map source of
347  * @param src the source object from which the map is taken
348  */
349 EAPI void
350 evas_object_map_source_set(Evas_Object *obj, Evas_Object *src)
351 {
352    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
353    return;
354    MAGIC_CHECK_END();
355    (void)src; /* method still needs to be implemented. */
356 }
357
358 /**
359  * Get the map source object
360  * 
361  * See evas_object_map_source_set()
362  * 
363  * @param obj object to set the map source of
364  * @return the object set as the source
365  */
366 EAPI Evas_Object *
367 evas_object_map_source_get(const Evas_Object *obj)
368 {
369    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
370    return NULL;
371    MAGIC_CHECK_END();
372    return NULL;
373 }
374
375 /**
376  * Set current object transformation map.
377  * 
378  * This sets the map on a given object. It is copied from the @p map pointer,
379  * so there is no need to keep the @p map object if you don't need it anymore.
380  * 
381  * A map is a set of 4 points which have canvas x, y coordinates per point,
382  * with an optional z point value as a hint for perspective correction, if it
383  * is available. As well each point has u and v coordinates. These are like
384  * "texture coordinates" in OpenGL in that they define a point in the source
385  * image that is mapped to that map vertex/point. The u corresponds to the x
386  * coordinate of this mapped point and v, the y coordinate. Note that these
387  * coordinates describe a bounding region to sample. If you have a 200x100
388  * source image and want to display it at 200x100 with proper pixel
389  * precision, then do:
390  * 
391  * @code
392  * Evas_Map *m = evas_map_new(4);
393  * evas_map_point_coord_set(m, 0,   0,   0, 0);
394  * evas_map_point_coord_set(m, 1, 200,   0, 0);
395  * evas_map_point_coord_set(m, 2, 200, 100, 0);
396  * evas_map_point_coord_set(m, 3,   0, 100, 0);
397  * evas_map_point_image_uv_set(m, 0,   0,   0);
398  * evas_map_point_image_uv_set(m, 1, 200,   0);
399  * evas_map_point_image_uv_set(m, 2, 200, 100);
400  * evas_map_point_image_uv_set(m, 3,   0, 100);
401  * evas_object_map_set(obj, m);
402  * evas_map_free(m);
403  * @endcode
404  * 
405  * Note that the map points a uv coordinates match the image geometry. If
406  * the @p map parameter is NULL, the stored map will be freed and geometry
407  * prior to enabling/setting a map will be restored.
408  *
409  * @param obj object to change transformation map
410  * @param map new map to use
411  *
412  * @see evas_map_new()
413  */
414 EAPI void
415 evas_object_map_set(Evas_Object *obj, const Evas_Map *map)
416 {
417    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
418    return;
419    MAGIC_CHECK_END();
420    if (!map)
421      {
422         if (obj->cur.map)
423           {
424              if (obj->cur.map->surface)
425                {
426                   obj->layer->evas->engine.func->image_map_surface_free
427                     (obj->layer->evas->engine.data.output,
428                      obj->cur.map->surface);
429                   obj->cur.map->surface = NULL;
430                }
431              obj->prev.geometry = obj->cur.map->normal_geometry;
432              if (!obj->prev.map)
433                {
434                   _evas_map_free(obj, obj->cur.map);
435                   obj->cur.map = NULL;
436                   evas_object_mapped_clip_across_mark(obj);
437                   return;
438                }
439              _evas_map_free(obj, obj->cur.map);
440              obj->cur.map = NULL;
441              if (!obj->cur.usemap) _evas_map_calc_geom_change(obj);
442              else _evas_map_calc_map_geometry(obj);
443              if (obj->cur.usemap)
444                 evas_object_mapped_clip_across_mark(obj);
445           }
446         return;
447      }
448    if (!obj->cur.map)
449      {
450         obj->cur.map = _evas_map_dup(map);
451         if (obj->cur.usemap)
452            evas_object_mapped_clip_across_mark(obj);
453      }
454    else
455      {
456         Evas_Map *omap = obj->cur.map;
457         obj->cur.map = _evas_map_new(4);
458         memcpy(obj->cur.map, omap, sizeof(Evas_Map) + (4 * sizeof(Evas_Map_Point)));
459         _evas_map_copy(obj->cur.map, map);
460         free(omap);
461      }
462    _evas_map_calc_map_geometry(obj);
463 }
464
465 /**
466  * Get current object transformation map.
467  * 
468  * This returns the current internal map set on the indicated object. It is
469  * intended for read-only acces and is only valid as long as the object is
470  * not deleted or the map on the object is not changed. If you wish to modify
471  * the map and set it back do the following:
472  * 
473  * @code
474  * const Evas_Map *m = evas_object_map_get(obj);
475  * Evas_Map *m2 = evas_map_dup(m);
476  * evas_map_util_rotate(m2, 30.0, 0, 0);
477  * evas_object_map_set(obj);
478  * evas_map_free(m2);
479  * @endcode
480  *
481  * @param obj object to query transformation map.
482  * @return map reference to map in use. This is an internal data structure, so
483  * do not modify it.
484  *
485  * @see evas_object_map_set()
486  */
487 EAPI const Evas_Map *
488 evas_object_map_get(const Evas_Object *obj)
489 {
490    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
491    return NULL;
492    MAGIC_CHECK_END();
493    if (obj->cur.map) return obj->cur.map;
494    return NULL;
495 }
496
497 /**
498  * Create map of transformation points to be later used with an evas object.
499  *
500  * This creates a set of points (currently only 4 is supported. no other
501  * number for @p count will work). That is empty and ready to be modified
502  * with evas_map calls.
503  * 
504  * @param count number of points in the map. *
505  * @return a newly allocated map or NULL on errors.
506  *
507  * @see evas_map_free()
508  * @see evas_map_dup()
509  * @see evas_map_point_coord_set()
510  * @see evas_map_point_image_uv_set()
511  * @see evas_map_util_points_populate_from_object_full()
512  * @see evas_map_util_points_populate_from_object()
513  *
514  * @see evas_object_map_set()
515  */
516 EAPI Evas_Map *
517 evas_map_new(int count)
518 {
519    if (count != 4)
520      {
521         ERR("num (%i) != 4 is unsupported!", count);
522         return NULL;
523      }
524    return _evas_map_new(count);
525 }
526
527 /**
528  * Set the smoothing for map rendering
529  * 
530  * This sets smoothing for map rendering. If the object is a type that has
531  * its own smoothing settings, then both the smooth settings for this object
532  * and the map must be turned off. By default smooth maps are enabled.
533  * 
534  * @param m map to modify. Must not be NULL.
535  * @param enabled enable or disable smooth map rendering
536  */
537 EAPI void
538 evas_map_smooth_set(Evas_Map *m, Eina_Bool enabled)
539 {
540    if (!m) return;
541    m->smooth = enabled;
542 }
543
544 /**
545  * get the smoothing for map rendering
546  * 
547  * This gets smoothing for map rendering.
548  * 
549  * @param m map to get the smooth from. Must not be NULL.
550  */
551 EAPI Eina_Bool
552 evas_map_smooth_get(const Evas_Map *m)
553 {
554    if (!m) return 0;
555    return m->smooth;
556 }
557
558 /**
559  * Set the alpha flag for map rendering
560  * 
561  * This sets alpha flag for map rendering. If the object is a type that has
562  * its own alpha settings, then this will take precedence. Only image objects
563  * have this currently. Fits stops alpha blending of the map area, and is
564  * useful if you know the object and/or all sub-objects is 100% solid.
565  * 
566  * @param m map to modify. Must not be NULL.
567  * @param enabled enable or disable alpha map rendering
568  */
569 EAPI void
570 evas_map_alpha_set(Evas_Map *m, Eina_Bool enabled)
571 {
572    if (!m) return;
573    m->alpha = enabled;
574 }
575
576 /**
577  * get the alpha flag for map rendering
578  * 
579  * This gets the alph flag for map rendering.
580  * 
581  * @param m map to get the alpha from. Must not be NULL.
582  */
583 EAPI Eina_Bool
584 evas_map_alpha_get(const Evas_Map *m)
585 {
586    if (!m) return 0;
587    return m->alpha;
588 }
589
590 /**
591  * Copy a previously allocated map.
592  * 
593  * This makes a duplicate of the @p m object and returns it.
594  *
595  * @param m map to copy. Must not be NULL.
596  * @return newly allocated map with the same count and contents as @p m.
597  */
598 EAPI Evas_Map *
599 evas_map_dup(const Evas_Map *m)
600 {
601    if (!m) return NULL;
602    return _evas_map_dup(m);
603 }
604
605 /**
606  * Free a previously allocated map.
607  *
608  * This frees a givem map @p m and all memory associated with it. You must NOT
609  * free a map returned by evas_object_map_get() as this is internal.
610  * 
611  * @param m map to free.
612  */
613 EAPI void
614 evas_map_free(Evas_Map *m)
615 {
616    if (!m) return;
617    _evas_map_free(NULL, m);
618 }
619
620 /**
621  * Change the map point's coordinate.
622  * 
623  * This sets the fixen point's coordinate in the map. Note that points
624  * describe the outline of a quadrangle and are ordered either clockwise
625  * or anit-clock-wise. It is suggested to keep your quadrangles concave and
626  * non-complex, though these polygon modes may work, they may not render
627  * a desired set of output. The quadrangle will use points 0 and 1 , 1 and 2,
628  * 2 and 3, and 3 and 0 to describe the edges of the quandrangle.
629  * 
630  * The X and Y and Z coordinates are in canvas units. Z is optional and may
631  * or may not be honored in drawing. Z is a hint and does not affect the
632  * X and Y rendered coordinates. It may be used for calculating fills with
633  * perspective correct rendering.
634  * 
635  * Remember all coordinates are canvas global ones like with move and reize
636  * in evas.
637  *
638  * @param m map to change point. Must not be @c NULL.
639  * @param idx index of point to change. Must be smaller than map size.
640  * @param x Point X Coordinate
641  * @param y Point Y Coordinate
642  * @param z Point Z Coordinate hint (pre-perspective transform)
643  *
644  * @see evas_map_util_rotate()
645  * @see evas_map_util_zoom()
646  * @see evas_map_util_points_populate_from_object_full()
647  * @see evas_map_util_points_populate_from_object()
648  */
649 EAPI void
650 evas_map_point_coord_set(Evas_Map *m, int idx, Evas_Coord x, Evas_Coord y, Evas_Coord z)
651 {
652    Evas_Map_Point *p;
653    if (!m) return;
654    if (idx >= m->count) return;
655    p = m->points + idx;
656    p->x = p->px = x;
657    p->y = p->py = y;
658    p->z = z;
659 }
660
661 /**
662  * Get the map point's coordinate.
663  * 
664  * This returns the coordinates of the given point in the map.
665  *
666  * @param m map to query point.
667  * @param idx index of point to query. Must be smaller than map size.
668  * @param x where to return the X coordinate.
669  * @param y where to return the Y coordinate.
670  * @param z where to return the Z coordinate.
671  */
672 EAPI void
673 evas_map_point_coord_get(const Evas_Map *m, int idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z)
674 {
675    const Evas_Map_Point *p;
676    
677    if (!m) goto error;
678    if (idx >= m->count) goto error;
679    p = m->points + idx;
680    if (x) *x = p->x;
681    if (y) *y = p->y;
682    if (z) *z = p->z;
683    return;
684
685  error:
686    if (x) *x = 0;
687    if (y) *y = 0;
688    if (z) *z = 0;
689 }
690
691 /**
692  * Change the map point's U and V texture source point
693  *
694  * This sets the U and V coordinates for the point. This determines which
695  * coordinate in the source image is mapped to the given point, much like
696  * OpenGL and textures. Notes that these points do select the pixel, but
697  * are double floating point values to allow for accuracy and sub-pixel
698  * selection.
699  * 
700  * @param m map to change the point of.
701  * @param idx index of point to change. Must be smaller than map size.
702  * @param u the X coordinate within the image/texture source
703  * @param v the Y coordinate within the image/texture source
704  * 
705  * @see evas_map_point_coord_set()
706  * @see evas_object_map_set()
707  * @see evas_map_util_points_populate_from_object_full()
708  * @see evas_map_util_points_populate_from_object()
709  */
710 EAPI void
711 evas_map_point_image_uv_set(Evas_Map *m, int idx, double u, double v)
712 {
713    Evas_Map_Point *p;
714    if (!m) return;
715    if (idx >= m->count) return;
716    p = m->points + idx;
717    p->u = u;
718    p->v = v;
719 }
720
721 /**
722  * Get the map point's U and V texture source points
723  *
724  * This returns the texture points set by evas_map_point_image_uv_set().
725  * 
726  * @param m map to query point.
727  * @param idx index of point to query. Must be smaller than map size.
728  * @param u where to write the X coordinate within the image/texture source
729  * @param v where to write the Y coordinate within the image/texture source
730  */
731 EAPI void
732 evas_map_point_image_uv_get(const Evas_Map *m, int idx, double *u, double *v)
733 {
734    const Evas_Map_Point *p;
735    if (!m) goto error;
736    if (idx >= m->count) goto error;
737    p = m->points + idx;
738    if (u) *u = p->u;
739    if (v) *v = p->v;
740    return;
741
742  error:
743    if (u) *u = 0.0;
744    if (v) *v = 0.0;
745 }
746
747 /**
748  * Set the color of a vertex in the map
749  *
750  * This sets the color of the vertex in the map. Colors will be linearly
751  * interpolated between vertex points through the map. Color will multiply
752  * the "texture" pixels (like GL_MODULATE in OpenGL). The default color of
753  * a vertex in a map is white solid (255, 255, 255, 255) which means it will
754  * have no affect on modifying the texture pixels.
755  * 
756  * @param m map to change the color of.
757  * @param idx index of point to change. Must be smaller than map size.
758  * @param r red (0 - 255)
759  * @param g green (0 - 255)
760  * @param b blue (0 - 255)
761  * @param a alpha (0 - 255)
762  *
763  * @see evas_map_util_points_color_set()
764  * @see evas_map_point_coord_set()
765  * @see evas_object_map_set()
766  */
767 EAPI void
768 evas_map_point_color_set(Evas_Map *m, int idx, int r, int g, int b, int a)
769 {
770    Evas_Map_Point *p;
771    if (!m) return;
772    if (idx >= m->count) return;
773    p = m->points + idx;
774    p->r = r;
775    p->g = g;
776    p->b = b;
777    p->a = a;
778 }
779
780 /**
781  * Get the color set on a vertex in the map
782  *
783  * This gets the color set by evas_map_point_color_set() on the given vertex
784  * of the map.
785  * 
786  * @param m map to get the color of the vertex from.
787  * @param idx index of point get. Must be smaller than map size.
788  * @param r pointer to red return
789  * @param g pointer to green return
790  * @param b pointer to blue return
791  * @param a pointer to alpha return (0 - 255)
792  * 
793  * @see evas_map_point_coord_set()
794  * @see evas_object_map_set()
795  */
796 EAPI void
797 evas_map_point_color_get(const Evas_Map *m, int idx, int *r, int *g, int *b, int *a)
798 {
799    const Evas_Map_Point *p;
800    if (!m) return;
801    if (idx >= m->count) return;
802    p = m->points + idx;
803    if (r) *r = p->r;
804    if (g) *g = p->g;
805    if (b) *b = p->b;
806    if (a) *a = p->a;
807 }
808
809 /****************************************************************************/
810 /* util functions for manipulating maps, so you don't need to know the math */
811 /****************************************************************************/
812 static inline void
813 _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)
814 {
815    Evas_Map_Point *p = m->points;
816
817    p[0].x = x;
818    p[0].y = y;
819    p[0].z = z;
820    p[0].u = 0.0;
821    p[0].v = 0.0;
822
823    p[1].x = x + w;
824    p[1].y = y;
825    p[1].z = z;
826    p[1].u = w;
827    p[1].v = 0.0;
828
829    p[2].x = x + w;
830    p[2].y = y + h;
831    p[2].z = z;
832    p[2].u = w;
833    p[2].v = h;
834
835    p[3].x = x;
836    p[3].y = y + h;
837    p[3].z = z;
838    p[3].u = 0.0;
839    p[3].v = h;
840
841    p[0].px = p[0].x;
842    p[0].py = p[0].y;
843    p[1].px = p[1].x;
844    p[1].py = p[1].y;
845    p[2].px = p[2].x;
846    p[2].py = p[2].y;
847    p[3].px = p[3].x;
848    p[3].py = p[3].y;
849 }
850
851 /**
852  * Populate source and destination map points to match exactly object.
853  *
854  * Usually one initialize map of an object to match it's original
855  * position and size, then transform these with evas_map_util_*
856  * functions, such as evas_map_util_rotate() or
857  * evas_map_util_3d_rotate(). The original set is done by this
858  * function, avoiding code duplication all around.
859  *
860  * @param m map to change all 4 points (must be of size 4).
861  * @param obj object to use unmapped geometry to populate map coordinates.
862  * @param z Point Z Coordinate hint (pre-perspective transform). This value
863  *        will be used for all four points.
864  *
865  * @see evas_map_util_points_populate_from_object()
866  * @see evas_map_point_coord_set()
867  * @see evas_map_point_image_uv_set()
868  */
869 EAPI void
870 evas_map_util_points_populate_from_object_full(Evas_Map *m, const Evas_Object *obj, Evas_Coord z)
871 {
872    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
873    return;
874    MAGIC_CHECK_END();
875    if (!m)
876      {
877         ERR("map == NULL");
878         return;
879      }
880    if (m->count != 4)
881      {
882         ERR("map has count=%d where 4 was expected.", m->count);
883         return;
884      }
885    _evas_map_util_points_populate(m, obj->cur.geometry.x, obj->cur.geometry.y,
886                                   obj->cur.geometry.w, obj->cur.geometry.h, z);
887 }
888
889 /**
890  * Populate source and destination map points to match exactly object.
891  *
892  * Usually one initialize map of an object to match it's original
893  * position and size, then transform these with evas_map_util_*
894  * functions, such as evas_map_util_rotate() or
895  * evas_map_util_3d_rotate(). The original set is done by this
896  * function, avoiding code duplication all around.
897  *
898  * Z Point coordinate is assumed as 0 (zero).
899  *
900  * @param m map to change all 4 points (must be of size 4).
901  * @param obj object to use unmapped geometry to populate map coordinates.
902  *
903  * @see evas_map_util_points_populate_from_object_full()
904  * @see evas_map_util_points_populate_from_geometry()
905  * @see evas_map_point_coord_set()
906  * @see evas_map_point_image_uv_set()
907  */
908 EAPI void
909 evas_map_util_points_populate_from_object(Evas_Map *m, const Evas_Object *obj)
910 {
911    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
912    return;
913    MAGIC_CHECK_END();
914    if (!m)
915      {
916         ERR("map == NULL");
917         return;
918      }
919    if (m->count != 4)
920      {
921         ERR("map has count=%d where 4 was expected.", m->count);
922         return;
923      }
924    _evas_map_util_points_populate(m, obj->cur.geometry.x, obj->cur.geometry.y,
925                                   obj->cur.geometry.w, obj->cur.geometry.h, 0);
926 }
927
928 /**
929  * Populate source and destination map points to match given geometry.
930  *
931  * Similar to evas_map_util_points_populate_from_object_full(), this
932  * call takes raw values instead of querying object's unmapped
933  * geometry. The given width will be used to calculate destination
934  * points (evas_map_point_coord_set()) and set the image uv
935  * (evas_map_point_image_uv_set()).
936  *
937  * @param m map to change all 4 points (must be of size 4).
938  * @param x Point X Coordinate
939  * @param y Point Y Coordinate
940  * @param w width to use to calculate second and third points.
941  * @param h height to use to calculate third and fourth points.
942  * @param z Point Z Coordinate hint (pre-perspective transform). This value
943  *        will be used for all four points.
944  *
945  * @see evas_map_util_points_populate_from_object()
946  * @see evas_map_point_coord_set()
947  * @see evas_map_point_image_uv_set()
948  */
949 EAPI void
950 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)
951 {
952    if (!m)
953      {
954         ERR("map == NULL");
955         return;
956      }
957    if (m->count != 4)
958      {
959         ERR("map has count=%d where 4 was expected.", m->count);
960         return;
961      }
962    _evas_map_util_points_populate(m, x, y, w, h, z);
963 }
964
965 /**
966  * Set color of all points to given color.
967  *
968  * This call is useful to reuse maps after they had 3d lightning or
969  * any other colorization applied before.
970  *
971  * @param m map to change the color of.
972  * @param r red (0 - 255)
973  * @param g green (0 - 255)
974  * @param b blue (0 - 255)
975  * @param a alpha (0 - 255)
976  *
977  * @see evas_map_point_color_set()
978  */
979 EAPI void
980 evas_map_util_points_color_set(Evas_Map *m, int r, int g, int b, int a)
981 {
982    Evas_Map_Point *p, *p_end;
983    if (!m)
984      {
985         ERR("map == NULL");
986         return;
987      }
988    p = m->points;
989    p_end = p + m->count;
990    for (; p < p_end; p++)
991      {
992         p->r = r;
993         p->g = g;
994         p->b = b;
995         p->a = a;
996      }
997 }
998
999 /**
1000  * Change the map to apply the given rotation.
1001  * 
1002  * This rotates the indicated map's coordinates around the center coordinate
1003  * given by @p cx and @p cy as the rotation center. The points will have their
1004  * X and Y coordinates rotated clockwise by @p degrees degress (360.0 is a
1005  * full rotation). Negative values for degrees will rotate counter-clockwise
1006  * by that amount. All coordinates are canvas global coordinates.
1007  *
1008  * @param m map to change.
1009  * @param degrees amount of degrees from 0.0 to 360.0 to rotate.
1010  * @param cx rotation's center horizontal position.
1011  * @param cy rotation's center vertical position.
1012  *
1013  * @see evas_map_point_coord_set()
1014  * @see evas_map_util_zoom()
1015  */
1016 EAPI void
1017 evas_map_util_rotate(Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy)
1018 {
1019    double r = (degrees * M_PI) / 180.0;
1020    Evas_Map_Point *p, *p_end;
1021
1022    if (!m) return;
1023    p = m->points;
1024    p_end = p + m->count;
1025
1026    for (; p < p_end; p++)
1027      {
1028         Evas_Coord x, y, xx, yy;
1029
1030         xx = x = p->x - cx;
1031         yy = y = p->y - cy;
1032
1033         xx = (x * cos(r));
1034         yy = (x * sin(r));
1035         x = xx + (y * cos(r + (M_PI / 2.0)));
1036         y = yy + (y * sin(r + (M_PI / 2.0)));
1037
1038         p->x = x + cx;
1039         p->y = y + cy;
1040         p->px = p->x;
1041         p->py = p->y;
1042      }
1043 }
1044
1045 /**
1046  * Change the map to apply the given zooming.
1047  *
1048  * Like evas_map_util_rotate(), this zooms the points of the map from a center
1049  * point. That center is defined by @p cx and @p cy. The @p zoomx and @p zoomy
1050  * parameters specific how much to zoom in the X and Y direction respectively.
1051  * A value of 1.0 means "don't zoom". 2.0 means "dobule the size". 0.5 is
1052  * "half the size" etc. All coordinates are canvas global coordinates.
1053  * 
1054  * @param m map to change.
1055  * @param zoomx horizontal zoom to use.
1056  * @param zoomy vertical zoom to use.
1057  * @param cx zooming center horizontal position.
1058  * @param cy zooming center vertical position.
1059  *
1060  * @see evas_map_point_coord_set()
1061  * @see evas_map_util_rotate()
1062  */
1063 EAPI void
1064 evas_map_util_zoom(Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy)
1065 {
1066    Evas_Map_Point *p, *p_end;
1067
1068    if (!m) return;
1069    p = m->points;
1070    p_end = p + m->count;
1071
1072    for (; p < p_end; p++)
1073      {
1074         Evas_Coord x, y;
1075
1076         x = p->x - cx;
1077         y = p->y - cy;
1078
1079         x = (((double)x) * zoomx);
1080         y = (((double)y) * zoomy);
1081
1082         p->x = x + cx;
1083         p->y = y + cy;
1084         p->px = p->x;
1085         p->py = p->y;
1086      }
1087 }
1088
1089 /**
1090  * Rotate the map around 3 axes in 3D
1091  * 
1092  * This will rotate not just around the "Z" axis as in evas_map_util_rotate()
1093  * (which is a convenience call for those only wanting 2D). This will rotate
1094  * around the X, Y and Z axes. The Z axis points "into" the screen with low
1095  * values at the screen and higher values further away. The X axis runs from
1096  * left to right on the screen and the Y axis from top to bottom. Like with
1097  * evas_map_util_rotate(0 you provide a center point to rotate around (in 3D).
1098  *
1099  * @param m map to change.
1100  * @param dx amount of degrees from 0.0 to 360.0 to rotate arount X axis.
1101  * @param dy amount of degrees from 0.0 to 360.0 to rotate arount Y axis.
1102  * @param dz amount of degrees from 0.0 to 360.0 to rotate arount Z axis.
1103  * @param cx rotation's center horizontal position.
1104  * @param cy rotation's center vertical position.
1105  * @param cz rotation's center vertical position.
1106  */
1107 EAPI void
1108 evas_map_util_3d_rotate(Evas_Map *m, double dx, double dy, double dz, 
1109                         Evas_Coord cx, Evas_Coord cy, Evas_Coord cz)
1110 {
1111    double rz = (dz * M_PI) / 180.0;
1112    double rx = (dx * M_PI) / 180.0;
1113    double ry = (dy * M_PI) / 180.0;
1114    Evas_Map_Point *p, *p_end;
1115
1116    if (!m) return;
1117    p = m->points;
1118    p_end = p + m->count;
1119
1120    for (; p < p_end; p++)
1121      {
1122         double x, y, z, xx, yy, zz;
1123
1124         x = p->x - cx;
1125         y = p->y - cy;
1126         z = p->z - cz;
1127         
1128         if (rz != 0.0)
1129           {
1130              xx = x * cos(rz);
1131              yy = x * sin(rz);
1132              x = xx + (y * cos(rz + M_PI_2));
1133              y = yy + (y * sin(rz + M_PI_2));
1134           }
1135
1136         if (ry != 0.0)
1137           {
1138              xx = x * cos(ry);
1139              zz = x * sin(ry);
1140              x = xx + (z * cos(ry + M_PI_2));
1141              z = zz + (z * sin(ry + M_PI_2));
1142           }
1143         
1144         if (rx != 0.0)
1145           {
1146              zz = z * cos(rx);
1147              yy = z * sin(rx);
1148              z = zz + (y * cos(rx + M_PI_2));
1149              y = yy + (y * sin(rx + M_PI_2));
1150           }
1151         
1152         p->x = x + cx;
1153         p->y = y + cy;
1154         p->z = z + cz;
1155         p->px = p->x;
1156         p->py = p->y;
1157      }
1158 }
1159
1160 /**
1161  * Perform lighting calculations on the given Map
1162  * 
1163  * This is used to apply lighting calculations (from a single light source)
1164  * to a given map. The R, G and B values of each vertex will be modified to
1165  * reflect the lighting based on the lixth point coordinates, the light
1166  * color and the ambient color, and at what angle the map is facing the
1167  * light source. A surface should have its points be declared in a
1168  * clockwise fashion if the face is "facing" towards you (as opposed to
1169  * away from you) as faces have a "logical" side for lighting.
1170  *
1171  * @param m map to change.
1172  * @param lx X coordinate in space of light point
1173  * @param ly Y coordinate in space of light point
1174  * @param lz Z coordinate in space of light point
1175  * @param lr light red value (0 - 255)
1176  * @param lg light green value (0 - 255)
1177  * @param lb light blue value (0 - 255)
1178  * @param ar ambient color red value (0 - 255)
1179  * @param ag ambient color green value (0 - 255)
1180  * @param ab ambient color blue value (0 - 255)
1181  */
1182 EAPI void
1183 evas_map_util_3d_lighting(Evas_Map *m, 
1184                           Evas_Coord lx, Evas_Coord ly, Evas_Coord lz,
1185                           int lr, int lg, int lb, int ar, int ag, int ab)
1186 {
1187    int i;
1188    
1189    if (!m) return;
1190    
1191    for (i = 0; i < m->count; i++)
1192      {
1193         double x, y, z;
1194         double nx, ny, nz, x1, y1, z1, x2, y2, z2, ln, br;
1195         int h, j, mr, mg, mb;
1196         
1197         x = m->points[i].x;
1198         y = m->points[i].y;
1199         z = m->points[i].z;
1200         
1201         // calc normal
1202         h = (i + m->count - 1) % m->count; // prev point
1203         j = (i + 1) % m->count; // next point
1204
1205         x1 = m->points[h].x - x;
1206         y1 = m->points[h].y - y;
1207         z1 = m->points[h].z - z;
1208         
1209         x2 = m->points[j].x - x;
1210         y2 = m->points[j].y - y;
1211         z2 = m->points[j].z - z;
1212         
1213         nx = (y1 * z2) - (z1 * y2);
1214         ny = (z1 * x2) - (x1 * z2);
1215         nz = (x1 * y2) - (y1 * x2);
1216         
1217         ln = (nx * nx) + (ny * ny) + (nz * nz);
1218         ln = sqrt(ln);
1219         
1220         if (ln != 0.0)
1221           {
1222              nx /= ln;
1223              ny /= ln;
1224              nz /= ln;
1225           }
1226         
1227         // calc point -> light vector
1228         x = lx - x;
1229         y = ly - y;
1230         z = lz - z;
1231         
1232         ln = (x * x) + (y * y) + (z * z);
1233         ln = sqrt(ln);
1234         
1235         if (ln != 0.0)
1236           {
1237              x /= ln;
1238              y /= ln;
1239              z /= ln;
1240           }
1241         
1242         // brightness - tan (0.0 -> 1.0 brightness really)
1243         br = (nx * x) + (ny * y) + (nz * z);
1244         if (br < 0.0) br = 0.0;
1245         
1246         mr = ar + ((lr - ar) * br);
1247         mg = ag + ((lg - ag) * br);
1248         mb = ab + ((lb - ab) * br);
1249         mr = (mr * m->points[i].a) / 255;
1250         mg = (mg * m->points[i].a) / 255;
1251         mb = (mb * m->points[i].a) / 255;
1252         m->points[i].r = (m->points[i].r * mr) / 255;
1253         m->points[i].g = (m->points[i].g * mg) / 255;
1254         m->points[i].b = (m->points[i].b * mb) / 255;
1255      }
1256 }
1257
1258 /**
1259  * Apply a perspective transform to the map
1260
1261  * This applies a given perspective (3D) to the map coordinates. X, Y and Z
1262  * values are used. The px and py points specify the "infinite distance" point
1263  * in the 3D conversion (where all lines converge to like when artists draw
1264  * 3D by hand). The @p z0 value specifis the z value at which there is a 1:1
1265  * mapping between spatial coorinates and screen coordinates. Any points
1266  * on this z value will not have their X and Y values modified in the transform.
1267  * Those further away (Z value higher) will shrink into the distance, and
1268  * those less than this value will expand and become bigger. The @p foc value
1269  * determines the "focal length" of the camera. This is in reality the distance
1270  * between the camera lens plane itself (at or closer than this rendering
1271  * results are undefined) and the "z0" z value. This allows for some "depth"
1272  * control and @p foc must be greater than 0.
1273  *
1274  * @param m map to change.
1275  * @param px The pespective distance X coordinate
1276  * @param py The pespective distance Y coordinate
1277  * @param z0 The "0" z plane value
1278  * @param foc The focal distance
1279  */
1280 EAPI void
1281 evas_map_util_3d_perspective(Evas_Map *m,
1282                              Evas_Coord px, Evas_Coord py,
1283                              Evas_Coord z0, Evas_Coord foc)
1284 {
1285    Evas_Map_Point *p, *p_end;
1286
1287    if (!m) return;
1288    p = m->points;
1289    p_end = p + m->count;
1290
1291    m->persp.px = px;
1292    m->persp.py = py;
1293    m->persp.z0 = z0;
1294    m->persp.foc = foc;
1295    for (; p < p_end; p++)
1296      {
1297         Evas_Coord x, y, zz;
1298
1299         if (foc > 0)
1300           {
1301              x = p->x - px;
1302              y = p->y - py;
1303              
1304              zz = ((p->z - z0) + foc);
1305              
1306              if (zz > 0)
1307                {
1308                   x = (x * foc) / zz;
1309                   y = (y * foc) / zz;
1310                }
1311              
1312              p->x = px + x;
1313              p->y = py + y;
1314           }
1315      }
1316 }
1317
1318 /**
1319  * Get the clockwise state of a map
1320  * 
1321  * This determines if the output points (X and Y. Z is not used) are
1322  * clockwise or anti-clockwise. This can be used for "back-face culling". This
1323  * is where you hide objects that "face away" from you. In this case objects
1324  * that are not clockwise.
1325  *
1326  * @param m map to query.
1327  * @return 1 if clockwise, 0 otherwise
1328  */
1329 EAPI Eina_Bool
1330 evas_map_util_clockwise_get(Evas_Map *m)
1331 {
1332    int i, j, k, count;
1333    long long c;
1334    
1335    if (!m) return 0;
1336    if (m->count < 3) return 0;
1337    
1338    count = 0;
1339    for (i = 0; i < m->count; i++)
1340      {
1341         j = (i + 1) % m->count; 
1342         k = (i + 2) % m->count;
1343         c = 
1344           ((m->points[j].x - m->points[i].x) *
1345            (m->points[k].y - m->points[j].y))
1346           -
1347           ((m->points[j].y - m->points[i].y) *
1348            (m->points[k].x - m->points[j].x));
1349         if (c < 0) count--;
1350         else if (c > 0) count++;
1351      }
1352    if (count > 0) return 1;
1353    return 0;
1354 }
1355
1356 /**
1357  * @}
1358  */