jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=7e552977a6728f70064640071b4a12fc38237a19

commit 7e552977a6728f70064640071b4a12fc38237a19
Author: Bryce Harrington <br...@osg.samsung.com>
Date:   Fri Jun 9 12:09:54 2017 +0900

    examples: Flesh out the evas-buffer-simple example
    
    Summary:
    This serves as an early example for new Evas programmers to introduce
    the buffer engine as well as very basic canvas usage, so we're going
    into a lot more detail for both of those than we'll do in subsequent
    examples.
    
    Reviewers: cedric
    
    Subscribers: jpeg
    
    Differential Revision: https://phab.enlightenment.org/D4950
---
 src/examples/evas/evas-buffer-simple.c | 166 ++++++++++++++++++++++++++-------
 1 file changed, 133 insertions(+), 33 deletions(-)

diff --git a/src/examples/evas/evas-buffer-simple.c 
b/src/examples/evas/evas-buffer-simple.c
index e2d02e9a32..9601108257 100644
--- a/src/examples/evas/evas-buffer-simple.c
+++ b/src/examples/evas/evas-buffer-simple.c
@@ -1,8 +1,29 @@
 /**
  * Example of using the buffer engine in Evas.
  *
- * You must have Evas compiled with the buffer engine, and have the
- * evas-software-buffer pkg-config files installed.
+ * In the evas-init-shutdown.c example we looked at how to turn Evas on
+ * and off.  In this example we'll turn it on and off but also do
+ * something in between.  We'll set up a canvas and add a few rectangles
+ * to show how graphics objects are configured.
+ *
+ * In Evas, graphic rendering is done by a 'backend engine', which can
+ * be changed to match the capabilities of the underlying hardware.  For
+ * this example to keep things simple we will use the 'buffer engine'.
+ * The buffer engine simply does all the rendering directly into a memory
+ * buffer, with no hardware acceleration.
+ *
+ * In real world usage you probably would not be using the raw buffer
+ * access that we'll be looking at here, but instead using higher level
+ * functionality from Ecore and Ecore's Ecore-Evas submodule.  Ecore
+ * provides convenience routines for creating and managing the canvas,
+ * integrating with the main loop, and automating scene drawing.  Since
+ * we're not yet ready to dig into Ecore's functionality, we'll
+ * substitute our own dummy routines create_canvas(), destroy_canvas(),
+ * and draw_scene(), so we can focus on the overall process flow in
+ * main().
+ *
+ * For this example you must have Evas compiled with the buffer engine,
+ * and have the evas-software-buffer pkg-config files installed.
  *
  * @verbatim
  * gcc -o evas-buffer-simple evas-buffer-simple.c `pkg-config --libs --cflags 
evas evas-software-buffer`
@@ -17,21 +38,9 @@
 #define WIDTH (320)
 #define HEIGHT (240)
 
-/*
- * create_canvas(), destroy_canvas() and draw_scene() are support functions.
- *
- * They are only required to use raw Evas, but for real world usage,
- * it is recommended to use ecore and its ecore-evas submodule, that
- * provide convenience canvas creators, integration with main loop and
- * automatic render of updates (draw_scene()) when system goes back to
- * main loop.
- */
-
 static Evas *create_canvas(int width, int height);
 static void destroy_canvas(Evas *canvas);
 static void draw_scene(Evas *canvas);
-
-// support function to save scene as PPM image
 static void save_scene(Evas *canvas, const char *dest);
 
 int main(void)
@@ -41,14 +50,29 @@ int main(void)
 
    evas_init();
 
-   // create your canvas
-   // NOTE: consider using ecore_evas_buffer_new() instead!
+   /* After turning Evas on, we create an Evas canvas to work in.
+    * Canvases are graphical workspaces used for placing and organizing
+    * graphical objects.  Normally we'd be using Ecore-Evas to create
+    * the canvas, but for this example we'll hide the details in a
+    * separate routine for convenience.
+    */
    canvas = create_canvas(WIDTH, HEIGHT);
    if (!canvas)
      return -1;
 
+   /* Next set the background to solid white.  This is typically done by
+    * creating a rectangle sized to the canvas, placed at the canvas
+    * origin.
+    *
+    * Note that if the canvas were to change size, our background
+    * rectangle will not automatically resize itself; we'd need to do
+    * that manually with another evas_object_resize() call.  In a real
+    * application using Ecore-Evas, functionality in Ecore will take
+    * care of resizing things.  For this example, we'll just keep the
+    * canvas dimensions fixed to avoid the problem.
+    */
    bg = evas_object_rectangle_add(canvas);
-   evas_object_color_set(bg, 255, 255, 255, 255); // white bg
+   evas_object_color_set(bg, 255, 255, 255, 255); // white bg, no transparency
    evas_object_move(bg, 0, 0);                    // at origin
    evas_object_resize(bg, WIDTH, HEIGHT);         // covers full canvas
    evas_object_show(bg);
