Created
January 5, 2023 22:59
-
-
Save Leowbattle/d4fcf4d0fb3bdf9e4968e1d3c914b1a2 to your computer and use it in GitHub Desktop.
Code to generate an icosphere in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <math.h> | |
void* xmalloc(size_t size) { | |
void* ptr = malloc(size); | |
if (ptr == NULL) { | |
fprintf(stderr, "Failed to allocate %ld bytes\n", size); | |
exit(EXIT_FAILURE); | |
} | |
return ptr; | |
} | |
void* xrealloc(void* ptr, size_t size) { | |
void* p2 = realloc(ptr, size); | |
if (p2 == NULL) { | |
fprintf(stderr, "Failed to allocate %ld bytes\n", size); | |
exit(EXIT_FAILURE); | |
} | |
return p2; | |
} | |
typedef struct vec3 { | |
float x; | |
float y; | |
float z; | |
} vec3; | |
typedef struct Face { | |
int indices[3]; | |
} Face; | |
typedef struct Mesh { | |
vec3* vertices; | |
size_t num_vertices; | |
Face* faces; | |
size_t num_faces; | |
} Mesh; | |
void Mesh_init(Mesh* m, const vec3* vertices, size_t num_vertices, const Face* faces, size_t num_faces) { | |
m->vertices = xmalloc(num_vertices * sizeof(vec3)); | |
memcpy(m->vertices, vertices, num_vertices * sizeof(vec3)); | |
m->num_vertices = num_vertices; | |
m->faces = xmalloc(num_faces * sizeof(Face)); | |
memcpy(m->faces, faces, num_faces * sizeof(Face)); | |
m->num_faces = num_faces; | |
} | |
void Mesh_init_icosahedron(Mesh* m) { | |
#define PHI 1.61803398875f | |
static const vec3 vertices[] = { | |
{PHI, 1, 0}, | |
{PHI, -1, 0}, | |
{-PHI, -1, 0}, | |
{-PHI, 1, 0}, | |
{1, 0, PHI}, | |
{-1, 0, PHI}, | |
{-1, 0, -PHI}, | |
{1, 0, -PHI}, | |
{0, PHI, 1}, | |
{0, PHI, -1}, | |
{0, -PHI, -1}, | |
{0, -PHI, 1}, | |
}; | |
static const Face faces[] = { | |
{0, 8, 4}, | |
{0, 4, 1}, | |
{0, 1, 7}, | |
{0, 7, 9}, | |
{0, 9, 8}, | |
{8, 4, 5}, | |
{4, 1, 11}, | |
{1, 7, 10}, | |
{7, 9, 6}, | |
{9, 8, 3}, | |
{3, 5, 8}, | |
{5, 11, 4}, | |
{11, 10, 1}, | |
{10, 6, 7}, | |
{6, 3, 9}, | |
{2, 3, 5}, | |
{2, 5, 11}, | |
{2, 11, 10}, | |
{2, 10, 6}, | |
{2, 6, 3}, | |
}; | |
Mesh_init(m, vertices, 12, faces, 20); | |
} | |
void Mesh_loop_subdivide(Mesh* m) { | |
size_t vertex_i = m->num_vertices; | |
size_t face_i = 0; | |
size_t num_faces = m->num_faces; | |
m->num_vertices = m->num_vertices + m->num_faces * 3; | |
m->vertices = xrealloc(m->vertices, m->num_vertices * sizeof(vec3)); | |
Face* newFaces = xmalloc(num_faces * 4 * sizeof(Face)); | |
for (int i = 0; i < num_faces; i++) { | |
const Face* f = &m->faces[i]; | |
vec3 v0 = m->vertices[f->indices[0]]; | |
vec3 v1 = m->vertices[f->indices[1]]; | |
vec3 v2 = m->vertices[f->indices[2]]; | |
size_t n = vertex_i; | |
m->vertices[vertex_i++] = (vec3){(v0.x + v1.x) / 2, (v0.y + v1.y) / 2, (v0.z + v1.z) / 2}; | |
m->vertices[vertex_i++] = (vec3){(v1.x + v2.x) / 2, (v1.y + v2.y) / 2, (v1.z + v2.z) / 2}; | |
m->vertices[vertex_i++] = (vec3){(v2.x + v0.x) / 2, (v2.y + v0.y) / 2, (v2.z + v0.z) / 2}; | |
newFaces[face_i++] = (Face){f->indices[0], n, n + 2}; | |
newFaces[face_i++] = (Face){n, f->indices[1], n + 1}; | |
newFaces[face_i++] = (Face){n + 2, n + 1, f->indices[2]}; | |
newFaces[face_i++] = (Face){n, n + 1, n + 2}; | |
} | |
free(m->faces); | |
m->faces = newFaces; | |
m->num_faces *= 4; | |
} | |
void Mesh_normalize(Mesh* m) { | |
for (int i = 0; i < m->num_vertices; i++) { | |
vec3* v = &m->vertices[i]; | |
float norm = sqrtf(v->x * v->x + v->y * v->y + v->z * v->z); | |
v->x /= norm; | |
v->y /= norm; | |
v->z /= norm; | |
} | |
} | |
int main(int argc, char** argv) { | |
Mesh mesh; | |
Mesh_init_icosahedron(&mesh); | |
int n = 4; | |
for (int i = 0; i < n; i++) { | |
Mesh_loop_subdivide(&mesh); | |
} | |
Mesh_normalize(&mesh); | |
for (int i = 0; i < mesh.num_vertices; i++) { | |
const vec3* v = &mesh.vertices[i]; | |
printf("v %f %f %f\n", v->x, v->y, v->z); | |
} | |
for (int i = 0; i < mesh.num_faces; i++) { | |
const Face* f = &mesh.faces[i]; | |
printf("f %d %d %d\n", f->indices[0] + 1, f->indices[1] + 1, f->indices[2] + 1); | |
} | |
free(mesh.vertices); | |
free(mesh.faces); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment