diff --git a/Makefile b/Makefile
index 35847a7..5d9a967 100644
--- a/Makefile
+++ b/Makefile
@@ -5,9 +5,9 @@ CC = gcc
PROG = libsweet.so
-OBJS = sweet_math.o sweet_matrix.o sweet_matrix_stack.o
+OBJS = sweet_math.o sweet_matrix.o sweet_matrix_stack.o sweet_geometry.o
-CFLAGS = -pedantic -fPIC
+CFLAGS = -pedantic -fPIC -Wall
LD = -shared
all: $(PROG)
diff --git a/sweet_geometry.c b/sweet_geometry.c
new file mode 100644
index 0000000..5453b36
--- /dev/null
+++ b/sweet_geometry.c
@@ -0,0 +1,379 @@
+/*
+ * Sweet is a small library for basic math and small matrix operations.
+ * Copyright 2014 Luc Girod.
+ *
+ * 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 3 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 .
+ */
+
+#include
+#include
+#include "sweet_types.h"
+#include "sweet_math.h"
+
+/* Definition of chain list for faces */
+
+struct face_item
+{
+ unsigned int v[3];
+ struct face_item * next;
+ struct face_item * prev;
+};
+
+static struct face_item *
+face_add (struct face_item * root, unsigned int v1, unsigned int v2, unsigned int v3)
+{
+ struct face_item * n = malloc (sizeof (struct face_item));
+ if (n == NULL) { return root; }
+ n->next = root;
+ n->prev = NULL;
+ n->v[0] = v1;
+ n->v[1] = v2;
+ n->v[2] = v3;
+
+ if (root != NULL) { root->prev = n; }
+ return n;
+}
+
+static struct face_item *
+face_rm (struct face_item * root, struct face_item * f)
+{
+ struct face_item * next;
+ struct face_item * prev;
+
+ if (f == NULL) { return root; }
+
+ next = f->next;
+ prev = f->prev;
+ f->next = NULL;
+ f->prev = NULL;
+
+ /* If it's not at one "edge" */
+ if (next != NULL && prev != NULL)
+ {
+ prev->next = next;
+ next->prev = prev;
+ } /* if f is at the end */
+ else if (prev != NULL)
+ {
+ prev->next = NULL;
+
+ } /* if f is at the start */
+ else if (next != NULL)
+ {
+ next->prev = NULL;
+ return next;
+ }
+ else
+ {
+ return NULL;
+ }
+ return root;
+}
+
+static void
+face_free (struct face_item * root)
+{
+ while (root != NULL)
+ {
+ struct face_item * item = root;
+ root = root->next;
+ free (item);
+ }
+}
+
+
+
+/* Definition of map */
+
+struct item
+{
+ struct item * next;
+ unsigned int hash;
+ unsigned int id;
+};
+
+#define MAP_SIZE 8192
+struct map
+{
+ struct item * items[MAP_SIZE];
+ unsigned int count_item;
+};
+
+static void
+map_init (struct map * map)
+{
+ int i;
+ for (i = 0; i < MAP_SIZE; i++)
+ {
+ map->items[i] = NULL;
+ }
+ map->count_item = 0;
+}
+
+static void
+map_free (struct map * map)
+{
+ int i;
+ for (i = 0; i < MAP_SIZE; i++)
+ {
+ struct item * item = map->items[i];
+ while (item != NULL)
+ {
+ struct item * tmp = item;
+ item = item->next;
+ free (tmp);
+ }
+ map->items[i] = NULL;
+ }
+ map->count_item = 0;
+}
+
+static struct item *
+map_get_item (struct map * map, unsigned int hash)
+{
+ struct item * item = map->items[hash % MAP_SIZE];
+ while (item != NULL && item->hash != hash) { item = item->next; }
+ return item;
+}
+
+static int
+map_add_item (struct map * map, unsigned int hash, int id)
+{
+ struct item * next;
+ struct item * item;
+ if (map_get_item (map, hash) != NULL) { return 0; }
+
+ next = map->items[hash % MAP_SIZE];
+ item = malloc (sizeof (struct item));
+ if (item == NULL) { return -1; }
+
+ item->hash = hash;
+ item->next = next;
+ item->id = id;
+
+ map->count_item++;
+ map->items[hash % MAP_SIZE] = item;
+ return 1;
+}
+
+static unsigned int
+hash_2_int (unsigned int a, unsigned int b)
+{
+ return a > b ? a * a + a + b : b * b + b + a;
+}
+
+/* helper structure */
+
+struct vertex_array
+{
+ vec3 * vertices;
+ size_t buffer;
+ unsigned int nb_vertices;
+};
+
+
+/* ICOSPHERE */
+
+/* Local containers */
+static vec3 base_vertices[12] = {
+ {-1, SWEET_GOLDEN_RATIO, 0},
+ { 1, SWEET_GOLDEN_RATIO, 0},
+ {-1, -SWEET_GOLDEN_RATIO, 0},
+ { 1, -SWEET_GOLDEN_RATIO, 0},
+
+ { 0, -1, SWEET_GOLDEN_RATIO},
+ { 0, 1, SWEET_GOLDEN_RATIO},
+ { 0, -1, -SWEET_GOLDEN_RATIO},
+ { 0, 1, -SWEET_GOLDEN_RATIO},
+
+ { SWEET_GOLDEN_RATIO, 0, -1},
+ { SWEET_GOLDEN_RATIO, 0, 1},
+ {-SWEET_GOLDEN_RATIO, 0, -1},
+ {-SWEET_GOLDEN_RATIO, 0, 1}
+};
+
+/* Utils */
+static int
+middle_point (struct map * map,
+ struct vertex_array * v,
+ unsigned int a, unsigned int b)
+{
+ unsigned int hash;
+ struct item * item;
+ unsigned int id;
+ vec3 v1;
+ vec3 v2;
+ vec3 middle;
+
+ hash = hash_2_int (a, b);
+ item = map_get_item (map, hash);
+ id = v->nb_vertices;
+
+ if (item != NULL) { return item->id; }
+
+ v1 = v->vertices[a];
+ v2 = v->vertices[b];
+ middle = sweet_vector_middle3 (v1, v2);
+
+ if (v->buffer < (v->nb_vertices * sizeof (vec3)))
+ {
+ vec3 * p;
+ v->buffer = v->buffer * 2;
+ p = realloc (v->vertices, v->buffer);
+ if (p == NULL) { return -1; }
+ v->vertices = p;
+ }
+ v->vertices[v->nb_vertices++] = sweet_vector_normalize3 (middle);
+
+ if (map_add_item (map, hash, id) == -1) { return -1; }
+ return id;
+}
+
+static struct face_item *
+first_iteration (struct vertex_array * v)
+{
+ struct face_item * root;
+ int i;
+ for (i = 0; i < v->nb_vertices; i++)
+ {
+ v->vertices[i] = sweet_vector_normalize3 (base_vertices[i]);
+ }
+
+ root = face_add (NULL, 0, 11, 5);
+ root = face_add (root, 0, 5, 1);
+ root = face_add (root, 0, 1, 7);
+ root = face_add (root, 0, 7, 10);
+ root = face_add (root, 0, 10, 11);
+
+ root = face_add (root, 1, 5, 9);
+ root = face_add (root, 5, 11, 4);
+ root = face_add (root, 11, 10, 2);
+ root = face_add (root, 10, 7, 6);
+ root = face_add (root, 7, 1, 8);
+
+ root = face_add (root, 3, 9, 4);
+ root = face_add (root, 3, 4, 2);
+ root = face_add (root, 3, 2, 6);
+ root = face_add (root, 3, 6, 8);
+ root = face_add (root, 3, 8, 9);
+
+ root = face_add (root, 4, 9, 5);
+ root = face_add (root, 2, 4, 11);
+ root = face_add (root, 6, 2, 10);
+ root = face_add (root, 8, 6, 7);
+ root = face_add (root, 9, 8, 1);
+
+ return root;
+}
+
+static void
+free_all (struct map * map, struct vertex_array * array, struct face_item * root, void * a1, void * a2)
+{
+ map_free (map);
+ if (array->vertices != NULL) { free (array->vertices); }
+ face_free (root);
+ if (a1 != NULL) { free (a1); }
+ if (a2 != NULL) { free (a2); }
+}
+
+int
+icosphere (unsigned int nb_iterations, float scale,
+ unsigned int ** mesh_indices, unsigned int * count_indices,
+ float ** mesh_vertices, unsigned int * count_vertices)
+{
+ struct face_item * root;
+ struct face_item * f;
+ unsigned int nb_faces;
+ struct map map;
+ struct vertex_array v;
+
+ unsigned int i;
+ unsigned int j;
+
+ map_init (&map);
+
+ *mesh_vertices = NULL;
+ *mesh_indices = NULL;
+ nb_faces = 20;
+ v.nb_vertices = 12;
+ v.buffer = v.nb_vertices * sizeof (vec3);
+ v.vertices = malloc (v.buffer);
+ if (v.vertices == NULL) { return 1; }
+
+ root = first_iteration (&v);
+
+ for (i = 1; i < nb_iterations; i++)
+ {
+ struct face_item * face = root;
+ while (face != NULL)
+ {
+ int a = middle_point (&map, &v, face->v[0], face->v[1]);
+ int b = middle_point (&map, &v, face->v[1], face->v[2]);
+ int c = middle_point (&map, &v, face->v[2], face->v[0]);
+ struct face_item * tmp;
+
+ if (a == -1 || b == -1 || c == -1)
+ {
+ free_all (&map, &v, root, *mesh_vertices, *mesh_indices);
+ *count_vertices = 0;
+ *count_indices = 0;
+ return 1;
+ }
+
+ tmp = face->next;
+ root = face_rm (root, face);
+ root = face_add (root, face->v[0], a, c);
+ root = face_add (root, face->v[1], b, a);
+ root = face_add (root, face->v[2], c, b);
+ root = face_add (root, a, b, c);
+ free (face);
+
+ nb_faces += 3;
+
+ face = tmp;
+ }
+ }
+
+ (*mesh_indices) = malloc (nb_faces * sizeof (unsigned int) * 3);
+ (*mesh_vertices) = malloc (v.nb_vertices * sizeof (float) * 3);
+
+ if (*mesh_indices == NULL || *mesh_vertices == NULL)
+ {
+ free_all (&map, &v, root, *mesh_vertices, *mesh_indices);
+ *count_vertices = 0;
+ *count_indices = 0;
+ return 1;
+ }
+
+ for (f = root, i = 0; f != NULL; i += 3)
+ {
+ (*mesh_indices)[i] = f->v[0];
+ (*mesh_indices)[i+1] = f->v[1];
+ (*mesh_indices)[i+2] = f->v[2];
+ f = f->next;
+ }
+ for (j = 0, i = 0; i < v.nb_vertices; i++, j += 3)
+ {
+ (*mesh_vertices)[j] = v.vertices[i].x * scale;
+ (*mesh_vertices)[j+1] = v.vertices[i].y * scale;
+ (*mesh_vertices)[j+2] = v.vertices[i].z * scale;
+ }
+
+ *count_vertices = v.nb_vertices;
+ *count_indices = nb_faces * 3;
+
+ free_all (&map, &v, root, NULL, NULL);
+ return 0;
+}
+
diff --git a/sweet_geometry.h b/sweet_geometry.h
new file mode 100644
index 0000000..fd091ee
--- /dev/null
+++ b/sweet_geometry.h
@@ -0,0 +1,8 @@
+#ifndef SWEET_GEOMETRY_H
+#define SWEET_GEOMETRY_H
+
+int icosphere (unsigned int nb_iterations, float scale,
+ unsigned int ** mesh_indices, unsigned int * count_indices,
+ float ** mesh_vertices, unsigned int * count_vertices);
+#endif
+