@@ -56,28 +80,50 @@ int main(void)
    puts("initial scene, with just background:");
    draw_scene(canvas);
 
+   /* To make the scene interesting let's add a few more rectangles of
+    * various sizes and colors, starting with a big red one.
+    *
+    * By default all Evas objects are created in a 'hidden' state,
+    * meaning they are not visible, won't be checked for changes during
+    * canvas rendering, and won't receive input events.  Thus, like we
+    * did for the background object we must call evas_object_show() to
+    * make our graphics objects usable.
+    */
    r1 = evas_object_rectangle_add(canvas);
    evas_object_color_set(r1, 255, 0, 0, 255); // 100% opaque red
    evas_object_move(r1, 10, 10);
    evas_object_resize(r1, 100, 100);
    evas_object_show(r1);
 
-   // pay attention to transparency! Evas color values are pre-multiplied by
-   // alpha, so 50% opaque green is:
-   // non-premul: r=0, g=255, b=0    a=128 (50% alpha)
-   // premul:
-   //         r_premul = r * a / 255 =      0 * 128 / 255 =      0
-   //         g_premul = g * a / 255 =    255 * 128 / 255 =    128
-   //         b_premul = b * a / 255 =      0 * 128 / 255 =      0
-   //
-   // this 50% green is over a red background, so it will show in the
-   // final output as yellow (green + red = yellow)
+   /* Let's add a partly transparent rectangle on top of the red one.
+    *
+    * Graphics objects are treated as a stack in the canvas for drawing
+    * purposes, so subsequent objects are drawn above the ones we've
+    * already added to the canvas.  This is important in objects that
+    * have partially transparent fill coloring since we'll see part of
+    * what's "behind" our object.
+    *
+    * In Evas, color values are pre-multiplied by their alpha.  This means
+    * that if we want a green rectangle that's half transparent, we'd have:
+    *
+    * non-premul: r=0, g=255, b=0    a=128 (50% alpha)
+    * premul:
+    *         r_premul = r * a / 255 =      0 * 128 / 255 =      0
+    *         g_premul = g * a / 255 =    255 * 128 / 255 =    128
+    *         b_premul = b * a / 255 =      0 * 128 / 255 =      0
+    *
+    * Since we're placing our half transparent green rectangle on top of
+    * a red one, in the final output we will actually see a yellow square
+    * (since in RGBA color green + red = yellow).
+    */
    r2 = evas_object_rectangle_add(canvas);
    evas_object_color_set(r2, 0, 128, 0, 128); // 50% opaque green
    evas_object_move(r2, 10, 10);
    evas_object_resize(r2, 50, 50);
    evas_object_show(r2);
 
+   /* Lastly, for comparison add a dark green rectangle with no
+    * transparency. */
    r3 = evas_object_rectangle_add(canvas);
    evas_object_color_set(r3, 0, 128, 0, 255); // 100% opaque dark green
    evas_object_move(r3, 60, 60);
@@ -86,9 +132,14 @@ int main(void)
 
    puts("final scene (note updates):");
    draw_scene(canvas);
+
+   /* In addition to displaying the canvas to the screen, let's also
+    * output the buffer to a graphics file, for comparison.  Evas
+    * supports a range of graphics file formats, but PPM is particularly
+    * trivial to write, so our save_scene routine will output as PPM.
+    */
    save_scene(canvas, "/tmp/evas-buffer-simple-render.ppm");
 
-   // NOTE: use ecore_evas_buffer_new() and here ecore_evas_free()
    destroy_canvas(canvas);
 
    evas_shutdown();
@@ -96,6 +147,9 @@ int main(void)
    return 0;
 }
 
