Skip to content

Instantly share code, notes, and snippets.

@Leowbattle
Created January 5, 2023 22:59
Show Gist options
  • Save Leowbattle/d4fcf4d0fb3bdf9e4968e1d3c914b1a2 to your computer and use it in GitHub Desktop.
Save Leowbattle/d4fcf4d0fb3bdf9e4968e1d3c914b1a2 to your computer and use it in GitHub Desktop.
Code to generate an icosphere in C
#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