summaryrefslogtreecommitdiff log msg author committer range
blob: 9601108257dffa2295eb57f7b7b33cc9036483fc (plain)
 ```1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 ``` ``````/** * Example of using the buffer engine in Evas. * * 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` * @endverbatim */ #include #include #include #include #define WIDTH (320) #define HEIGHT (240) static Evas *create_canvas(int width, int height); static void destroy_canvas(Evas *canvas); static void draw_scene(Evas *canvas); static void save_scene(Evas *canvas, const char *dest); int main(void) { Evas *canvas; Evas_Object *bg, *r1, *r2, *r3; evas_init(); /* 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, no transparency evas_object_move(bg, 0, 0); // at origin evas_object_resize(bg, WIDTH, HEIGHT); // covers full canvas evas_object_show(bg); 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); /* 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); evas_object_resize(r3, 50, 50); evas_object_show(r3); 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"); destroy_canvas(canvas); evas_shutdown(); 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; Evas_Engine_Info_Buffer *einfo; int method; void *pixels; /* Request a handle for the 'buffer' type of rendering engine. */ method = evas_render_method_lookup("buffer"); if (method <= 0) { fputs("ERROR: evas was not compiled with 'buffer' engine!\n", stderr); 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) { fputs("ERROR: could not instantiate new evas canvas.\n", stderr); 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) { fputs("ERROR: could not get evas engine info!\n", stderr); evas_free(canvas); return NULL; } /* 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) { fputs("ERROR: could not allocate canvas pixels!\n", stderr); evas_free(canvas); 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); einfo->info.use_color_key = 0; 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; einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(canvas); if (!einfo) { fputs("ERROR: could not get evas engine info!\n", stderr); evas_free(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 the canvas, and get a list of the updated rectangles. */ updates = evas_render_updates(canvas); /* 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 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; const unsigned int *pixels, *pixels_end; 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) { fprintf(stderr, "ERROR: could not open for writing '%s': %s\n", dest, strerror(errno)); 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. 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++) { int r, g, b; r = ((*pixels) & 0xff0000) >> 16; g = ((*pixels) & 0x00ff00) >> 8; b = (*pixels) & 0x0000ff; fprintf(f, "%c%c%c", r, g, b); } fclose(f); printf("saved scene as '%s'\n", dest); } ``````