+/* Convenience routine to allocate and initialize the canvas.
+ * In a real application we'd be using ecore_evas_buffer_new() instead.
+ */
 static Evas *create_canvas(int width, int height)
 {
    Evas *canvas;
@@ -103,6 +157,7 @@ static Evas *create_canvas(int width, int height)
    int method;
    void *pixels;
 
+   /* Request a handle for the 'buffer' type of rendering engine. */
    method = evas_render_method_lookup("buffer");
    if (method <= 0)
      {
@@ -110,6 +165,8 @@ static Evas *create_canvas(int width, int height)
        return NULL;
      }
 
+   /* Create a general canvas object.
+    * Note that we are responsible for freeing the canvas when we're done. */
    canvas = evas_new();
    if (!canvas)
      {
@@ -117,10 +174,20 @@ static Evas *create_canvas(int width, int height)
        return NULL;
      }
 
+   /* Specify that the canvas will be rendering using the buffer engine method.
+    * We also size the canvas and viewport to the same width and height, with
+    * the viewport set to the origin of the canvas.
+    */
    evas_output_method_set(canvas, method);
    evas_output_size_set(canvas, width, height);
    evas_output_viewport_set(canvas, 0, 0, width, height);
 
+   /* Before we can use the engine, we *must* set its configuration
+    * parameters.  The available parameters are kept in a struct
+    * named Evas_Engine_Info which is internal to Evas.  Thus to set
+    * parameters we must first request the current info object from
+    * our canvas:
+    */
    einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(canvas);
    if (!einfo)
      {
@@ -129,7 +196,13 @@ static Evas *create_canvas(int width, int height)
        return NULL;
      }
 
-   // ARGB32 is sizeof(int), that is 4 bytes, per pixel
+   /* Create the underlying data buffer that our canvas will use.  This
+    * is a simple array of ARGB32 pixels.  Each color component
+    * (including alpha) is one byte, resulting in 4 bytes per pixel (or
+    * 32 bits).  We can thus store each pixel in an integer data type,
+    * thus calculating our data buffer as W x H x sizeof(int) bytes in
+    * length.
+    */
    pixels = malloc(width * height * sizeof(int));
    if (!pixels)
      {
@@ -138,6 +211,10 @@ static Evas *create_canvas(int width, int height)
        return NULL;
      }
 
+   /* Next set the various configuration parameters.  We
+    * register the pixel buffer that the canvas will use,
+    * indicate the pixel format as ARGB32, and the size of
+    * each row of data. */
    einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
    einfo->info.dest_buffer = pixels;
    einfo->info.dest_buffer_row_bytes = width * sizeof(int);
@@ -145,11 +222,16 @@ static Evas *create_canvas(int width, int height)
    einfo->info.alpha_threshold = 0;
    einfo->info.func.new_update_region = NULL;
    einfo->info.func.free_update_region = NULL;
+
+   /* Finally, we configure the canvas with our chosen parameters. */
    evas_engine_info_set(canvas, (Evas_Engine_Info *)einfo);
 
    return canvas;
 }
 
+/* Convenience routine to shut down the canvas.
+ * In a real application we'd be using ecore_evas_free() instead
+ */
 static void destroy_canvas(Evas *canvas)
 {
    Evas_Engine_Info_Buffer *einfo;
@@ -162,27 +244,34 @@ static void destroy_canvas(Evas *canvas)
        return;
      }
 
+   /* Free the data buffer we allocated in create_buffer() */
    free(einfo->info.dest_buffer);
+
+   /* Finally, free the canvas itself. */
    evas_free(canvas);
 }
 
+/* Convenience routine to update the scene.
+ * In a real application Ecore Evas would be doing this for us.
+ */
 static void draw_scene(Evas *canvas)
 {
    Eina_List *updates, *n;
    Eina_Rectangle *update;
 
-   // render and get the updated rectangles:
+   /* Render the canvas, and get a list of the updated rectangles. */
    updates = evas_render_updates(canvas);
 
-   // informative only here, just print the updated areas:
+   /* Just for informative purposes, print out the areas being updated: */
    EINA_LIST_FOREACH(updates, n, update)
      printf("UPDATED REGION: pos: %3d, %3d    size: %3dx%3d\n",
            update->x, update->y, update->w, update->h);
 
-   // free list of updates
+   /* Free the list of update rectangles */
    evas_render_updates_free(updates);
 }
 
+/* Output the canvas buffer to a Portable Pixel Map (PPM) file */
 static void save_scene(Evas *canvas, const char *dest)
 {
    Evas_Engine_Info_Buffer *einfo;
@@ -190,14 +279,18 @@ static void save_scene(Evas *canvas, const char *dest)
    int width, height;
    FILE *f;
 
+   /* Retrieve the current data buffer. */
    einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(canvas);
    if (!einfo)
      {
        fputs("ERROR: could not get evas engine info!\n", stderr);
        return;
      }
+
+   /* Retrieve the canvas dimensions */
    evas_output_size_get(canvas, &width, &height);
 
+   /* Open our output PPM file for writing */
    f = fopen(dest, "wb+");
    if (!f)
      {
@@ -206,10 +299,17 @@ static void save_scene(Evas *canvas, const char *dest)
        return;
      }
 
+   /* Write out the pixel data to the PPM file */
    pixels = einfo->info.dest_buffer;
    pixels_end = pixels + (width * height);
 
-   // PPM P6 format is dead simple to write:
+   /* PPM P6 format is dead simple to write.  First we output a magic
+    * number 'P6' to designate the file as PPM, then the width and
+    * height on their own line in ASCII decimal, followed by the maximum
+    * color value (255) on its own line in ASCII decimal, and finally a
+    * the pixel data in RGB order with each color component written as
+    * a char (byte).  No alpha information is stored.
+    */
    fprintf(f, "P6\n%d %d\n255\n",  width, height);
    for (; pixels < pixels_end; pixels++)
      {

-- 


Reply via email to