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