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 +