efl/src/examples/evas/evas-buffer-simple.c

229 lines
6.1 KiB
C

/**
* Simple Evas example using the Buffer engine.
*
* You must have Evas compiled with the buffer engine, and have the
* evas-software-buffer pkg-config files installed.
*
* Compile with:
*
* @verbatim
* gcc -o evas-buffer-simple evas-buffer-simple.c `pkg-config --libs --cflags evas evas-software-buffer`
* @endverbatim
*
*/
#include <Evas.h>
#include <Evas_Engine_Buffer.h>
#include <stdio.h>
#include <errno.h>
#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)
{
Evas *canvas;
Evas_Object *bg, *r1, *r2, *r3;
evas_init();
// create your canvas
// NOTE: consider using ecore_evas_buffer_new() instead!
canvas = create_canvas(WIDTH, HEIGHT);
if (!canvas)
return -1;
bg = evas_object_rectangle_add(canvas);
evas_object_color_set(bg, 255, 255, 255, 255); // white bg
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);
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)
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);
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);
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();
return 0;
}
static Evas *create_canvas(int width, int height)
{
Evas *canvas;
Evas_Engine_Info_Buffer *einfo;
int method;
void *pixels;
method = evas_render_method_lookup("buffer");
if (method <= 0)
{
fputs("ERROR: evas was not compiled with 'buffer' engine!\n", stderr);
return NULL;
}
canvas = evas_new();
if (!canvas)
{
fputs("ERROR: could not instantiate new evas canvas.\n", stderr);
return NULL;
}
evas_output_method_set(canvas, method);
evas_output_size_set(canvas, width, height);
evas_output_viewport_set(canvas, 0, 0, width, height);
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;
}
// ARGB32 is sizeof(int), that is 4 bytes, per pixel
pixels = malloc(width * height * sizeof(int));
if (!pixels)
{
fputs("ERROR: could not allocate canvas pixels!\n", stderr);
evas_free(canvas);
return NULL;
}
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;
evas_engine_info_set(canvas, (Evas_Engine_Info *)einfo);
return canvas;
}
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(einfo->info.dest_buffer);
evas_free(canvas);
}
static void draw_scene(Evas *canvas)
{
Eina_List *updates, *n;
Eina_Rectangle *update;
// render and get the updated rectangles:
updates = evas_render_updates(canvas);
// informative only here, just print the updated areas:
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
evas_render_updates_free(updates);
}
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;
einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(canvas);
if (!einfo)
{
fputs("ERROR: could not get evas engine info!\n", stderr);
return;
}
evas_output_size_get(canvas, &width, &height);
f = fopen(dest, "wb+");
if (!f)
{
fprintf(stderr, "ERROR: could not open for writing '%s': %s\n",
dest, strerror(errno));
return;
}
pixels = einfo->info.dest_buffer;
pixels_end = pixels + (width * height);
// PPM P6 format is dead simple to write:
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);
}