* eina: oops forgotten file.

SVN revision: 48425
This commit is contained in:
Cedric BAIL 2010-04-29 17:30:18 +00:00
parent 9367b5f7c7
commit d239b6c524
5 changed files with 1429 additions and 0 deletions

View File

@ -0,0 +1,52 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef EINA_QUADTREE_H_
#define EINA_QUADTREE_H_
#include "eina_config.h"
#include "eina_array.h"
typedef struct _Eina_QuadTree Eina_QuadTree;
typedef struct _Eina_QuadTree_Item Eina_QuadTree_Item;
typedef enum {
EINA_QUAD_LEFT,
EINA_QUAD_RIGHT,
EINA_QUAD_BOTH
} Eina_Quad_Direction;
typedef Eina_Quad_Direction (*Eina_Quad_Callback)(const void *object, size_t middle);
EAPI Eina_QuadTree *eina_quadtree_new(size_t w, size_t h,
Eina_Quad_Callback vertical,
Eina_Quad_Callback horizontal);
EAPI void eina_quadtree_free(Eina_QuadTree *q);
EAPI void eina_quadtree_resize(Eina_QuadTree *q, size_t w, size_t h);
EAPI Eina_QuadTree_Item *eina_quadtree_add(Eina_QuadTree *q, const void *object);
EAPI Eina_Bool eina_quadtree_del(Eina_QuadTree_Item *object);
EAPI Eina_Bool eina_quadtree_change(Eina_QuadTree_Item *object);
EAPI Eina_Bool eina_quadtree_hide(Eina_QuadTree_Item *object);
EAPI Eina_Bool eina_quadtree_show(Eina_QuadTree_Item *object);
EAPI void eina_quadtree_collide(Eina_Array *result, Eina_QuadTree *q,
int x, int y, size_t w, size_t h);
#endif

View File

