/* EINA - EFL data type library * Copyright (C) 2010 Cedric BAIL * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; * if not, see . */ #define WIDTH 720 #define HEIGHT 576 #include #include "eina_main.h" #include "eina_mempool.h" #include "eina_rectangle.h" #include "eina_quadtree.h" #include "eina_list.h" #include "eina_bench.h" static void eina_bench_render_loop(int request) { Eina_List *objects = NULL; Eina_Rectangle *r; int i; int j; eina_init(); for (i = 0; i < request; ++i) objects = eina_list_append(objects, eina_rectangle_new((rand() * WIDTH) / RAND_MAX, (rand() * HEIGHT) / RAND_MAX, (rand() * WIDTH / 2) / RAND_MAX, (rand() * HEIGHT / 2) / RAND_MAX)); for (j = 0; j < 100; ++j) { Eina_Rectangle *collide; Eina_List *collided = NULL; Eina_List *changed = NULL; Eina_List *l; /* Delete 25% of all objects */ i = request * 25 / 100; for (; i > 0; --i) { eina_rectangle_free(eina_list_data_get(objects)); objects = eina_list_remove_list(objects, objects); } /* Add them back */ i = request * 25 / 100; for (; i > 0; --i) { r = eina_rectangle_new((rand() * WIDTH) / RAND_MAX, (rand() * HEIGHT) / RAND_MAX, (rand() * WIDTH / 3) / RAND_MAX, (rand() * HEIGHT / 3) / RAND_MAX); objects = eina_list_prepend(objects, r); changed = eina_list_append(changed, r); } /* Do one collide search */ collide = eina_rectangle_new((rand() * WIDTH) / RAND_MAX, (rand() * HEIGHT) / RAND_MAX, (rand() * WIDTH / 4) / RAND_MAX, (rand() * HEIGHT / 4) / RAND_MAX); EINA_LIST_FOREACH(objects, l, r) if (eina_rectangles_intersect(r, collide)) collided = eina_list_append(collided, r); collided = eina_list_free(collided); eina_rectangle_free(collide); /* Modify 50% of all objects */ i = request * 50 / 100; for (; i > 0; --i) { r = eina_list_data_get(eina_list_last(objects)); objects = eina_list_remove_list(objects, eina_list_last(objects)); r->x = (rand() * WIDTH) / RAND_MAX; r->y = (rand() * HEIGHT) / RAND_MAX; r->w = (rand() * WIDTH / 3) / RAND_MAX; r->h = (rand() * HEIGHT / 3) / RAND_MAX; objects = eina_list_prepend(objects, r); changed = eina_list_append(changed, r); } /* Emulating the render loop by colliding all modified object with all intersecting object */ EINA_LIST_FREE(changed, r) { EINA_LIST_FOREACH(objects, l, collide) if (r != collide && eina_rectangles_intersect(collide, r)) collided = eina_list_append(collided, collide); collided = eina_list_append(collided, r); } /* Ok, we compute it, now it's done */ collided = eina_list_free(collided); } EINA_LIST_FREE(objects, r) eina_rectangle_free(r); eina_shutdown(); } typedef struct _Eina_Bench_Quad Eina_Bench_Quad; struct _Eina_Bench_Quad { Eina_Rectangle r; Eina_QuadTree_Item *item; }; static Eina_Quad_Direction _eina_bench_quadtree_vertical(const void *object, size_t middle) { const Eina_Bench_Quad *b = object; size_t y; y = b->r.y < 0 ? 0 : (size_t)b->r.y; if (y + b->r.h < middle) return EINA_QUAD_LEFT; if (y > middle) return EINA_QUAD_RIGHT; return EINA_QUAD_BOTH; } static Eina_Quad_Direction _eina_bench_quadtree_horizontal(const void *object, size_t middle) { const Eina_Bench_Quad *b = object; size_t x; x = b->r.x < 0 ? 0 : (size_t)b->r.x; if (x + b->r.w < middle) return EINA_QUAD_LEFT; if (x > middle) return EINA_QUAD_RIGHT; return EINA_QUAD_BOTH; } static void eina_bench_quadtree_render_loop(int request) { Eina_List *objects = NULL; Eina_Inlist *possibility; Eina_Bench_Quad *b; Eina_QuadTree *q; Eina_Mempool *mp; int i; int j; eina_init(); mp = eina_mempool_add("chained_mempool", "bench-quad", NULL, sizeof (Eina_Bench_Quad), 320); q = eina_quadtree_new(WIDTH, HEIGHT, _eina_bench_quadtree_vertical, _eina_bench_quadtree_horizontal); /* Create requested object */ for (i = 0; i < request; ++i) { b = eina_mempool_malloc(mp, sizeof (Eina_Bench_Quad)); EINA_RECTANGLE_SET(&b->r, (rand() * WIDTH) / RAND_MAX, (rand() * HEIGHT) / RAND_MAX, (rand() * WIDTH / 2) / RAND_MAX, (rand() * HEIGHT / 2) / RAND_MAX); b->item = eina_quadtree_add(q, b); objects = eina_list_append(objects, b); } for (j = 0; j < 100; ++j) { Eina_Bench_Quad *collide; Eina_List *changed = NULL; Eina_List *collided = NULL; /* Delete 25% of all objects */ i = request * 25 / 100; for (; i > 0; --i) { b = eina_list_data_get(objects); eina_quadtree_del(b->item); eina_mempool_free(mp, b); objects = eina_list_remove_list(objects, objects); } /* Add them back */ i = request * 25 / 100; for (; i > 0; --i) { b = eina_mempool_malloc(mp, sizeof (Eina_Bench_Quad)); EINA_RECTANGLE_SET(&b->r, (rand() * WIDTH) / RAND_MAX, (rand() * HEIGHT) / RAND_MAX, (rand() * WIDTH / 3) / RAND_MAX, (rand() * HEIGHT / 3) / RAND_MAX); b->item = eina_quadtree_add(q, b); objects = eina_list_prepend(objects, b); changed = eina_list_append(changed, b); } /* Do one collide search */ collide = eina_mempool_malloc(mp, sizeof (Eina_Bench_Quad)); EINA_RECTANGLE_SET(&collide->r, (rand() * WIDTH) / RAND_MAX, (rand() * HEIGHT) / RAND_MAX, (rand() * WIDTH / 4) / RAND_MAX, (rand() * HEIGHT / 4) / RAND_MAX); possibility = eina_quadtree_collide(q, collide->r.x, collide->r.y, collide->r.w, collide->r.h); while (possibility) { b = eina_quadtree_object(possibility); possibility = possibility->next; if (eina_rectangles_intersect(&b->r, &collide->r)) collided = eina_list_append(collided, b); } collided = eina_list_free(collided); eina_mempool_free(mp, collide); /* Modify 50% of all objects */ i = request * 50 / 100; for (; i > 0; --i) { b = eina_list_data_get(eina_list_last(objects)); objects = eina_list_remove_list(objects, eina_list_last(objects)); b->r.x = (rand() * WIDTH) / RAND_MAX; b->r.y = (rand() * HEIGHT) / RAND_MAX; b->r.w = (rand() * WIDTH / 3) / RAND_MAX; b->r.h = (rand() * HEIGHT / 3) / RAND_MAX; eina_quadtree_change(b->item); objects = eina_list_prepend(objects, b); changed = eina_list_append(changed, b); } /* Emulating the render loop by colliding all modified object with all intersecting object */ EINA_LIST_FREE(changed, b) { possibility = eina_quadtree_collide(q, b->r.x, b->r.y, b->r.w, b->r.h); while (possibility) { collide = eina_quadtree_object(possibility); possibility = possibility->next; if (collide != b && eina_rectangles_intersect(&b->r, &collide->r)) collided = eina_list_append(collided, collide); } collided = eina_list_append(collided, b); } /* Ok, we compute it, now it's done */ collided = eina_list_free(collided); } EINA_LIST_FREE(objects, b) { eina_quadtree_del(b->item); eina_mempool_free(mp, b); } eina_mempool_del(mp); eina_quadtree_free(q); eina_shutdown(); } void eina_bench_quadtree(Eina_Benchmark *bench) { eina_benchmark_register(bench, "collide-all", EINA_BENCHMARK(eina_bench_render_loop), 100, 1500, 50); eina_benchmark_register(bench, "collide-quad-tree", EINA_BENCHMARK(eina_bench_quadtree_render_loop), 100, 1500, 50); }