Added the Eina_Tile_Grid_Slicer iterator.
authorantognolli <antognolli>
Fri, 11 Sep 2009 23:51:47 +0000 (23:51 +0000)
committerantognolli <antognolli@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 11 Sep 2009 23:51:47 +0000 (23:51 +0000)
This new iterator receives a rectangle as argument and tile_w X tile_h sized
tile, and slices the rectangle iterating over it on each iteration.

git-svn-id: http://svn.enlightenment.org/svn/e/trunk/eina@42427 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/include/Makefile.am
src/include/eina_inline_tiler.x [new file with mode: 0644]
src/include/eina_tiler.h
src/lib/eina_tiler.c
src/tests/Makefile.am
src/tests/eina_suite.c
src/tests/eina_suite.h
src/tests/eina_test_tiler.c [new file with mode: 0644]

index 78d266d..fff22a4 100644 (file)
@@ -38,7 +38,8 @@ eina_main.h \
 eina_cpu.h \
 eina_tiler.h \
 eina_hamster.h \
-eina_matrixsparse.h
+eina_matrixsparse.h \
+eina_inline_tiler.x
 
 installed_mainheaderdir = $(includedir)/eina-@VMAJ@
 dist_installed_mainheader_DATA = Eina.h eina_config.h
diff --git a/src/include/eina_inline_tiler.x b/src/include/eina_inline_tiler.x
new file mode 100644 (file)
index 0000000..3a597d8
--- /dev/null
@@ -0,0 +1,174 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2009 Rafael Antognolli
+ *
+ * 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_TILER_INLINE_H_
+#define EINA_TILER_INLINE_H_
+
+#include "eina_safety_checks.h"
+
+/**
+ * This struct should not be accessed directly, it is used by
+ * eina_tile_grid_slicer functions to maintain context and fill "info"
+ * member with correct values for given iteration.
+ */
+struct _Eina_Tile_Grid_Slicer
+{
+   unsigned long col1, col2, row1, row2; // initial and final col,row
+   int tile_w, tile_h; // tile width, height
+   int x_rel, y_rel; // starting x,y coordinates of the first col,row
+   int w1_rel, h1_rel; // width,height of the first col,row
+   int w2_rel, h2_rel; // width,height of the last col,row
+   struct Eina_Tile_Grid_Info info; // info about the current tile
+   Eina_Bool first;
+};
+
+/**
+ * @brief Iterates over the tiles set by eina_tile_grid_slicer_setup().
+ *
+ * @param   slc Pointer to an Eina_Tile_Grid_Slicer struct.
+ * @param   rect Pointer to a struct Eina_Tile_Grid_Info *.
+ * @return  @c EINA_TRUE if the current rect is valid.
+ *          @c EINA_FALSE if there is no more rects to iterate over (and
+ *            thus the current one isn't valid).
+ *
+ * This functions iterates over each Eina_Tile_Grid_Info *rect of the grid.
+ * eina_tile_grid_slicer_setup() must be called first, and *rect is only valid
+ * if this function returns EINA_TRUE. Its content shouldn't be modified.
+ */
+static inline Eina_Bool
+eina_tile_grid_slicer_next(Eina_Tile_Grid_Slicer *slc, const Eina_Tile_Grid_Info **rect)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(slc, 0);
+
+   if (slc->first)
+     {
+       slc->first = 0;
+       *rect = &slc->info;
+       return EINA_TRUE;
+     }
+
+   slc->info.col++;
+
+   if (slc->info.col > slc->col2)
+     {
+       slc->info.row++;
+       if (slc->info.row > slc->row2)
+         return EINA_FALSE;
+       else if (slc->info.row < slc->row2)
+         slc->info.rect.h = slc->tile_h;
+       else
+         slc->info.rect.h = slc->h2_rel;
+       slc->info.rect.y = 0;
+       slc->info.col = slc->col1;
+       slc->info.rect.x = slc->x_rel;
+       slc->info.rect.w = slc->w1_rel;
+     }
+   else
+     {
+       slc->info.rect.x = 0;
+       if (slc->info.col < slc->col2)
+         slc->info.rect.w = slc->tile_w;
+       else
+         slc->info.rect.w = slc->w2_rel;
+     }
+
+   if (slc->info.rect.w == slc->tile_w && slc->info.rect.h == slc->tile_h)
+     slc->info.full = EINA_TRUE;
+   else
+     slc->info.full = EINA_FALSE;
+
+   *rect = &slc->info;
+
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Setup an Eina_Tile_Grid_Slicer struct.
+ *
+ * @param   slc Pointer to an Eina_Tile_Grid_Slicer struct.
+ * @param   x X axis coordinate.
+ * @param   y Y axis coordinate.
+ * @param   w width.
+ * @param   h height.
+ * @param   tile_w tile width.
+ * @param   tile_h tile height.
+ * @return  A pointer to the Eina_Iterator.
+ *          @c NULL on failure.
+ *
+ * This function splits the rectangle given as argument into tiles of size
+ * tile_w X tile_h, and returns an iterator to them. The geometry of each
+ * tile can be accessed with eina_tile_grid_slicer_next, where rect
+ * will be a pointer to a struct Eina_Tile_Grid_Info.
+ */
+static inline Eina_Bool
+eina_tile_grid_slicer_setup(Eina_Tile_Grid_Slicer *slc, int x, int y, int w, int h, int tile_w, int tile_h)
+{
+   int x1, x2, y1, y2;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(slc, 0);
+
+   x1 = x;
+   y1 = y;
+   x2 = x + w - 1;
+   y2 = y + h - 1;
+
+   if (x < 0 || y < 0 || w <= 0 || h <= 0 || tile_w <= 0 || tile_h <= 0)
+     {
+       slc->col1 = slc->row1 = 0;
+       slc->col2 = slc->row2 = 0;
+       return EINA_TRUE;
+     }
+
+   slc->col1 = x1 / tile_w;
+   slc->row1 = y1 / tile_h;
+   slc->col2 = (x2 - 0) / tile_w;
+   slc->row2 = (y2 - 0) / tile_h;
+   slc->x_rel = x1 % tile_w;
+   slc->y_rel = y1 % tile_h;
+   slc->w1_rel = tile_w - slc->x_rel;
+   slc->h1_rel = tile_h - slc->y_rel;
+   slc->w2_rel = x2 % tile_w + 1;
+   slc->h2_rel = y2 % tile_h + 1;
+
+   slc->tile_w = tile_w;
+   slc->tile_h = tile_h;
+
+   slc->first = 1;
+   slc->info.col = slc->col1;
+   slc->info.row = slc->row1;
+   slc->info.rect.x = slc->x_rel;
+   slc->info.rect.y = slc->y_rel;
+
+   if (slc->info.col == slc->col2)
+     slc->w1_rel = slc->w2_rel - slc->x_rel;
+
+   if (slc->info.row == slc->row2)
+     slc->h1_rel = slc->h2_rel - slc->y_rel;
+
+   slc->info.rect.w = slc->w1_rel;
+   slc->info.rect.h = slc->h1_rel;
+
+   if (slc->info.rect.w == slc->tile_w && slc->info.rect.h == slc->tile_h)
+     slc->info.full = EINA_TRUE;
+   else
+     slc->info.full = EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+#endif
index 5ba7964..1a04a9c 100644 (file)
 
 typedef struct _Eina_Tiler Eina_Tiler;
 
+struct Eina_Tile_Grid_Info
+{
+   unsigned long col, row;
+   Eina_Rectangle rect;
+   Eina_Bool full;
+};
+
+typedef struct Eina_Tile_Grid_Info Eina_Tile_Grid_Info;
+typedef struct _Eina_Tile_Grid_Slicer Eina_Tile_Grid_Slicer;
+
 EAPI Eina_Tiler *eina_tiler_new(int w, int h);
 EAPI void eina_tiler_free(Eina_Tiler *t);
 EAPI void eina_tiler_tile_size_set(Eina_Tiler *t, int w, int h);
@@ -32,5 +42,10 @@ EAPI Eina_Bool eina_tiler_rect_add(Eina_Tiler *t, const Eina_Rectangle *r);
 EAPI void eina_tiler_rect_del(Eina_Tiler *t, const Eina_Rectangle *r);
 EAPI void eina_tiler_clear(Eina_Tiler *t);
 EAPI Eina_Iterator * eina_tiler_iterator_new(const Eina_Tiler *t);
+EAPI Eina_Iterator * eina_tile_grid_slicer_iterator_new(int x, int y, int w, int h, int tile_w, int tile_h);
+static inline Eina_Bool eina_tile_grid_slicer_next(Eina_Tile_Grid_Slicer *slc, const Eina_Tile_Grid_Info **rect);
+static inline Eina_Bool eina_tile_grid_slicer_setup(Eina_Tile_Grid_Slicer *slc, int x, int y, int w, int h, int tile_w, int tile_h);
+
+#include "eina_inline_tiler.x"
 
 #endif /* EINA_TILER_H_ */
index 2f53e14..be259ba 100644 (file)
@@ -32,6 +32,7 @@
 #include "eina_config.h"
 #include "eina_private.h"
 #include "eina_tiler.h"
+#include "eina_error.h"
 
 /*============================================================================*
  *                                  Local                                     *
@@ -1215,3 +1216,66 @@ EAPI Eina_Iterator * eina_tiler_iterator_new(const Eina_Tiler *t)
 
        return &it->iterator;
 }
+
+struct _Eina_Tile_Grid_Slicer_Iterator
+{
+   Eina_Iterator iterator;
+   Eina_Tile_Grid_Slicer priv;
+};
+
+typedef struct _Eina_Tile_Grid_Slicer_Iterator Eina_Tile_Grid_Slicer_Iterator;
+
+static void
+eina_tile_grid_slicer_iterator_free(Eina_Tile_Grid_Slicer_Iterator *it)
+{
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_NONE);
+   free(it);
+}
+
+static Eina_Bool
+eina_tile_grid_slicer_iterator_next(Eina_Tile_Grid_Slicer_Iterator *it, void **data)
+{
+   return eina_tile_grid_slicer_next(&it->priv, data);
+}
+
+/**
+ * @brief Creates a new Eina_Iterator that slices over a list of tiles.
+ *
+ * @param   x X axis coordinate.
+ * @param   y Y axis coordinate.
+ * @param   w width.
+ * @param   h height.
+ * @param   tile_w tile width.
+ * @param   tile_h tile height.
+ * @return  A pointer to the Eina_Iterator.
+ *          @c NULL on failure.
+ *
+ * The tile grid is defined by @a tile_w and @a tile_h while the region is
+ * defined by @a x, @a y, @a w, @a h. The output is given as
+ * @c Eina_Tile_Grid_Info where tile index is given in @c col col and
+ * @c row row with tile-relative
+ *    coordinates in @c x, @c y, @c w, @c h. If tile was fully filled by
+ *    region, then @c full flag
+ *     is set.
+ */
+EAPI Eina_Iterator *
+eina_tile_grid_slicer_iterator_new(int x, int y, int w, int h, int tile_w, int tile_h)
+{
+   Eina_Tile_Grid_Slicer_Iterator *it;
+
+   it = calloc(1, sizeof(*it));
+   if (!it)
+     {
+       eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+       return NULL;
+     }
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->iterator.next = FUNC_ITERATOR_NEXT(eina_tile_grid_slicer_iterator_next);
+   it->iterator.free = FUNC_ITERATOR_FREE(eina_tile_grid_slicer_iterator_free);
+
+   eina_tile_grid_slicer_setup(&it->priv, x, y, w, h, tile_w, tile_h);
+
+   return &it->iterator;
+}
index d616380..cb5d3d8 100644 (file)
@@ -66,7 +66,8 @@ eina_test_benchmark.c \
 eina_test_mempool.c    \
 eina_test_rectangle.c  \
 eina_test_list.c       \
-eina_test_matrixsparse.c
+eina_test_matrixsparse.c \
+eina_test_tiler.c
 
 eina_suite_LDADD = @CHECK_LIBS@ $(top_builddir)/src/lib/libeina.la
 
index 2fefa9e..e753dae 100644 (file)
@@ -54,6 +54,7 @@ static const Eina_Test_Case etc[] = {
   { "Mempool", eina_test_mempool },
   { "Rectangle", eina_test_rectangle },
   { "Matrix Sparse", eina_test_matrixsparse },
+  { "Eina Tiler", eina_test_tiler },
   { NULL, NULL }
 };
 
index 2928c05..a2ad389 100644 (file)
@@ -42,5 +42,6 @@ void eina_test_benchmark(TCase *tc);
 void eina_test_mempool(TCase *tc);
 void eina_test_rectangle(TCase *tc);
 void eina_test_matrixsparse(TCase *tc);
+void eina_test_tiler(TCase *tc);
 
 #endif /* EINA_SUITE_H_ */
diff --git a/src/tests/eina_test_tiler.c b/src/tests/eina_test_tiler.c
new file mode 100644 (file)
index 0000000..e24044f
--- /dev/null
@@ -0,0 +1,128 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2009 Rafael Antognolli
+ *
+ * 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 <stdio.h>
+
+#include "eina_suite.h"
+#include "Eina.h"
+
+struct test_rect {
+     unsigned long col, row;
+     int x, y, w, h;
+     Eina_Bool full;
+};
+
+static void
+check_iterator(Eina_Iterator *it, struct test_rect *cur_test)
+{
+   unsigned int i = 0;
+   struct Eina_Tile_Grid_Info *tile;
+
+   EINA_ITERATOR_FOREACH(it, tile) {
+      fail_if(cur_test[i].col != tile->col ||
+             cur_test[i].row != tile->row ||
+             cur_test[i].x != tile->rect.x ||
+             cur_test[i].y != tile->rect.y ||
+             cur_test[i].w != tile->rect.w ||
+             cur_test[i].h != tile->rect.h ||
+             cur_test[i].full != tile->full);
+      i++;
+   }
+}
+
+START_TEST(eina_test_tile_grid_slicer_iterator)
+{
+   Eina_Iterator *it;
+   struct test_rect *cur_test;
+   struct test_rect test1[] = {{1, 1, 72, 82, 10, 15, 0}};
+   struct test_rect test2[] =
+     {{1, 1,  72,  82,  56,  15,  0},
+      {2, 1,   0,  82, 128,  15,  0},
+      {3, 1,   0,  82, 116,  15,  0}};
+   struct test_rect test3[] =
+     {{1, 1,  72,  82,  10,  46,  0},
+      {1, 2,  72,   0,  10, 128,  0},
+      {1, 3,  72,   0,  10, 126,  0}};
+   struct test_rect test4[] =
+     {{1, 1,  72,  82,  56,  46,  0},
+      {2, 1,   0,  82, 128,  46,  0},
+      {3, 1,   0,  82, 128,  46,  0},
+      {4, 1,   0,  82,  88,  46,  0},
+      {1, 2,  72,   0,  56, 128,  0},
+      {2, 2,   0,   0, 128, 128,  1},
+      {3, 2,   0,   0, 128, 128,  1},
+      {4, 2,   0,   0,  88, 128,  0},
+      {1, 3,  72,   0,  56, 126,  0},
+      {2, 3,   0,   0, 128, 126,  0},
+      {3, 3,   0,   0, 128, 126,  0},
+      {4, 3,   0,   0,  88, 126,  0}};
+   struct test_rect test5[] = {{1, 1, 0, 0, 128, 128, 1}};
+   struct test_rect test6[] = {{1, 1, 0, 0, 1, 1, 0}};
+   struct test_rect test7[] =
+     {{1, 1,   0,   0, 128, 128,  1},
+      {2, 1,   0,   0,   1, 128,  0},
+      {1, 2,   0,   0, 128,   1,  0},
+      {2, 2,   0,   0,   1,   1,  0}};
+
+
+   cur_test = test1;
+   it = eina_tile_grid_slicer_iterator_new(200, 210, 10, 15, 128, 128);
+   check_iterator(it, cur_test);
+   eina_iterator_free(it);
+
+   cur_test = test2;
+   it = eina_tile_grid_slicer_iterator_new(200, 210, 300, 15, 128, 128);
+   check_iterator(it, cur_test);
+   eina_iterator_free(it);
+
+   cur_test = test3;
+   it = eina_tile_grid_slicer_iterator_new(200, 210, 10, 300, 128, 128);
+   check_iterator(it, cur_test);
+   eina_iterator_free(it);
+
+   cur_test = test4;
+   it = eina_tile_grid_slicer_iterator_new(200, 210, 400, 300, 128, 128);
+   check_iterator(it, cur_test);
+   eina_iterator_free(it);
+
+   cur_test = test5;
+   it = eina_tile_grid_slicer_iterator_new(128, 128, 128, 128, 128, 128);
+   check_iterator(it, cur_test);
+   eina_iterator_free(it);
+
+   cur_test = test6;
+   it = eina_tile_grid_slicer_iterator_new(128, 128, 1, 1, 128, 128);
+   check_iterator(it, cur_test);
+   eina_iterator_free(it);
+
+   cur_test = test7;
+   it = eina_tile_grid_slicer_iterator_new(128, 128, 129, 129, 128, 128);
+   check_iterator(it, cur_test);
+   eina_iterator_free(it);
+}
+END_TEST
+
+void
+eina_test_tiler(TCase *tc)
+{
+   tcase_add_test(tc, eina_test_tile_grid_slicer_iterator);
+}