@ -0,0 +1,820 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
/* 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 <http://www.gnu.org/licenses/>.
*/
/**
* @page tutorial_quadtree_page QuadTree Tutorial
*
* to be written...
*
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include "eina_quadtree.h"
#include "eina_magic.h"
#include "eina_mempool.h"
#include "eina_list.h"
#include "eina_inlist.h"
#include "eina_trash.h"
#include "eina_log.h"
#include "eina_rectangle.h"
#include "eina_private.h"
typedef struct _Eina_QuadTree_Root Eina_QuadTree_Root;
static const char EINA_MAGIC_QUADTREE_STR[] = "Eina QuadTree";
static const char EINA_MAGIC_QUADTREE_ROOT_STR[] = "Eina QuadTree Root";
static const char EINA_MAGIC_QUADTREE_ITEM_STR[] = "Eina QuadTree Item";
#define EINA_MAGIC_CHECK_QUADTREE(d, ...) \
do { \
if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_QUADTREE)) \
{ \
EINA_MAGIC_FAIL(d, EINA_MAGIC_QUADTREE); \
return __VA_ARGS__; \
} \
} while(0);
#define EINA_MAGIC_CHECK_QUADTREE_ROOT(d, ...) \
do { \
if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_QUADTREE_ROOT)) \
{ \
EINA_MAGIC_FAIL(d, EINA_MAGIC_QUADTREE_ROOT); \
return __VA_ARGS__; \
} \
} while(0);
#define EINA_MAGIC_CHECK_QUADTREE_ITEM(d, ...) \
do { \
if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_QUADTREE_ITEM)) \
{ \
EINA_MAGIC_FAIL(d, EINA_MAGIC_QUADTREE_ITEM); \
return __VA_ARGS__; \
} \
} while(0);
struct _Eina_QuadTree
{
EINA_MAGIC;
Eina_QuadTree_Root *root;
Eina_List *hidden;
Eina_Array *change;
size_t items_count;
Eina_Trash *items_trash;
Eina_Mempool *items_mp;
size_t root_count;
Eina_Trash *root_trash;
Eina_Mempool *root_mp;
size_t index;
struct {
Eina_Quad_Callback v;
Eina_Quad_Callback h;
} func;
struct {
size_t w;
size_t h;
} geom;
Eina_Bool resize : 1;
};
struct _Eina_QuadTree_Root
{
EINA_MAGIC;
Eina_QuadTree_Root *parent;
Eina_QuadTree_Root *left;
Eina_QuadTree_Root *right;
Eina_List *both;
Eina_Bool sorted : 1;
};
struct _Eina_QuadTree_Item
{
EINA_MAGIC;
EINA_INLIST;
Eina_QuadTree *quad;
Eina_QuadTree_Root *root;
const void *object;
size_t index;
Eina_Bool change : 1;
Eina_Bool delete_me : 1;
Eina_Bool visible : 1;
Eina_Bool hidden : 1;
};
static int _eina_log_qd_dom = -1;
#ifdef ERR
#undef ERR
#endif
#define ERR(...) EINA_LOG_DOM_ERR(_eina_log_qd_dom, __VA_ARGS__)
#ifdef DBG
#undef DBG
#endif
#define DBG(...) EINA_LOG_DOM_DBG(_eina_log_qd_dom, __VA_ARGS__)
static int
_eina_quadtree_item_cmp(const void *a, const void *b)
{
const Eina_QuadTree_Item *i = a;
const Eina_QuadTree_Item *j = b;
return i->index - j->index;
}
static Eina_QuadTree_Root *
eina_quadtree_root_free(Eina_QuadTree *q, Eina_QuadTree_Root *root)
{
if (!root) return NULL;
EINA_MAGIC_CHECK_QUADTREE_ROOT(root, NULL);
root->both = eina_list_free(root->both);
root->left = eina_quadtree_root_free(q, root->left);
root->right = eina_quadtree_root_free(q, root->right);
EINA_MAGIC_SET(root, 0);
/* eina_quadtree_root_free is only called when the memory pool will be destroyed */
return NULL;
}
static Eina_QuadTree_Root *
eina_quadtree_root_rebuild_pre(Eina_QuadTree *q,
Eina_Array *change,
Eina_QuadTree_Root *root)
{
Eina_QuadTree_Item *item;
if (!root) return NULL;
EINA_LIST_FREE(root->both, item)
{
if (item->visible)
{
eina_array_push(change, item);
}
else if (!item->hidden)
{
q->hidden = eina_list_append(q->hidden, item);
item->hidden = EINA_TRUE;
item->root = NULL;
}
}
root->left = eina_quadtree_root_rebuild_pre(q, change, root->left);
root->right = eina_quadtree_root_rebuild_pre(q, change, root->right);
EINA_MAGIC_SET(root, 0);
if (q->root_count > 50)
{
eina_mempool_free(q->root_mp, root);
}
else
{
eina_trash_push(&q->root_trash, root);
q->root_count++;
}
return NULL;
}
static size_t
_eina_quadtree_split(Eina_Array *objects,
Eina_QuadTree_Root *root,
Eina_Array *left,
Eina_Array *right,
Eina_Quad_Callback func,
int border,
int middle)
{
Eina_QuadTree_Item *object;
Eina_Array_Iterator it;
unsigned int i;
middle /= 2;
if (middle <= 4)
{
EINA_ARRAY_ITER_NEXT(objects, i, object, it)
{
object->change = EINA_FALSE;
if (!object->visible)
{
if (!object->hidden)
{
object->hidden = EINA_TRUE;
object->quad->hidden = eina_list_append(object->quad->hidden,
object);
}
continue;
}
if (object->hidden)
{
object->hidden = EINA_FALSE;
object->quad->hidden = eina_list_remove(object->quad->hidden, object);
}
if (!object->delete_me)
{
if (root->sorted)
{
root->both = eina_list_sorted_insert(root->both,
_eina_quadtree_item_cmp,
object);
}
else
{
root->both = eina_list_append(root->both, object);
}
object->root = root;
}
else
{
eina_quadtree_del(object);
}
}
}
else
{
EINA_ARRAY_ITER_NEXT(objects, i, object, it)
{
object->change = EINA_FALSE;
if (!object->visible)
{
if (!object->hidden)
{
object->hidden = EINA_TRUE;
object->quad->hidden = eina_list_append(object->quad->hidden,
object);
}
continue;
}
if (object->hidden)
{
object->hidden = EINA_FALSE;
object->quad->hidden = eina_list_remove(object->quad->hidden, object);
}
if (!object->delete_me)
{
switch (func(object->object, border + middle))
{
case EINA_QUAD_LEFT:
eina_array_push(left, object);
break;
case EINA_QUAD_RIGHT:
eina_array_push(right, object);
break;
case EINA_QUAD_BOTH:
root->both = eina_list_append(root->both, object);
object->root = root;
break;
default:
abort();
}
}
else
{
eina_quadtree_del(object);
}
}
}
eina_array_clean(objects);
return middle;
}
static Eina_QuadTree_Root *
_eina_quadtree_update(Eina_QuadTree *q, Eina_QuadTree_Root *parent,
Eina_QuadTree_Root *root, Eina_Array *objects,
Eina_Bool direction, Eina_Rectangle *size)
{
Eina_Array right;
Eina_Array left;
size_t w2;
size_t h2;
if (!objects || eina_array_count_get(objects) == 0)
return root;
if (!root)
{
root = eina_trash_pop(&q->root_trash);
if (!root) root = eina_mempool_malloc(q->root_mp, sizeof (Eina_QuadTree_Root));
else q->root_count--;
if (!root)
{
/* FIXME: NOT GOOD TIMING, WE ARE GOING TO LEAK MORE MEMORY */
return NULL;
}
root->parent = parent;
root->both = NULL;
root->left = NULL;
root->right = NULL;
root->sorted = EINA_TRUE;
EINA_MAGIC_SET(root, EINA_MAGIC_QUADTREE_ROOT);
}
eina_array_step_set(&right, 32);
eina_array_step_set(&left, 32);
w2 = 0;
h2 = 0;
if (direction)
w2 = _eina_quadtree_split(objects, root,
&left, &right,
q->func.h, size->x, size->w);
else
h2 = _eina_quadtree_split(objects, root,
&left, &right,
q->func.v, size->y, size->h);
size->w -= w2; size->h -= h2;
root->left = _eina_quadtree_update(q, root,
root->left, &left,
!direction, size);
size->x += w2; size->y += h2;
root->right = _eina_quadtree_update(q, root,
root->right, &right,
!direction, size);
size->x -= w2; size->y -= h2;
size->w += w2; size->h += h2;
eina_array_flush(&left);
eina_array_flush(&right);
return root;
}
static Eina_Inlist *
_eina_quadtree_merge(Eina_Inlist *result,
Eina_List *both)
{
Eina_QuadTree_Item *item;
Eina_QuadTree_Item *b;
Eina_Inlist *moving;
if (!both) return result;
if (!result)
{
Eina_List *l;
EINA_LIST_FOREACH(both, l, item)
if (item->visible)
result = eina_inlist_append(result, EINA_INLIST_GET(item));
return result;
}
moving = result;
item = EINA_INLIST_CONTAINER_GET(moving, Eina_QuadTree_Item);
b = eina_list_data_get(both);
while (both && moving)
{
if (!b->visible)
{
both = eina_list_next(both);
b = eina_list_data_get(both);
continue ;
}
if (_eina_quadtree_item_cmp(item, b) < 0)
{
/* moving is still lower than item, so we can continue to the next one. */
moving = moving->next;
item = EINA_INLIST_CONTAINER_GET(moving, Eina_QuadTree_Item);
}
else
{
/* we just get above the limit of both, so insert it */
result = eina_inlist_prepend_relative(result,
EINA_INLIST_GET(b),
moving);
both = eina_list_next(both);
b = eina_list_data_get(both);
}
}
item = EINA_INLIST_CONTAINER_GET(result->last, Eina_QuadTree_Item);
while (both)
{
b = eina_list_data_get(both);
if (b->visible)
{
if (_eina_quadtree_item_cmp(item, b) < 0)
break;
result = eina_inlist_prepend_relative(result,
EINA_INLIST_GET(b),
result->last);
}
both = eina_list_next(both);
}
while (both)
{
b = eina_list_data_get(both);
if (b->visible)
result = eina_inlist_append(result, EINA_INLIST_GET(b));
both = eina_list_next(both);
}
return result;
}
static Eina_Inlist *
_eina_quadtree_collide(Eina_Inlist *result,
Eina_QuadTree_Root *root,
Eina_Bool direction, Eina_Rectangle *size,
Eina_Rectangle *target)
{
if (!root) return result;
if (!root->sorted)
{
root->both = eina_list_sort(root->both, -1, _eina_quadtree_item_cmp);
root->sorted = EINA_TRUE;
}
result = _eina_quadtree_merge(result, root->both);
DBG("%p: %i in both for (%i, %i - %i, %i)",
root, eina_list_count(root->both),
size->x, size->y, size->w, size->h);
if (direction)
{
int middle = size->w / 2;
size->w -= middle;
if (eina_spans_intersect(size->x, size->w, target->x, target->w))
result = _eina_quadtree_collide(result, root->left,
!direction, size,
target);
size->x += middle;
if (eina_spans_intersect(size->x, size->w, target->x, target->w))
result = _eina_quadtree_collide(result, root->right,
!direction, size,
target);
size->x -= middle;
size->w += middle;
}
else
{
int middle = size->h / 2;
size->h -= middle;
if (eina_spans_intersect(size->y, size->h, target->y, target->h))
result = _eina_quadtree_collide(result, root->left,
!direction, size,
target);
size->y += middle;
if (eina_spans_intersect(size->y, size->h, target->y, target->h))
result = _eina_quadtree_collide(result, root->right,
!direction, size,
target);
size->y -= middle;
size->h += middle;
}
return result;
}
static void
_eina_quadtree_remove(Eina_QuadTree_Item *object)
{
if (!object->root) return ;
object->root->both = eina_list_remove(object->root->both, object);
if (object->root->both) goto end;
if (object->root->left) goto end;
if (object->root->right) goto end;
/* The root is not usefull anymore... */
if (object->root->parent)
{
if (object->root->parent->left == object->root)
object->root->parent->left = NULL;
else
object->root->parent->right = NULL;
object->root->parent = NULL;
}
else
{
object->quad->root = NULL;
}
if (object->quad->root_count > 50)
{
eina_mempool_free(object->quad->root_mp, object->root);
}
else
{
eina_trash_push(&object->quad->root_trash, object->root);
object->quad->root_count++;
}
end:
object->root = NULL;
}
EAPI Eina_QuadTree *
eina_quadtree_new(size_t w, size_t h,
Eina_Quad_Callback vertical, Eina_Quad_Callback horizontal)
{
Eina_QuadTree *result;
if (!vertical || !horizontal || h == 0 || w == 0)
return NULL;
result = calloc(1, sizeof (Eina_QuadTree));
if (!result)
return NULL;
result->func.v = vertical;
result->func.h = horizontal;
result->geom.w = w;
result->geom.h = h;
result->change = eina_array_new(32);
result->items_mp = eina_mempool_add("chained_mempool", "QuadTree Item", NULL,
sizeof (Eina_QuadTree_Item), 320);
result->root_mp = eina_mempool_add("chained_mempool", "QuadTree Root", NULL,
sizeof (Eina_QuadTree_Root), 32);
EINA_MAGIC_SET(result, EINA_MAGIC_QUADTREE);
return result;
}
EAPI void
eina_quadtree_free(Eina_QuadTree *q)
{
if (!q) return ;
EINA_MAGIC_CHECK_QUADTREE(q);
eina_array_free(q->change);
q->hidden = eina_list_free(q->hidden);
eina_quadtree_root_free(q, q->root);
eina_mempool_del(q->items_mp);
eina_mempool_del(q->root_mp);
EINA_MAGIC_SET(q, 0);
free(q);
}
EAPI Eina_QuadTree_Item *
eina_quadtree_add(Eina_QuadTree *q, const void *object)
{
Eina_QuadTree_Item *result;
EINA_MAGIC_CHECK_QUADTREE(q, NULL);
if (!object) return NULL;
result = eina_trash_pop(&q->items_trash);
if (!result) result = eina_mempool_malloc(q->items_mp, sizeof (Eina_QuadTree_Item));
else q->items_count--;
if (!result) return NULL;
result->quad = q;
result->root = NULL;
result->object = object;
result->change = EINA_TRUE;
result->delete_me = EINA_FALSE;
result->visible = EINA_TRUE;
result->hidden = EINA_FALSE;
EINA_MAGIC_SET(result, EINA_MAGIC_QUADTREE_ITEM);
/* Insertion is delayed until we really need to use it */
eina_array_push(q->change, result);
return result;
}
EAPI Eina_Bool
eina_quadtree_del(Eina_QuadTree_Item *object)
{
if (!object) return EINA_FALSE;
EINA_MAGIC_CHECK_QUADTREE_ITEM(object, EINA_FALSE);
_eina_quadtree_remove(object);
if (object->change)
{
/* This object is still in the update array, delaying it's removal !*/
object->delete_me = EINA_TRUE;
object->visible = EINA_TRUE;
return EINA_TRUE;
}
if (object->hidden)
{
object->quad->hidden = eina_list_remove(object->quad->hidden, object);
object->hidden = EINA_TRUE;
}
/* This object is not anymore inside the tree, we can remove it now !*/
EINA_MAGIC_SET(object, 0);
if (object->quad->items_count > 256)
{
eina_mempool_free(object->quad->items_mp, object);
}
else
{
object->quad->items_count++;
eina_trash_push(&object->quad->items_trash, object);
}
return EINA_TRUE;
}
EAPI Eina_Bool
eina_quadtree_change(Eina_QuadTree_Item *object)
{
EINA_MAGIC_CHECK_QUADTREE_ITEM(object, EINA_FALSE);
if (object->delete_me || !object->visible)
return EINA_FALSE;
if (object->quad->resize)
return EINA_TRUE;
/* Delaying change until needed */
if (!object->change)
eina_array_push(object->quad->change, object);
object->change = EINA_TRUE;
_eina_quadtree_remove(object);
return EINA_TRUE;
}
EAPI Eina_Bool
eina_quadtree_hide(Eina_QuadTree_Item *object)
{
EINA_MAGIC_CHECK_QUADTREE_ITEM(object, EINA_FALSE);
object->visible = EINA_FALSE;
return EINA_TRUE;
}
EAPI Eina_Bool
eina_quadtree_show(Eina_QuadTree_Item *object)
{
EINA_MAGIC_CHECK_QUADTREE_ITEM(object, EINA_FALSE);
object->index = object->quad->index++;
if (object->root)
object->root->sorted = EINA_FALSE;
if (object->visible) return EINA_TRUE;
object->visible = EINA_TRUE;
if (!object->change)
return eina_quadtree_change(object);
return EINA_TRUE;
}
EAPI void
eina_quadtree_collide(Eina_Array *result,
Eina_QuadTree *q, int x, int y, size_t w, size_t h)
{
Eina_Inlist *head = NULL;
Eina_QuadTree_Item *current;
Eina_QuadTree_Item *p = NULL;
Eina_Rectangle canvas;
Eina_Rectangle target;
Eina_Array_Iterator it;
unsigned int i;
EINA_MAGIC_CHECK_QUADTREE(q);
/* Now we need the tree to be up to date, so it's time */
if (q->resize) /* Full rebuild needed ! */
{
DBG("resizing quadtree");
q->root = eina_quadtree_root_rebuild_pre(q, q->change, q->root);
q->resize = EINA_FALSE;
}
EINA_RECTANGLE_SET(&canvas, 0, 0, q->geom.w, q->geom.h);
if (eina_array_count_get(q->change) > 0)
{
DBG("updating quadtree content");
q->root = _eina_quadtree_update(q, NULL, q->root, q->change,
EINA_FALSE, &canvas);
}
EINA_RECTANGLE_SET(&target, x, y, w, h);
DBG("colliding content");
head = _eina_quadtree_collide(NULL, q->root,
EINA_FALSE, &canvas,
&target);
EINA_INLIST_FOREACH(head, current)
eina_array_push(result, current->object);
}
EAPI void
eina_quadtree_resize(Eina_QuadTree *q, size_t w, size_t h)
{
EINA_MAGIC_CHECK_QUADTREE(q);
if (q->geom.w == w
&& q->geom.h == h)
return ;
q->resize = EINA_TRUE;
q->geom.w = w;
q->geom.h = h;
}
Eina_Bool
eina_quadtree_init(void)
{
_eina_log_qd_dom = eina_log_domain_register("eina_quadtree", EINA_LOG_COLOR_DEFAULT);
if (_eina_log_qd_dom < 0)
{
EINA_LOG_ERR("Could not register log domain: eina_quadtree");
return EINA_FALSE;
}
#define EMS(n) eina_magic_string_static_set(n, n##_STR)
EMS(EINA_MAGIC_QUADTREE);
EMS(EINA_MAGIC_QUADTREE_ROOT);
EMS(EINA_MAGIC_QUADTREE_ITEM);
#undef EMS
return EINA_TRUE;
}
Eina_Bool
eina_quadtree_shutdown(void)
{
eina_log_domain_unregister(_eina_log_qd_dom);
_eina_log_qd_dom = -1;
return EINA_TRUE;
}

