1 #include "evas_common.h"
2 #include "evas_private.h"
6 _evas_map_calc_geom_change(Evas_Object *obj)
8 int is, was = 0, pass = 0;
10 evas_object_change(obj);
11 evas_object_clip_dirty(obj);
12 if (obj->layer->evas->events_frozen <= 0)
14 evas_object_recalc_clippees(obj);
17 if (!obj->smart.smart)
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,
31 evas_object_inform_call_move(obj);
32 evas_object_inform_call_resize(obj);
36 _evas_map_calc_map_geometry(Evas_Object *obj)
38 Evas_Coord x1, x2, y1, y2;
39 const Evas_Map_Point *p, *p_end;
42 if (!obj->cur.map) return;
43 p = obj->cur.map->points;
44 p_end = p + obj->cur.map->count;
50 for (; p < p_end; p++)
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;
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);
69 static inline Evas_Map *
70 _evas_map_new(int count)
73 Evas_Map *m = calloc(1, sizeof(Evas_Map) + (count * sizeof(Evas_Map_Point)));
79 for (i = 0; i < count; i++)
89 static inline Eina_Bool
90 _evas_map_copy(Evas_Map *dst, const Evas_Map *src)
92 if (dst->count != src->count)
94 ERR("cannot copy map of different sizes: dst=%i, src=%i", dst->count, src->count);
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;
104 static inline Evas_Map *
105 _evas_map_dup(const Evas_Map *orig)
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;
117 _evas_map_free(Evas_Object *obj, Evas_Map *m)
122 obj->layer->evas->engine.func->image_map_surface_free
123 (obj->layer->evas->engine.data.output, m->surface);
129 evas_map_coords_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y,
130 Evas_Coord *mx, Evas_Coord *my, int grab)
132 int i, j, edges, edge[4][2], douv;
134 double u[2] = { 0.0, 0.0 };
135 double v[2] = { 0.0, 0.0 };
137 if (m->count != 4) return 0;
138 // FIXME need to handle grab mode and extrapolte coords outside
142 Evas_Coord ymin, ymax;
144 ymin = m->points[0].y;
145 ymax = m->points[0].y;
146 for (i = 1; i < m->count; i++)
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;
151 if (y <= ymin) y = ymin + 1;
152 if (y >= ymax) y = ymax - 1;
155 for (i = 0; i < m->count; i++)
157 j = (i + 1) % m->count;
158 if ((m->points[i].y <= y) && (m->points[j].y > y))
164 else if ((m->points[j].y <= y) && (m->points[i].y > y))
172 if ((mx) || (my)) douv = 1;
173 for (i = 0; i < (edges - 1); i+= 2)
178 yd = m->points[edge[i][1]].y - m->points[edge[i][0]].y;
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);
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);
194 xe[0] = m->points[edge[i][0]].x;
197 u[0] = m->points[edge[i][0]].u;
198 v[0] = m->points[edge[i][0]].v;
201 yd = m->points[edge[j][1]].y - m->points[edge[j][0]].y;
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);
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);
217 xe[1] = m->points[edge[j][0]].x;
220 u[1] = m->points[edge[j][0]].u;
221 v[1] = m->points[edge[j][0]].v;
228 ti = xe[0]; xe[0] = xe[1]; xe[1] = ti;
233 td = u[0]; u[0] = u[1]; u[1] = td;
234 td = v[0]; v[0] = v[1]; v[1] = td;
237 if ((x >= xe[0]) && (x < xe[1]))
242 *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) /
245 *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) /
255 *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) /
258 *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) /
268 evas_map_inside_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y)
270 return evas_map_coords_get(m, x, y, NULL, NULL, 0);
275 * Enable or disable the map that is set.
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.
285 * @param obj object to enable the map on
286 * @param enabled enabled state
289 evas_object_map_enable_set(Evas_Object *obj, Eina_Bool enabled)
291 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
295 if (obj->cur.usemap == enabled) return;
296 obj->cur.usemap = enabled;
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;
308 _evas_map_calc_geom_change(obj);
309 evas_object_mapped_clip_across_mark(obj);
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);
319 * Get the map enabled state
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().
325 * @param obj object to get the map enabled state from
326 * @return the map enabled state
329 evas_object_map_enable_get(const Evas_Object *obj)
331 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
334 return obj->cur.usemap;
339 * Set the map source object
341 * This sets the object from which the map is taken - can be any object that
342 * has map enabled on it.
344 * Currently not implemented. for future use.
346 * @param obj object to set the map source of
347 * @param src the source object from which the map is taken
350 evas_object_map_source_set(Evas_Object *obj, Evas_Object *src)
352 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
355 (void)src; /* method still needs to be implemented. */
359 * Get the map source object
361 * See evas_object_map_source_set()
363 * @param obj object to set the map source of
364 * @return the object set as the source
367 evas_object_map_source_get(const Evas_Object *obj)
369 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
376 * Set current object transformation map.
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.
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:
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);
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.
409 * @param obj object to change transformation map
410 * @param map new map to use
412 * @see evas_map_new()
415 evas_object_map_set(Evas_Object *obj, const Evas_Map *map)
417 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
424 if (obj->cur.map->surface)
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;
431 obj->prev.geometry = obj->cur.map->normal_geometry;
434 _evas_map_free(obj, obj->cur.map);
436 evas_object_mapped_clip_across_mark(obj);
439 _evas_map_free(obj, obj->cur.map);
441 if (!obj->cur.usemap) _evas_map_calc_geom_change(obj);
442 else _evas_map_calc_map_geometry(obj);
444 evas_object_mapped_clip_across_mark(obj);
450 obj->cur.map = _evas_map_dup(map);
452 evas_object_mapped_clip_across_mark(obj);
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);
462 _evas_map_calc_map_geometry(obj);
466 * Get current object transformation map.
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:
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);
481 * @param obj object to query transformation map.
482 * @return map reference to map in use. This is an internal data structure, so
485 * @see evas_object_map_set()
487 EAPI const Evas_Map *
488 evas_object_map_get(const Evas_Object *obj)
490 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
493 if (obj->cur.map) return obj->cur.map;
498 * Create map of transformation points to be later used with an evas object.
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.
504 * @param count number of points in the map. *
505 * @return a newly allocated map or NULL on errors.
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()
514 * @see evas_object_map_set()
517 evas_map_new(int count)
521 ERR("num (%i) != 4 is unsupported!", count);
524 return _evas_map_new(count);
528 * Set the smoothing for map rendering
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.
534 * @param m map to modify. Must not be NULL.
535 * @param enabled enable or disable smooth map rendering
538 evas_map_smooth_set(Evas_Map *m, Eina_Bool enabled)
545 * get the smoothing for map rendering
547 * This gets smoothing for map rendering.
549 * @param m map to get the smooth from. Must not be NULL.
552 evas_map_smooth_get(const Evas_Map *m)
559 * Set the alpha flag for map rendering
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.
566 * @param m map to modify. Must not be NULL.
567 * @param enabled enable or disable alpha map rendering
570 evas_map_alpha_set(Evas_Map *m, Eina_Bool enabled)
577 * get the alpha flag for map rendering
579 * This gets the alph flag for map rendering.
581 * @param m map to get the alpha from. Must not be NULL.
584 evas_map_alpha_get(const Evas_Map *m)
591 * Copy a previously allocated map.
593 * This makes a duplicate of the @p m object and returns it.
595 * @param m map to copy. Must not be NULL.
596 * @return newly allocated map with the same count and contents as @p m.
599 evas_map_dup(const Evas_Map *m)
602 return _evas_map_dup(m);
606 * Free a previously allocated map.
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.
611 * @param m map to free.
614 evas_map_free(Evas_Map *m)
617 _evas_map_free(NULL, m);
621 * Change the map point's coordinate.
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.
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.
635 * Remember all coordinates are canvas global ones like with move and reize
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)
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()
650 evas_map_point_coord_set(Evas_Map *m, int idx, Evas_Coord x, Evas_Coord y, Evas_Coord z)
654 if (idx >= m->count) return;
662 * Get the map point's coordinate.
664 * This returns the coordinates of the given point in the map.
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.
673 evas_map_point_coord_get(const Evas_Map *m, int idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z)
675 const Evas_Map_Point *p;
678 if (idx >= m->count) goto error;
692 * Change the map point's U and V texture source point
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
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
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()
711 evas_map_point_image_uv_set(Evas_Map *m, int idx, double u, double v)
715 if (idx >= m->count) return;
722 * Get the map point's U and V texture source points
724 * This returns the texture points set by evas_map_point_image_uv_set().
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
732 evas_map_point_image_uv_get(const Evas_Map *m, int idx, double *u, double *v)
734 const Evas_Map_Point *p;
736 if (idx >= m->count) goto error;
748 * Set the color of a vertex in the map
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.
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)
763 * @see evas_map_util_points_color_set()
764 * @see evas_map_point_coord_set()
765 * @see evas_object_map_set()
768 evas_map_point_color_set(Evas_Map *m, int idx, int r, int g, int b, int a)
772 if (idx >= m->count) return;
781 * Get the color set on a vertex in the map
783 * This gets the color set by evas_map_point_color_set() on the given vertex
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)
793 * @see evas_map_point_coord_set()
794 * @see evas_object_map_set()
797 evas_map_point_color_get(const Evas_Map *m, int idx, int *r, int *g, int *b, int *a)
799 const Evas_Map_Point *p;
801 if (idx >= m->count) return;
809 /****************************************************************************/
810 /* util functions for manipulating maps, so you don't need to know the math */
811 /****************************************************************************/
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)
815 Evas_Map_Point *p = m->points;
852 * Populate source and destination map points to match exactly object.
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.
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.
865 * @see evas_map_util_points_populate_from_object()
866 * @see evas_map_point_coord_set()
867 * @see evas_map_point_image_uv_set()
870 evas_map_util_points_populate_from_object_full(Evas_Map *m, const Evas_Object *obj, Evas_Coord z)
872 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
882 ERR("map has count=%d where 4 was expected.", m->count);
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);
890 * Populate source and destination map points to match exactly object.
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.
898 * Z Point coordinate is assumed as 0 (zero).
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.
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()
909 evas_map_util_points_populate_from_object(Evas_Map *m, const Evas_Object *obj)
911 MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
921 ERR("map has count=%d where 4 was expected.", m->count);
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);
929 * Populate source and destination map points to match given geometry.
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()).
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.
945 * @see evas_map_util_points_populate_from_object()
946 * @see evas_map_point_coord_set()
947 * @see evas_map_point_image_uv_set()
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)
959 ERR("map has count=%d where 4 was expected.", m->count);
962 _evas_map_util_points_populate(m, x, y, w, h, z);
966 * Set color of all points to given color.
968 * This call is useful to reuse maps after they had 3d lightning or
969 * any other colorization applied before.
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)
977 * @see evas_map_point_color_set()
980 evas_map_util_points_color_set(Evas_Map *m, int r, int g, int b, int a)
982 Evas_Map_Point *p, *p_end;
989 p_end = p + m->count;
990 for (; p < p_end; p++)
1000 * Change the map to apply the given rotation.
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.
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.
1013 * @see evas_map_point_coord_set()
1014 * @see evas_map_util_zoom()
1017 evas_map_util_rotate(Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy)
1019 double r = (degrees * M_PI) / 180.0;
1020 Evas_Map_Point *p, *p_end;
1024 p_end = p + m->count;
1026 for (; p < p_end; p++)
1028 Evas_Coord x, y, xx, yy;
1035 x = xx + (y * cos(r + (M_PI / 2.0)));
1036 y = yy + (y * sin(r + (M_PI / 2.0)));
1046 * Change the map to apply the given zooming.
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.
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.
1060 * @see evas_map_point_coord_set()
1061 * @see evas_map_util_rotate()
1064 evas_map_util_zoom(Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy)
1066 Evas_Map_Point *p, *p_end;
1070 p_end = p + m->count;
1072 for (; p < p_end; p++)
1079 x = (((double)x) * zoomx);
1080 y = (((double)y) * zoomy);
1090 * Rotate the map around 3 axes in 3D
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).
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.
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)
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;
1118 p_end = p + m->count;
1120 for (; p < p_end; p++)
1122 double x, y, z, xx, yy, zz;
1132 x = xx + (y * cos(rz + M_PI_2));
1133 y = yy + (y * sin(rz + M_PI_2));
1140 x = xx + (z * cos(ry + M_PI_2));
1141 z = zz + (z * sin(ry + M_PI_2));
1148 z = zz + (y * cos(rx + M_PI_2));
1149 y = yy + (y * sin(rx + M_PI_2));
1161 * Perform lighting calculations on the given Map
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.
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)
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)
1191 for (i = 0; i < m->count; i++)
1194 double nx, ny, nz, x1, y1, z1, x2, y2, z2, ln, br;
1195 int h, j, mr, mg, mb;
1202 h = (i + m->count - 1) % m->count; // prev point
1203 j = (i + 1) % m->count; // next point
1205 x1 = m->points[h].x - x;
1206 y1 = m->points[h].y - y;
1207 z1 = m->points[h].z - z;
1209 x2 = m->points[j].x - x;
1210 y2 = m->points[j].y - y;
1211 z2 = m->points[j].z - z;
1213 nx = (y1 * z2) - (z1 * y2);
1214 ny = (z1 * x2) - (x1 * z2);
1215 nz = (x1 * y2) - (y1 * x2);
1217 ln = (nx * nx) + (ny * ny) + (nz * nz);
1227 // calc point -> light vector
1232 ln = (x * x) + (y * y) + (z * z);
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;
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;
1259 * Apply a perspective transform to the map
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.
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
1281 evas_map_util_3d_perspective(Evas_Map *m,
1282 Evas_Coord px, Evas_Coord py,
1283 Evas_Coord z0, Evas_Coord foc)
1285 Evas_Map_Point *p, *p_end;
1289 p_end = p + m->count;
1295 for (; p < p_end; p++)
1297 Evas_Coord x, y, zz;
1304 zz = ((p->z - z0) + foc);
1319 * Get the clockwise state of a map
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.
1326 * @param m map to query.
1327 * @return 1 if clockwise, 0 otherwise
1330 evas_map_util_clockwise_get(Evas_Map *m)
1336 if (m->count < 3) return 0;
1339 for (i = 0; i < m->count; i++)
1341 j = (i + 1) % m->count;
1342 k = (i + 2) % m->count;
1344 ((m->points[j].x - m->points[i].x) *
1345 (m->points[k].y - m->points[j].y))
1347 ((m->points[j].y - m->points[i].y) *
1348 (m->points[k].x - m->points[j].x));
1350 else if (c > 0) count++;
1352 if (count > 0) return 1;