www-content/pages/program_guide/event_effect/evas_map_animations.txt

578 lines
21 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

~~Title: Evas Map Effects~~
{{page>index}}
----
===== Evas Map Effects =====
Evas Map animations allow you to apply transformations to all types of objects
by way of UV mapping.
In UV mapping, you map points in the source object to 3D space positions in
the target object. This allows for rotation, perspective, scale, and other
transformation effects, depending on the map. In addition, each map point can
carry a multiplier color, which, if properly calculated, can be used to apply
3D shading effects on the target object.
Evas provides both raw and easy-to-use functions for UV mapping. The raw
functions allow you to create UV maps outside Evas and import them into your
application, for example by loading them from an external file. The
easy-to-use functions allow you to create UV maps directly in Evas by
calculating the map points based on high-level parameters, such as rotation
angle and ambient light.
=== Table of Contents ===
* [[#Map_Points|Map Points]]
* [[#Utility_Functions|Utility Functions]]
* [[#Zoom|Zoom]]
* [[#3D_Maps|3D Maps]]
* [[#3D_Rotation_and_Perspective|3D Rotation and Perspective]]
* [[#Color_and_Lighting|Color and Lighting]]
* [[#Mapping|Mapping]]
* [[#Lighting|Lighting]]
* [[#Alpha_Channel|Alpha Channel]]
* [[#Smoothing|Smoothing]]
=== Related Info ===
* [[https://build.enlightenment.org/job/nightly_efl_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/group__Evas__Object__Group__Map.html | Evas Map API]]
* [[https://build.enlightenment.org/job/nightly_efl_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/Example_Evas_Map_Overview.html|Evas Map Example]]
==== Map Points ====
A map consists of a set of points. (Currently, only four points are
supported.) Each point contains X and Y canvas coordinates that can be used to
alter the geometry of the mapped object, and a Z coordinate that indicates the
depth of the point. The Z coordinate does not normally affect the map, but
several utility functions use it to calculate the right position of the point
given the other parameters.
First, create an ''Evas_Map'' object using the ''evas_map_new()'' function.
This function creates the specified number of map points (currently only up to
four points). Each point is empty and ready to be modified with ''Evas_Map''
functions.
<code c>
Evas_Map *m = evas_map_new(4);
</code>
If you want to get the size (number of points) of an existing map, use the
''evas_map_count_get()'' function.
To set the coordinates for each point, use the ''evas_map_point_coord_set()''
function:
<code c>
evas_map_point_coord_set(Evas_Map *m, int idx, Evas_Coord x, Evas_Coord y, Evas_Coord z)
</code>
The following example shows a common way to define a map that matches the
geometry of a rectangle (a square in this case):
<code c>
evas_map_point_coord_set(m, 0, 100, 100, 0);
evas_map_point_coord_set(m, 1, 300, 100, 0);
evas_map_point_coord_set(m, 2, 300, 300, 0);
evas_map_point_coord_set(m, 3, 100, 300, 0);
</code>
{{ :event_effect_evas_map_1.png }}
The following examples all produce the same result as the above example, but
with simpler code:
* To create a rectangle map using the starting X and Y coordinates combined with width and height, use the ''evas_map_util_points_populate_from_geometry()'' function:
<code c>
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)
</code>
The following example creates the same map as above:
<code c>
evas_map_util_points_populate_from_geometry(m, 100, 100, 200, 200, 0);
</code>
* To create a map based on the geometry of a given object, use the ''evas_map_util_points_populate_from_object()'' or ''evas_map_util_points_populate_from_object_full()'' function. The former sets the Z coordinate of all points to 0, whereas the latter allows you to define the same custom Z coordinate for all points:
<code c>
evas_map_util_points_populate_from_object(Evas_Map *m, const Evas_Object *obj)
</code>
<code c>
evas_map_util_points_populate_from_object_full(Evas_Map *m, const Evas_Object *obj, Evas_Coord z)
</code>
The following example creates the same map as above:
<code c>
Evas_Object *o;
evas_object_move(o, 100, 100);
evas_object_resize(o, 200, 200);
evas_map_util_points_populate_from_object(m, o);
// OR
evas_map_util_points_populate_from_object_full(m, o, 0);
</code>
You can apply several effects to an object by simply setting each point of the
map to the appropriate coordinates. The following example shows how to create
a simulated perspective:
{{ :event_effect_evas_map_2.png }}
<code c>
evas_map_point_coord_set(m, 0, 100, 100, 0);
evas_map_point_coord_set(m, 1, 250, 120, 0);
evas_map_point_coord_set(m, 2, 250, 280, 0);
evas_map_point_coord_set(m, 0, 100, 300, 0);
</code>
In the above example, the Z coordinate is unused: when setting points by hand,
the Z coordinate is irrelevant.
If you want to get the actual coordinates of a map, use the
''evas_map_point_coord_get()'' function:
<code c>
evas_map_point_coord_get(const Evas_Map *m, int idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z)
</code>
After you have defined the map points, apply them to your map for
transformation:
<code c>
evas_object_map_set(o, m);
evas_object_map_enable_set(o, EINA_TRUE);
</code>
Finally, after you are done with the map, release the memory allocated to it
using the ''evas_map_free()'' function:
<code c>
evas_map_free(m);
</code>
The utility functions described in the next section allow you to perform the
above tasks with less coding work.
==== Utility Functions ====
Utility functions take an already configured map and allow you to easily
modify it to produce specific effects. For example, to rotate an object around
its center, you need the rotation angle and the coordinates of each corner of
the object to perform the math required to get the new set of coordinates that
needs to be set for the map. Evas provides a utility function that does the
math for you:
<code c>
void evas_map_util_rotate(Evas_Map * m,
double degrees,
Evas_Coord cx,
Evas_Coord cy
)
</code>
* ''m'' map to change.
* ''zoomx'' horizontal zoom to use.
* ''zoomy'' vertical zoom to use.
* ''cx'' zooming center horizontal position.
* ''cy'' zooming center vertical position.
This function rotates the map based on the angle and the center coordinates of
the rotation provided as arguments. A positive angle rotates the map
clockwise, while a negative angle rotates the map counterclockwise.
The following example shows how to rotate an object around its center point by
45 degrees clockwise. In the following figure, the center of rotation is the
red dot.
<code c>
evas_object_geometry_get(o, &x, &y, &w, &h);
m = evas_map_new(4);
evas_map_util_points_populate_from_object(m, o);
evas_map_util_rotate(m, 45, x + (w / 2), y + (h / 2));
evas_object_map_set(o, m);
evas_object_map_enable_set(o, EINA_TRUE);
evas_map_free(m);
</code>
{{ :event_effect_evas_map_3.png }}
You can rotate the object around any other point simply by setting the last
two arguments of the ''evas_map_util_rotate()'' function to the appropriate
values:
<code c>
evas_map_util_rotate(m, 45, x + w - 20, y + h - 20);
</code>
{{ :event_effect_evas_map_4.png }}
You can also set the center of the window as the center of the rotation using
the appropriate coordinates of the Evas canvas:
<code c>
evas_output_size_get(evas, &amp;w, &amp;h);
m = evas_map_new(4);
evas_map_util_points_populate_from_object(m, o);
evas_map_util_rotate(m, 45, w, h);
evas_object_map_set(o, m);
evas_object_map_enable_set(o, EINA_TRUE);
evas_map_free(m);
</code>
==== Zoom ====
The ''evas_map_util_zoom()'' function zooms the points of the map from a
center point, defined by ''cx'' and ''cy''. The ''zoomx'' and ''zoomy''
arguments specify how much to zoom in on the X and Y axes. A value of 1.0
means no zoom, 2.0 means double the size, 0.5 means half the size, and so on.
All the coordinates are global canvas coordinates.
<code c>
void evas_map_util_zoom(Evas_Map * m,
double zoomx,
double zoomy,
Evas_Coord cx,
Evas_Coord cy
)
</code>
* ''m'' map to change.
* ''zoomx'' horizontal zoom to use.
* ''zoomy'' vertical zoom to use.
* ''cx'' zooming center horizontal position.
* ''cy'' zooming center vertical position.
==== 3D Maps ====
Maps can also be used to achieve a 3D effect. In a 3D effect, the Z coordinate
of each point is meaningful: the higher the value, the further back the point
is located. Smaller values (usually negative) mean that the point is closer to
the user.
3D also introduces the concept of the back face of an object. An object is
said to be facing the user when all its points are placed in a clockwise
formation, as shown in the left map in the following figure. Rotating the map
around its Y axis swaps the order of the points into a counterclockwise
formation, making the object face away from the user, as shown in the right
map in the following figure. The back face is especially relevant in lighting
(see below).
{{ :event_effect_evas_map_5.png }}
To determine whether a map is facing the user, use the
''evas_map_util_clockwise_get()'' function. This function returns
''EINA_TRUE'' if the map is facing the user and ''EINA_FALSE'' if the map is
facing away from the user. This is normally done after all the other
operations are applied to the map.
<code c>
Eina_Bool evas_map_util_clockwise_get(Evas_Map *m)
</code>
==== 3D Rotation and Perspective ====
The ''evas_map_util_3d_rotate()'' function transforms a map to apply a 3D
rotation to the mapped object. You can apply the rotation around any point in
the canvas (including a Z coordinate). You can also apply the rotation around
any of the three axes.
<code c>
evas_map_util_3d_rotate(Evas_Map * m,
double dx,
double dy,
double dz,
Evas_Coord cx,
Evas_Coord cy,
Evas_Coord cz
)
</code>
* ''m'': map to change.
* ''dx'': amount of degrees from 0.0 to 360.0 to rotate around X axis.
* ''dy'': amount of degrees from 0.0 to 360.0 to rotate around Y axis.
* ''dz'': amount of degrees from 0.0 to 360.0 to rotate around Z axis.
* ''cx'': rotation's center horizontal position.
* ''cy'': rotation's center vertical position.
* ''cz'': rotation's center vertical position.
Starting from this simple setup, and setting the maps so that the blue square
rotates around the Y axis, we get the following:
{{ :event_effect_evas_map_6.png }}
A simple overlay over the image shows the original geometry of each object and
the axis around which they are being rotated. The Z axis is not shown, since
it is orthogonal to the screen. To show the Z axis, that is, to add 3D
perspective to the transformation, use the ''evas_map_util_3d_perspective()''
function on the map after its position has been set:
<code c>
void evas_map_util_3d_perspective(Evas_Map * m,
Evas_Coord px,
Evas_Coord py,
Evas_Coord z0,
Evas_Coord foc
)
</code>
* ''m'': map to change.
* ''px'': The perspective distance X coordinate
* ''py'': The perspective distance Y coordinate
* ''z0'': The "0" z plane value
* ''foc'': The focal distance
The result makes the vanishing point the center of each object:
{{ :event_effect_evas_map_7.png }}
==== Color and Lighting ====
Each point in a map can be set to a color, which will be multiplied with the
objects own color and linearly interpolated between adjacent points. To set
the color separately for each point, use the ''evas_map_point_color_set()''
function:
<code c>
void evas_map_point_color_set(Evas_Map * m,
int idx,
int r,
int g,
int b,
int a
)
</code>
* ''m'' map to change the color of.
* ''idx'' index of point to change. Must be smaller than map size.
* ''r'' red (0 - 255)
* ''g'' green (0 - 255)
* ''b'' blue (0 - 255)
* ''a'' alpha (0 - 255)
To set the same color for every point, use the
''evas_map_util_points_color_set()'' function:
<code c>
void evas_map_util_points_color_set(Evas_Map *m, int r, int g, int b, int a)
</code>
When using a 3D effect, colors can be used to improve its look by simulating a
light source. The ''evas_map_util_3d_lighting()'' function makes this task
easier by taking the coordinates of the light source and its color, along with
the color of the ambient light. Evas then sets the color of each point based
on its distance to the light source, the angle at which the object is facing
the light source, and the ambient light. Here, the orientation of each point
is important.
<code c>
evas_map_util_3d_lighting(Evas_Map * m,
Evas_Coord lx,
Evas_Coord ly,
Evas_Coord lz,
int lr,
int lg,
int lb,
int ar,
int ag,
int ab
)
</code>
* ''m'' map to change.
* ''lx'' X coordinate in space of light point
* ''ly'' Y coordinate in space of light point
* ''lz'' Z coordinate in space of light point
* ''lr'' light red value (0 - 255)
* ''lg'' light green value (0 - 255)
* ''lb'' light blue value (0 - 255)
* ''ar'' ambient color red value (0 - 255)
* ''ag'' ambient color green value (0 - 255)
* ''ab'' ambient color blue value (0 - 255)
If the map points are defined counterclockwise, the object faces away from the
user and is therefore obscured, since no light is reflecting back from it.
{{ :event_effect_evas_map_8.png }}
==== Mapping ====
Images need special handling when mapped. While Evas can easily handle objects, it is completely oblivious to the contents of images. This means that each point in a map needs to be mapped to a specific pixel in the source image. Failing to do this can result in unexpected behavior.
Let's get started with the following three images, each sized at 200 × 200 pixels:
{{ :event_effect_evas_map_9.png }}
The following three images illustrate the case where a map is set to an image
object without setting the right UV mapping for each map point. The objects
themselves are mapped properly to their new geometries, but the images are not
displayed correctly within the mapped objects.
{{ :event_effect_evas_map_10.png }}
To transform an image correctly, Evas needs to know how to handle the image
within the map. You can do this using the ''evas_map_point_image_uv_set()''
function, which allows you to map a given point in a map to a given pixel in a
source image:
<code c>
void evas_map_point_image_uv_set(Evas_Map *m,
int idx,
double u,
double v
)
</code>
* ''m'' map to change the point of.
* ''idx'' index of point to change. Must be smaller than map size.
* ''u'' the X coordinate within the image/texture source
* ''v'' the Y coordinate within the image/texture source
To match our example images to the maps above, all we need is the size of each
image, which we can get using the ''evas_object_image_size_get()'' function.
<code c>
// Tux 1: Some cropping and stretch up
evas_map_point_image_uv_set(m, 0, 0, 20);
evas_map_point_image_uv_set(m, 1, 200, 20);
evas_map_point_image_uv_set(m, 2, 200, 180);
evas_map_point_image_uv_set(m, 3, 0, 180);
evas_object_map_set(tux1, m);
evas_object_map_enable_set(tux1, EINA_TRUE);
// Inverted texture for shadow:
evas_map_point_image_uv_set(m, 0, 0, 180);
evas_map_point_image_uv_set(m, 1, 200, 180);
evas_map_point_image_uv_set(m, 2, 200, 20);
evas_map_point_image_uv_set(m, 3, 0, 20);
evas_object_map_set(tux1_shadow, m);
evas_object_map_enable_set(tux1_shadow, EINA_TRUE);
// Tux 2: Make it fit to the map:
evas_map_point_image_uv_set(m, 0, 0, 0);
evas_map_point_image_uv_set(m, 1, 200, 0);
evas_map_point_image_uv_set(m, 2, 200, 200);
evas_map_point_image_uv_set(m, 3, 0, 200);
evas_object_map_set(tux2, m);
evas_object_map_enable_set(tux2, EINA_TRUE);
// Tux 3: Zoom and fit relatively to image size
evas_object_image_size_get(evas_object_image_source_get(tux3), &w, &h);
evas_map_point_image_uv_set(m, 0, 0.1 * w, 0.1 * h);
evas_map_point_image_uv_set(m, 1, 0.9 * w, 0.1 * h);
evas_map_point_image_uv_set(m, 2, 0.9 * w, 0.9 * h);
evas_map_point_image_uv_set(m, 3, 0.1 * w, 0.9 * h);
evas_object_map_set(tux3, m);
evas_object_map_enable_set(tux3, EINA_TRUE);
</code>
{{ :event_effect_evas_map_11.png }}
You can also set a map to use only part of an image, or you can even map the
points in inverted order. Combined with the ''evas_object_image_source_set()''
function, you can achieve more interesting results still.
==== Lighting ====
''Evas_Map'' allows you to define an ambient light and a light source within
the scene. Both of these light sources have their own colors.
<code c>
void evas_map_util_3d_lighting(Evas_Map * m,
Evas_Coord lx,
Evas_Coord ly,
Evas_Coord lz,
int lr,
int lg,
int lb,
int ar,
int ag,
int ab
)
</code>
* ''m'' map to change.
* ''lx'' X coordinate in space of light point
* ''ly'' Y coordinate in space of light point
* ''lz'' Z coordinate in space of light point
* ''lr'' light red value (0 - 255)
* ''lg'' light green value (0 - 255)
* ''lb'' light blue value (0 - 255)
* ''ar'' ambient color red value (0 - 255)
* ''ag'' ambient color green value (0 - 255)
* ''ab'' ambient color blue value (0 - 255)
The above function is used to apply lighting calculations (from a single light
source) to a given map. The red, green, and blue values of each vertex will be
modified to reflect the lighting based on the light source coordinates, its
color, the ambient color, and the angle at which the map faces the light
source. The points of a surface should be defined in a clockwise formation if
the surface is facing the user, since faces have a logical side for lighting.
To get the reflections (gradient) in the shadow of our previous example, you
have to define a source of light close enough to the user and a very bright
ambient light, for example:
<code c>
evas_map_util_3d_lighting(m, // Evas_Map object
250/2, 150/2, -100, // Spot light coordinates
255, 255, 255, // Spot light color
200, 200, 200); // Ambient light color
</code>
==== Alpha Channel ====
You can also use an alpha channel on your map by enabling the alpha channel
feature:
<code c>
evas_map_alpha_set(Evas_Map *m, Eina_Bool enabled)
</code>
Next, set the alpha value separately for each map point:
<code c>
evas_map_point_color_set(Evas_Map *m, int idx, int r, int g, int b, int a)
</code>
Alternatively, you can set the same alpha value to all map points:
<code c>
evas_map_util_points_color_set(Evas_Map *m, int r, int g, int b, int a)
</code>
The following code sets the shadow transparency for the first image in the
above three-image example:
<code c>
// Set object transparency to 50%:
evas_map_util_points_color_set(m, 255, 255, 255, 127);
// Tux's head is almost invisible in the shadow:
evas_map_point_color_set(m, 3, 255, 255, 255, 15);
evas_map_point_color_set(m, 4, 255, 255, 255, 15);
</code>
==== Smoothing ====
To enable smoothing when rendering a map, use the ''evas_map_smooth_set()''
function:
<code c>
evas_map_smooth_set(Evas_Map *m, Eina_Bool enabled)
</code>
The first argument is the ''Evas_Map'' object to apply smoothing to. The second argument sets whether to enable the smoothing:
* ''EINA_TRUE'': Enable smoothing.
* ''EINA_FALSE'': Disable smoothing.
If the object is of a type that has its own smoothing settings, the smoothing
settings must be disabled for both the object and the map. Map smoothing is
enabled by default. To check whether map smoothing is enabled, use the
''evas_map_smooth_get()'' function.
\\
[[https://build.enlightenment.org/job/nightly_efl_gcc_x86_64/lastSuccessfulBuild/artifact/doc/html/Example_Evas_Map_Overview.html|Evas Map Example]]
-------
{{page>index}}