View File

@ -0,0 +1,304 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#define WIDTH 720
#define HEIGHT 576
#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_Array *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);
}
possibility = eina_array_new(64);
for (j = 0; j < 100; ++j)
{
Eina_Bench_Quad *collide;
Eina_List *changed = NULL;
Eina_List *collided = NULL;
Eina_Array_Iterator it;
unsigned int k;
/* 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);
eina_quadtree_collide(possibility, q,
collide->r.x, collide->r.y,
collide->r.w, collide->r.h);
EINA_ARRAY_ITER_NEXT(possibility, k, b, it)
if (eina_rectangles_intersect(&b->r, &collide->r))
collided = eina_list_append(collided, b);
collided = eina_list_free(collided);
eina_mempool_free(mp, collide);
eina_array_clean(possibility);
/* 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)
{
eina_quadtree_collide(possibility, q,
b->r.x, b->r.y, b->r.w, b->r.h);
EINA_ARRAY_ITER_NEXT(possibility, k, collide, it)
if (collide != b && eina_rectangles_intersect(&b->r, &collide->r))
collided = eina_list_append(collided, collide);
eina_array_clean(possibility);
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);
}

View File

@ -0,0 +1,93 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <math.h>
#include <stdio.h>
#include "eina_suite.h"
#include "Eina.h"
START_TEST(eina_fp_cos)
{
Eina_F32p32 fc;
Eina_F32p32 fl;
Eina_F32p32 step;
Eina_F32p32 fresult;
double dc;
double dresult;
double delta;
fail_if(!eina_init());
fl = eina_f32p32_scale(EINA_F32P32_PI, 4);
step = eina_f32p32_div(fl, eina_f32p32_int_from(2048));
for (fc = 0; fc < fl; fc += step)
{
fresult = eina_f32p32_cos(fc);
dc = eina_f32p32_double_to(fc);
dresult = cos(dc);
delta = fabs(dresult - eina_f32p32_double_to(fresult));
fail_if(delta > 0.005);
}
eina_shutdown();
}
END_TEST
START_TEST(eina_fp_sin)
{
Eina_F32p32 fc;
Eina_F32p32 fl;
Eina_F32p32 step;
Eina_F32p32 fresult;
double dc;
double dresult;
double delta;
fail_if(!eina_init());
fl = eina_f32p32_scale(EINA_F32P32_PI, 4);
step = eina_f32p32_div(fl, eina_f32p32_int_from(2048));
for (fc = 0; fc < fl; fc += step)
{
fresult = eina_f32p32_sin(fc);
dc = eina_f32p32_double_to(fc);
dresult = sin(dc);
delta = fabs(dresult - eina_f32p32_double_to(fresult));
fail_if(delta > 0.005);
}
eina_shutdown();
}
END_TEST
void
eina_test_fp(TCase *tc)
{
tcase_add_test(tc, eina_fp_cos);
tcase_add_test(tc, eina_fp_sin);
}

View File

@ -0,0 +1,160 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "eina_suite.h"
#include "Eina.h"
static Eina_Quad_Direction
_eina_quadtree_rectangle_vert(const void *object, size_t middle)
{
const Eina_Rectangle *r = object;
if (r->y + r->h < (int) middle)
return EINA_QUAD_LEFT;
if (r->y > (int) middle)
return EINA_QUAD_RIGHT;
return EINA_QUAD_BOTH;
}
static Eina_Quad_Direction
_eina_quadtree_rectangle_hort(const void *object, size_t middle)
{
const Eina_Rectangle *r = object;
if (r->x + r->w < (int) middle)
return EINA_QUAD_LEFT;
if (r->x > (int) middle)
return EINA_QUAD_RIGHT;
return EINA_QUAD_BOTH;
}
START_TEST(eina_quadtree_collision)
{
struct {
Eina_Rectangle r;
Eina_QuadTree_Item *item;
} objects[] = {
{ { 10, 10, 30, 30 }, NULL },
{ { 20, 20, 30, 30 }, NULL },
{ { 5, 30, 30, 30 }, NULL },
{ { 70, 130, 100, 100 }, NULL },
{ { 10, 220, 50, 40 }, NULL },
{ { 310, 20, 50, 30 }, NULL },
{ { 300, 220, 40, 40 }, NULL },
{ { 500, 150, 40, 40 }, NULL },
{ { 500, 220, 40, 40 }, NULL },
{ { 330, 250, 40, 40 }, NULL },
{ { 300, 400, 40, 40 }, NULL },
{ { 10, 400, 40, 40 }, NULL },
{ { 0, 0, 0, 0 }, NULL }
};
struct {
Eina_Rectangle r;
int count;
int result[20];
} tests [] = {
{ { 600, 400, 40, 40 }, 4, { 4, 6, 8, 10 } },
{ { 20, 30, 10, 10 }, 7, { 0, 1, 2, 4, 5, 6, 8 } },
{ { 0, 0, 0, 0 }, -1, {} },
};
int hidden[] = { 4, 5, 6, 8, 10 };
int show[] = { 0, 1, 2 };
Eina_QuadTree *q;
Eina_Array *result;
Eina_Rectangle *r;
Eina_Array_Iterator it;
unsigned int j;
int i;
fail_if(!eina_init());
q = eina_quadtree_new(640, 480,
_eina_quadtree_rectangle_vert,
_eina_quadtree_rectangle_hort);
fail_if(!q);
for (i = 0; objects[i].r.w != 0 && objects[i].r.h != 0; ++i)
{
objects[i].item = eina_quadtree_add(q, &objects[i].r);
fail_if(!objects[i].item);
fail_if(!eina_quadtree_show(objects[i].item));
}
result = eina_array_new(16);
fail_if(!result);
for (i = 0; tests[i].count != -1; ++i)
{
eina_quadtree_collide(result, q,
tests[i].r.x, tests[i].r.y, tests[i].r.w, tests[i].r.h);
fail_if(eina_array_count_get(result) != (unsigned int) tests[i].count);
EINA_ARRAY_ITER_NEXT(result, j, r, it)
{
int k;
for (k = 0; k < tests[i].count; ++k)
{
if (&objects[tests[i].result[k]].r == r)
break;
}
fail_if(k == tests[i].count);
}
eina_array_clean(result);
}
for (j = 0; j < sizeof (hidden) / sizeof (int); ++j)
eina_quadtree_hide(objects[hidden[j]].item);
for (j = 0; j < sizeof (show) / sizeof (int); ++j)
eina_quadtree_show(objects[show[j]].item);
eina_quadtree_collide(result, q,
tests[1].r.x, tests[1].r.y, tests[1].r.w, tests[1].r.h);
fail_if(eina_array_count_get(result) != 3);
EINA_ARRAY_ITER_NEXT(result, j, r, it)
fail_if(r != &objects[tests[1].result[show[j]]].r);
eina_array_clean(result);
eina_quadtree_show(objects[4].item);
eina_quadtree_show(objects[5].item);
eina_quadtree_del(objects[5].item);
eina_quadtree_change(objects[10].item);
eina_quadtree_collide(result, q,
tests[0].r.x, tests[0].r.y, tests[0].r.w, tests[0].r.h);
fail_if(eina_array_count_get(result) != 1);
eina_quadtree_free(q);
eina_shutdown();
}
END_TEST
void
eina_test_quadtree(TCase *tc)
{
tcase_add_test(tc, eina_quadtree_collision);
}