diff --git a/exemple/exemple_geometry.c b/exemple/exemple_geometry.c new file mode 100644 index 0000000..74609e7 --- /dev/null +++ b/exemple/exemple_geometry.c @@ -0,0 +1,25 @@ +#include +#include +#include "sweet.h" + +#define SCALE 1.5 +#define NB_ITERATIONS 3 + +int +main () +{ + unsigned int nb_faces; + unsigned int nb_elements; + unsigned int nb_vertices; + float * vertices; + unsigned int * indices; + nb_faces = sweet_geometry_icosphere (NB_ITERATIONS, SCALE, &nb_elements, &indices, &nb_vertices, &vertices); + + printf ("There are %d faces\n", nb_faces); + + free (vertices); + free (indices); + + return 0; +} + diff --git a/sweet_geometry.c b/sweet_geometry.c index 15b7eee..a1cdd96 100644 --- a/sweet_geometry.c +++ b/sweet_geometry.c @@ -17,7 +17,7 @@ */ #include -#include +#include #include "sweet_types.h" #include "sweet_math.h" @@ -93,7 +93,6 @@ face_free (struct face_item * root) } - /* Definition of map */ struct item @@ -173,6 +172,7 @@ 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 @@ -182,198 +182,344 @@ struct vertex_array 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} +struct tcoord_array +{ + vec2 * uv; + size_t buffer; + unsigned int nb_uv; }; + /* Utils */ -static int -middle_point (struct map * map, - struct vertex_array * v, - unsigned int a, unsigned int b) +static unsigned int +middle_point_v (struct map * map, int * state, + 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; } + if (item != NULL) { *state = 0; return item->id; } - v1 = v->vertices[a]; - v2 = v->vertices[b]; - middle = sweet_vector_middle3 (v1, v2); + if (map_add_item (map, hash, id) == -1) { *state = -1; return 0; } + + *state = 1; + middle = sweet_vector_middle3 (v->vertices[a], v->vertices[b]); - 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); + return id; +} - if (map_add_item (map, hash, id) == -1) { return -1; } +static unsigned int +middle_point_vt (struct map * map, int * state, + struct vertex_array * v, struct tcoord_array * t, + unsigned int a, unsigned int b) +{ + unsigned int id = middle_point_v (map, state, v, a, b); + + if (*state == 1) + { + t->uv[t->nb_uv++] = sweet_vector_middle2 (t->uv[a], t->uv[b]); + } return id; } static struct face_item * -first_iteration (struct vertex_array * v) +first_iteration (struct vertex_array * v, + unsigned int nb_indices, unsigned int * indices, + unsigned int nb_vertices, float * vertices) { struct face_item * root; - int i; - for (i = 0; i < v->nb_vertices; i++) + unsigned int i; + unsigned int j; + + v->nb_vertices = nb_vertices; + for (i = 0, j = 0; i < v->nb_vertices; i++, j += 3) { - v->vertices[i] = sweet_vector_normalize3 (base_vertices[i]); + v->vertices[i] = sweet_vector_normalize3 (sweet_vector_new3 (vertices[j], vertices[j+1], vertices[j+2])); } - 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); + root = NULL; + for (i = 0; i < nb_indices; i += 3) + { + root = face_add (root, indices[i], indices[i+1], indices[i+2]); + } return root; } +static struct face_item * +first_iteration_vt (struct vertex_array * v, struct tcoord_array * t, + unsigned int nb_indices, unsigned int * indices, + unsigned int nb_vertices, float * vertices, float * tcoord) +{ + unsigned int i; + unsigned int j; + + t->nb_uv = nb_vertices; + for (i = 0, j = 0; i < t->nb_uv; i++, j += 2) + { + t->uv[i] = sweet_vector_new2 (tcoord[j], tcoord[j+1]); + } + + return first_iteration (v, nb_indices, indices, nb_vertices, vertices); +} + static void -free_all (struct map * map, struct vertex_array * array, struct face_item * root, void * a1, void * a2) +free_all (struct map * map, struct vertex_array * v, struct tcoord_array * t, struct face_item * root, void * a1, void * a2, void * a3) { map_free (map); - if (array->vertices != NULL) { free (array->vertices); } + if (v != NULL && v->vertices != NULL) { free (v->vertices); } + if (t != NULL && t->uv != NULL) { free (t->uv); } face_free (root); if (a1 != NULL) { free (a1); } if (a2 != NULL) { free (a2); } + if (a3 != NULL) { free (a3); } +} + +static void +copy_indices (unsigned int * mesh_indices, struct face_item * root) +{ + unsigned int i; + struct face_item * f; + 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; + } +} + +static void +copy_vertices (float * mesh_vertices, struct vertex_array * v, float scale) +{ + unsigned int i; + unsigned int j; + for (i = 0, j = 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; + } +} + +static struct face_item * +iterate (struct map * map, struct vertex_array * v, struct tcoord_array * t, struct face_item * root, + unsigned int * nb_faces, unsigned int nb_iterations) +{ + unsigned int i; + for (i = 0; i < nb_iterations; i++) + { + struct face_item * face = root; + while (face != NULL) + { + int r1; + int r2; + int r3; + unsigned int a; + unsigned int b; + unsigned int c; + + if (t != NULL) + { + a = middle_point_vt (map, &r1, v, t, face->v[0], face->v[1]); + b = middle_point_vt (map, &r2, v, t, face->v[1], face->v[2]); + c = middle_point_vt (map, &r3, v, t, face->v[2], face->v[0]); + } + else + { + a = middle_point_v (map, &r1, v, face->v[0], face->v[1]); + b = middle_point_v (map, &r2, v, face->v[1], face->v[2]); + c = middle_point_v (map, &r3, v, face->v[2], face->v[0]); + } + + if (r1 == -1 || r2 == -1 || r3 == -1) + { + free_all (map, v, t, root, NULL, NULL, NULL); + return 0; + } + + r1 = face->v[1]; + r2 = face->v[2]; + face->v[1] = a; + face->v[2] = c; + + root = face_add (root, r1, b, a); + root = face_add (root, r2, c, b); + root = face_add (root, a, b, c); + + *nb_faces += 3; + + face = face->next; + } + } + return root; } 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) +sweet_geometry_subdivide_mesh_vt (unsigned int nb_iterations, float scale, + unsigned int nb_indices, unsigned int * indices, + unsigned int nb_vertices, float * vcoord, float * tcoord, + unsigned int * count_indices, unsigned int ** mesh_indices, + unsigned int * count_vertices, float ** mesh_vertices, float ** mesh_tcoord) { struct face_item * root; - struct face_item * f; unsigned int nb_faces; struct map map; struct vertex_array v; + struct tcoord_array t; unsigned int i; unsigned int j; map_init (&map); - *mesh_vertices = NULL; - *mesh_indices = NULL; + *count_vertices = 0; + *count_indices = 0; + nb_faces = nb_indices / 3; - nb_faces = 20; - v.nb_vertices = 12; - v.buffer = v.nb_vertices * sizeof (vec3); + v.buffer = nb_vertices * sizeof (vec3) * pow (4, nb_iterations); v.vertices = malloc (v.buffer); - if (v.vertices == NULL) { return 1; } + if (v.vertices == NULL) { return 0; } - root = first_iteration (&v); - - for (i = 1; i < nb_iterations; i++) + t.buffer = nb_vertices * sizeof (vec2) * pow (4, nb_iterations); + t.uv = malloc (t.buffer); + if (t.uv == NULL) { free (v.vertices); return 0; } + + root = first_iteration_vt (&v, &t, nb_indices, indices, nb_vertices, vcoord, tcoord); + root = iterate (&map, &v, &t, root, &nb_faces, nb_iterations); + + (*mesh_indices) = malloc (nb_faces * 3 * sizeof (unsigned int)); + (*mesh_vertices) = malloc (v.nb_vertices * sizeof (float) * 3); + (*mesh_tcoord) = malloc ((*count_vertices) * sizeof (float) * 2); + + if ((*mesh_indices) == NULL || (*mesh_vertices) == NULL || (*mesh_tcoord) == NULL) { - 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; - } + free_all (&map, &v, &t, root, *mesh_vertices, *mesh_indices, *mesh_tcoord); + return 0; } + + copy_indices (*mesh_indices, root); + copy_vertices (*mesh_vertices, &v, scale); + + for (i = 0, j = 0; i < v.nb_vertices; i++, j += 2) + { + (*mesh_tcoord)[j] = t.uv[i].x; + (*mesh_tcoord)[j+1] = t.uv[i].y; + } + + free_all (&map, &v, &t, root, *mesh_vertices, *mesh_indices, *mesh_tcoord); - (*mesh_indices) = malloc (nb_faces * sizeof (unsigned int) * 3); + (*count_indices) = nb_faces * 3; + (*count_vertices) = v.nb_vertices; + return nb_faces; +} + +int +sweet_geometry_subdivide_mesh_v (unsigned int nb_iterations, float scale, + unsigned int nb_indices, unsigned int * indices, + unsigned int nb_vertices, float * vcoord, + unsigned int * count_indices, unsigned int ** mesh_indices, + unsigned int * count_vertices, float ** mesh_vertices) +{ + struct face_item * root; + unsigned int nb_faces; + struct map map; + struct vertex_array v; + + map_init (&map); + *count_vertices = 0; + *count_indices = 0; + nb_faces = nb_indices / 3; + + v.buffer = nb_vertices * sizeof (vec3) * pow (4, nb_iterations); + v.vertices = malloc (v.buffer); + if (v.vertices == NULL) { return 0; } + + root = first_iteration (&v, nb_indices, indices, nb_vertices, vcoord); + + root = iterate (&map, &v, NULL, root, &nb_faces, nb_iterations); + + (*mesh_indices) = malloc (nb_faces * 3 * sizeof (unsigned int)); (*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; + free_all (&map, &v, NULL, root, *mesh_vertices, *mesh_indices, NULL); + return 0; } - 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; + copy_indices (*mesh_indices, root); + copy_vertices (*mesh_vertices, &v, scale); - free_all (&map, &v, root, NULL, NULL); - return 0; + free_all (&map, &v, NULL, root, NULL, NULL, NULL); + + (*count_indices) = nb_faces * 3; + (*count_vertices) = v.nb_vertices; + + return nb_faces; +} + +/* Icosphere */ +static float icosphere_vertices_v[36] = { + -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 +}; + +static unsigned int icosphere_indices_v[60] = { + 0, 11, 5, + 0, 5, 1, + 0, 1, 7, + 0, 7, 10, + 0, 10, 11, + + 1, 5, 9, + 5, 11, 4, + 11, 10, 2, + 10, 7, 6, + 7, 1, 8, + + 3, 9, 4, + 3, 4, 2, + 3, 2, 6, + 3, 6, 8, + 3, 8, 9, + + 4, 9, 5, + 2, 4, 11, + 6, 2, 10, + 8, 6, 7, + 9, 8, 1 +}; + +static unsigned int nb_indices = 60; +static unsigned int nb_vertices_v = 12; + +int +sweet_geometry_icosphere (unsigned int nb_iterations, float scale, + unsigned int * count_indices, unsigned int ** mesh_indices, + unsigned int * count_vertices, float ** mesh_vertices) +{ + return sweet_geometry_subdivide_mesh_v (nb_iterations, scale, + nb_indices, icosphere_indices_v, nb_vertices_v, icosphere_vertices_v, + count_indices, mesh_indices, count_vertices, mesh_vertices); } diff --git a/sweet_geometry.h b/sweet_geometry.h index 69849ef..6d63031 100644 --- a/sweet_geometry.h +++ b/sweet_geometry.h @@ -1,8 +1,40 @@ +/* + * 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 . + */ + #ifndef SWEET_GEOMETRY_H #define SWEET_GEOMETRY_H + +int sweet_geometry_subdivide_mesh_v (unsigned int nb_iterations, float scale, + unsigned int nb_indices, unsigned int * indices, + unsigned int nb_vertices, float * vcoord, + unsigned int * count_indices, unsigned int ** mesh_indices, + unsigned int * count_vertices, float ** mesh_vertices); + +int sweet_geometry_subdivide_mesh_vt (unsigned int nb_iterations, float scale, + unsigned int nb_indices, unsigned int * indices, + unsigned int nb_vertices, float * vcoord, float * tcoord, + unsigned int * count_indices, unsigned int ** mesh_indices, + unsigned int * count_vertices, float ** mesh_vertices, float ** mesh_tcoord); + 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); + unsigned int * count_indices, unsigned int ** mesh_indices, + unsigned int * count_vertices, float ** mesh_vertices); + #endif