/* * 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 sweet_geometry_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; }