/* * 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 a; unsigned int b; 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, unsigned int a, unsigned int b) { unsigned int tmp; struct item * item; tmp = a; a = tmp > b ? tmp : b; b = tmp > b ? b : tmp; item = map->items[hash % MAP_SIZE]; while (item != NULL && item->a != a && item->b != b) { item = item->next; } return item; } static int map_add_item (struct map * map, unsigned int hash, unsigned int a, unsigned int b, int id) { struct item * next; struct item * item; if (map_get_item (map, hash, a, b) != NULL) { return 0; } next = map->items[hash % MAP_SIZE]; item = malloc (sizeof (struct item)); if (item == NULL) { return -1; } item->a = a > b ? a : b; item->b = a < b ? a : b; 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; }; struct tcoord_array { vec2 * uv; size_t buffer; unsigned int nb_uv; }; /* Utils */ 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 middle; hash = hash_2_int (a, b); item = map_get_item (map, hash, a, b); id = v->nb_vertices; if (item != NULL) { *state = 0; return item->id; } if (map_add_item (map, hash, a, b, id) == -1) { *state = -1; return 0; } *state = 1; middle = sweet_vector_middle3 (v->vertices[a], v->vertices[b]); v->vertices[v->nb_vertices++] = sweet_vector_normalize3 (middle); return id; } 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, unsigned int nb_indices, unsigned int * indices, unsigned int nb_vertices, float * vertices) { struct face_item * root; 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 (sweet_vector_new3 (vertices[j], vertices[j+1], vertices[j+2])); } 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 * v, struct tcoord_array * t, struct face_item * root, void * a1, void * a2, void * a3) { map_free (map); 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_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; unsigned int nb_faces; struct map map; struct vertex_array v; struct tcoord_array t; unsigned int i; unsigned int j; 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; } 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 (t.nb_uv * sizeof (float) * 2); if ((*mesh_indices) == NULL || (*mesh_vertices) == NULL || (*mesh_tcoord) == NULL) { 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, NULL, NULL, NULL); (*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, NULL, root, *mesh_vertices, *mesh_indices, NULL); return 0; } copy_indices (*mesh_indices, root); copy_vertices (*mesh_vertices, &v, scale); free_all (&map, &v, NULL, root, NULL, NULL, NULL); (*count_indices) = nb_faces * 3; (*count_vertices) = v.nb_vertices; return nb_faces; } /* Icosphere */ #define NB_INDICES 60 #define NB_VERTICES 12 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[NB_INDICES] = { 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 }; 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, icosphere_vertices_v, count_indices, mesh_indices, count_vertices, mesh_vertices); } #undef NB_INDICES #undef NB_VERTICES #define NB_INDICES 36 #define NB_VERTICES 8 static float cube_vertices_v[24] = { -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5 }; static unsigned int cube_indices_v[NB_INDICES] = { 2, 3, 0, 0, 1, 2, 4, 7, 6, 6, 5, 4, 0, 3, 7, 7, 4, 0, 6, 2, 1, 1, 5, 6, 0, 4, 1, 1, 4, 5, 3, 2, 6, 6, 7, 3 }; int sweet_geometry_cube (float scale, unsigned int * count_indices, unsigned int ** mesh_indices, unsigned int * count_vertices, float ** mesh_vertices) { int i; *mesh_vertices = NULL; *mesh_indices = NULL; *count_indices = NB_INDICES; *count_vertices = NB_VERTICES; *mesh_vertices = malloc (NB_VERTICES * 3 * sizeof (float)); if (*mesh_vertices == NULL) { return 0; } *mesh_indices = malloc (NB_INDICES * sizeof (unsigned int)); if (*mesh_indices == NULL) { return 0; } for (i = 0; i < NB_VERTICES * 3; i++) { (*mesh_vertices)[i] = cube_vertices_v[i] * scale; } for (i = 0; i < NB_INDICES; i++) { (*mesh_indices)[i] = cube_indices_v[i]; } return 6; }