#include "defines.h" #include #ifndef MINIMAL_PLAYER static void push_face(Universe *uni, Object3D *obj, int a, int b, int c, uint8_t wire) { Face *f = &uni->faces[uni->num_faces++]; f->a = a; f->b = b; f->c = c; f->force_wire = wire; obj->num_faces++; } static Object3D *alloc_object(Universe *uni) { Object3D *obj = &uni->objects[uni->num_objects++]; obj->vert_start = uni->num_verts; obj->face_start = uni->num_faces; obj->num_verts = 0; obj->num_faces = 0; obj->pos.x = obj->pos.y = obj->pos.z = 0; obj->base_pos.x = obj->base_pos.y = obj->base_pos.z = 0; mat3_identity(&obj->rot); return obj; } /* Déplacement absolu : fixe la position de l'objet dans l'espace de l'orbite */ void set_object_pos(Object3D *obj, fixed x, fixed y, fixed z) { if (!obj) return; obj->base_pos.x = x; obj->base_pos.y = y; obj->base_pos.z = z; } /* Déplacement relatif : ajoute un décalage à la position actuelle */ void move_object(Object3D *obj, fixed dx, fixed dy, fixed dz) { if (!obj) return; obj->base_pos.x += dx; obj->base_pos.y += dy; obj->base_pos.z += dz; } /* Changement de couleur */ void set_object_color(Object3D *obj, uint8_t col) { if (!obj) return; obj->color = col; } Object3D *add_box(Universe *uni, fixed x, fixed y, fixed z, fixed dx, fixed dy, fixed dz, uint8_t col, uint8_t wire) { int i, j, v_base; Object3D *obj; fixed hx = dx / 2, hy = dy / 2, hz = dz / 2; /* Normales des 6 faces : +Z, -Z, +Y, -Y, +X, -X */ fixed nx[6] = {0, 0, 0, 0, int_to_f(1), -int_to_f(1)}; fixed ny[6] = {0, 0, int_to_f(1), -int_to_f(1), 0, 0}; fixed nz[6] = {int_to_f(1), -int_to_f(1), 0, 0, 0, 0}; /* Configuration des sommets pour respecter le "face culling" (sens trigo) */ /* int sx[24] = {-1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1}; int sy[24] = {-1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1}; int sz[24] = { 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1}; */ /* Ordre CCW rigoureux pour que le "back-face culling" affiche les 6 faces */ int sx[24] = { -1, 1, 1, -1, /* Face +Z (Avant) */ 1, -1, -1, 1, /* Face -Z (Arrière) */ -1, 1, 1, -1, /* Face +Y (Haut) */ -1, 1, 1, -1, /* Face -Y (Bas) */ 1, 1, 1, 1, /* Face +X (Droite) */ -1, -1, -1, -1 /* Face -X (Gauche) */ }; int sy[24] = { -1, -1, 1, 1, /* Face +Z */ -1, -1, 1, 1, /* Face -Z */ 1, 1, 1, 1, /* Face +Y */ -1, -1, -1, -1, /* Face -Y */ -1, -1, 1, 1, /* Face +X */ -1, -1, 1, 1 /* Face -X */ }; int sz[24] = { 1, 1, 1, 1, /* Face +Z */ -1, -1, -1, -1, /* Face -Z */ 1, 1, -1, -1, /* Face +Y */ -1, -1, 1, 1, /* Face -Y */ 1, -1, -1, 1, /* Face +X */ -1, 1, 1, -1 /* Face -X */ }; if (uni->num_objects >= MAX_OBJECTS) return NULL; if (uni->num_verts + 24 > MAX_VERTEX) return NULL; if (uni->num_faces + 12 > MAX_FACES) return NULL; obj = alloc_object(uni); obj->color = col; v_base = uni->num_verts; for (i = 0; i < 6; i++) { for(j = 0; j < 4; j++) { int idx = i * 4 + j; uni->v_normals[uni->num_verts].x = nx[i]; uni->v_normals[uni->num_verts].y = ny[i]; uni->v_normals[uni->num_verts].z = nz[i]; uni->verts[uni->num_verts].x = x + (sx[idx] > 0 ? hx : -hx); uni->verts[uni->num_verts].y = y + (sy[idx] > 0 ? hy : -hy); uni->verts[uni->num_verts].z = z + (sz[idx] > 0 ? hz : -hz); uni->num_verts++; obj->num_verts++; } /* Deux triangles par face */ push_face(uni, obj, v_base + i * 4, v_base + i * 4 + 1, v_base + i * 4 + 2, wire); push_face(uni, obj, v_base + i * 4, v_base + i * 4 + 2, v_base + i * 4 + 3, wire); } return obj; } Object3D *add_sphere(Universe *uni, fixed x, fixed y, fixed z, fixed r, int det, uint8_t col, uint8_t wire) { int i, j, v_base, phi, th; Object3D *obj; Vector3 *v, *n; if (uni->num_objects >= MAX_OBJECTS) return NULL; if (uni->num_verts + (det + 1) * det > MAX_VERTEX) return NULL; if (uni->num_faces + det * det * 2 > MAX_FACES) return NULL; obj = alloc_object(uni); obj->color = col; v_base = uni->num_verts; for (j = 0; j <= det; j++) { phi = (j * 180 / det) % 360; for (i = 0; i < det; i++) { th = (i * 360 / det) % 360; v = &uni->verts[uni->num_verts]; n = &uni->v_normals[uni->num_verts]; n->x = f_mul(sintab[phi], costab[th]); n->y = costab[phi]; n->z = f_mul(sintab[phi], sintab[th]); v->x = x + f_mul(r, n->x); v->y = y + f_mul(r, n->y); v->z = z + f_mul(r, n->z); uni->num_verts++; obj->num_verts++; } } for (j = 0; j < det; j++) { for (i = 0; i < det; i++) { int a = v_base + j * det + i; int b = v_base + j * det + (i + 1) % det; int c = v_base + (j + 1) * det + i; int d = v_base + (j + 1) * det + (i + 1) % det; push_face(uni, obj, a, b, c, wire); push_face(uni, obj, b, d, c, wire); } } return obj; } Object3D *add_cone(Universe *uni, fixed x, fixed y, fixed z, fixed r, fixed h, int det, uint8_t col, uint8_t wire) { int i, v_base, cap_bot_center, cap_bot_rim, th; fixed half_h, s, cs; Object3D *obj; if (uni->num_objects >= MAX_OBJECTS) return NULL; if (uni->num_verts + 1 + 3 * det > MAX_VERTEX) return NULL; if (uni->num_faces + 2 * det > MAX_FACES) return NULL; obj = alloc_object(uni); obj->color = col; v_base = uni->num_verts; half_h = h / 2; /* --- Corps --- */ for (i = 0; i < det; i++) { th = (i * 360 / det) % 360; s = sintab[th]; cs = costab[th]; /* Base du corps */ uni->v_normals[uni->num_verts].x = cs; uni->v_normals[uni->num_verts].y = 0; uni->v_normals[uni->num_verts].z = s; uni->verts[uni->num_verts].x = x + f_mul(r, cs); uni->verts[uni->num_verts].y = y - half_h; uni->verts[uni->num_verts].z = z + f_mul(r, s); uni->num_verts++; obj->num_verts++; /* Pointe du corps (dupliquée par face pour préserver les normales) */ uni->v_normals[uni->num_verts].x = cs; uni->v_normals[uni->num_verts].y = 0; uni->v_normals[uni->num_verts].z = s; uni->verts[uni->num_verts].x = x; uni->verts[uni->num_verts].y = y + half_h; uni->verts[uni->num_verts].z = z; uni->num_verts++; obj->num_verts++; } for (i = 0; i < det; i++) { int a = v_base + (i * 2); int b = v_base + ((i * 2 + 2) % (det * 2)); int cv = a + 1; push_face(uni, obj, a, cv, b, wire); } /* --- Fond bas --- */ cap_bot_center = uni->num_verts; uni->v_normals[uni->num_verts].x = 0; uni->v_normals[uni->num_verts].y = -int_to_f(1); uni->v_normals[uni->num_verts].z = 0; uni->verts[uni->num_verts].x = x; uni->verts[uni->num_verts].y = y - half_h; uni->verts[uni->num_verts].z = z; uni->num_verts++; obj->num_verts++; cap_bot_rim = uni->num_verts; for (i = 0; i < det; i++) { th = (i * 360 / det) % 360; s = sintab[th]; cs = costab[th]; uni->v_normals[uni->num_verts].x = 0; uni->v_normals[uni->num_verts].y = -int_to_f(1); uni->v_normals[uni->num_verts].z = 0; uni->verts[uni->num_verts].x = x + f_mul(r, cs); uni->verts[uni->num_verts].y = y - half_h; uni->verts[uni->num_verts].z = z + f_mul(r, s); uni->num_verts++; obj->num_verts++; } for (i = 0; i < det; i++) push_face(uni, obj, cap_bot_center, cap_bot_rim + i, cap_bot_rim + (i + 1) % det, wire); return obj; } Object3D *add_plane(Universe *uni, fixed x, fixed y, fixed z, fixed w, fixed d, int seg_x, int seg_z, uint8_t col, uint8_t wire) { int i, j, v_base; Object3D *obj; fixed h_w = w / 2, h_d = d / 2; fixed step_x, step_z; if (seg_x < 1) seg_x = 1; if (seg_z < 1) seg_z = 1; if (uni->num_objects >= MAX_OBJECTS) return NULL; if (uni->num_verts + (seg_x + 1) * (seg_z + 1) > MAX_VERTEX) return NULL; if (uni->num_faces + seg_x * seg_z * 2 > MAX_FACES) return NULL; obj = alloc_object(uni); obj->color = col; v_base = uni->num_verts; step_x = w / seg_x; step_z = d / seg_z; for (j = 0; j <= seg_z; j++) { for (i = 0; i <= seg_x; i++) { uni->v_normals[uni->num_verts].x = 0; uni->v_normals[uni->num_verts].y = int_to_f(1); uni->v_normals[uni->num_verts].z = 0; uni->verts[uni->num_verts].x = x - h_w + i * step_x; uni->verts[uni->num_verts].y = y; uni->verts[uni->num_verts].z = z - h_d + j * step_z; uni->num_verts++; obj->num_verts++; } } for (j = 0; j < seg_z; j++) { for (i = 0; i < seg_x; i++) { int a = v_base + j * (seg_x + 1) + i; int b = a + 1; int c = v_base + (j + 1) * (seg_x + 1) + i; int d_idx = c + 1; /* Triangulation (a,c,b) et (b,c,d_idx) pour garantir une normale face +Y */ push_face(uni, obj, a, c, b, wire); push_face(uni, obj, b, c, d_idx, wire); } } return obj; } Object3D *add_math_surface(Universe *uni, fixed x, fixed y, fixed z, fixed w, fixed d, int seg_x, int seg_z, uint8_t col, uint8_t wire, SurfaceFunc func) { int i, j, v_base; Object3D *obj; fixed h_w = w / 2, h_d = d / 2; fixed step_x, step_z; if (seg_x < 1) seg_x = 1; if (seg_z < 1) seg_z = 1; if (uni->num_objects >= MAX_OBJECTS) return NULL; if (uni->num_verts + (seg_x + 1) * (seg_z + 1) > MAX_VERTEX) return NULL; if (uni->num_faces + seg_x * seg_z * 2 > MAX_FACES) return NULL; obj = alloc_object(uni); obj->color = col; v_base = uni->num_verts; step_x = w / seg_x; step_z = d / seg_z; for (j = 0; j <= seg_z; j++) { for (i = 0; i <= seg_x; i++) { fixed vx = x - h_w + i * step_x; fixed vz = z - h_d + j * step_z; uni->verts[uni->num_verts].x = vx; /* Appel de la fonction passée en paramètre pour obtenir la hauteur */ uni->verts[uni->num_verts].y = y + func(vx, vz); uni->verts[uni->num_verts].z = vz; uni->v_normals[uni->num_verts].x = 0; uni->v_normals[uni->num_verts].y = int_to_f(1); uni->v_normals[uni->num_verts].z = 0; uni->num_verts++; obj->num_verts++; } } for (j = 0; j < seg_z; j++) { for (i = 0; i < seg_x; i++) { int a = v_base + j * (seg_x + 1) + i; int b = a + 1; int c = v_base + (j + 1) * (seg_x + 1) + i; push_face(uni, obj, a, c, b, wire); push_face(uni, obj, b, c, c + 1, wire); } } return obj; } Object3D *add_torus(Universe *uni, fixed x, fixed y, fixed z, fixed r_main, fixed r_tube, int seg_main, int seg_tube, uint8_t col, uint8_t wire) { int i, j, v_base; Object3D *obj; if (uni->num_objects >= MAX_OBJECTS) return NULL; if (uni->num_verts + seg_main * seg_tube > MAX_VERTEX) return NULL; if (uni->num_faces + seg_main * seg_tube * 2 > MAX_FACES) return NULL; obj = alloc_object(uni); obj->color = col; v_base = uni->num_verts; for (i = 0; i < seg_main; i++) { int th_main = (i * 360 / seg_main) % 360; fixed cos_u = costab[th_main]; fixed sin_u = sintab[th_main]; for (j = 0; j < seg_tube; j++) { int th_tube = (j * 360 / seg_tube) % 360; fixed cos_v = costab[th_tube]; fixed sin_v = sintab[th_tube]; fixed dist = r_main + f_mul(r_tube, cos_v); uni->v_normals[uni->num_verts].x = f_mul(cos_v, cos_u); uni->v_normals[uni->num_verts].y = sin_v; uni->v_normals[uni->num_verts].z = f_mul(cos_v, sin_u); uni->verts[uni->num_verts].x = x + f_mul(dist, cos_u); uni->verts[uni->num_verts].y = y + f_mul(r_tube, sin_v); uni->verts[uni->num_verts].z = z + f_mul(dist, sin_u); uni->num_verts++; obj->num_verts++; } } for (i = 0; i < seg_main; i++) { int next_i = (i + 1) % seg_main; for (j = 0; j < seg_tube; j++) { int next_j = (j + 1) % seg_tube; int a = v_base + i * seg_tube + j; int b = v_base + next_i * seg_tube + j; int c = v_base + i * seg_tube + next_j; int d = v_base + next_i * seg_tube + next_j; push_face(uni, obj, a, c, b, wire); push_face(uni, obj, b, c, d, wire); } } return obj; } Object3D *add_cylinder(Universe *uni, fixed x, fixed y, fixed z, fixed r, fixed h, int det, uint8_t col, uint8_t wire) { int i, v_base, cap_bot_center, cap_bot_rim, cap_top_center, cap_top_rim, th; fixed half_h, s, cs; Object3D *obj; if (uni->num_objects >= MAX_OBJECTS) return NULL; if (uni->num_verts + 2 + 4 * det > MAX_VERTEX) return NULL; if (uni->num_faces + 4 * det > MAX_FACES) return NULL; obj = alloc_object(uni); obj->color = col; v_base = uni->num_verts; half_h = h / 2; /* --- Corps --- */ for (i = 0; i < det; i++) { th = (i * 360 / det) % 360; s = sintab[th]; cs = costab[th]; uni->v_normals[uni->num_verts].x = cs; uni->v_normals[uni->num_verts].y = 0; uni->v_normals[uni->num_verts].z = s; uni->verts[uni->num_verts].x = x + f_mul(r, cs); uni->verts[uni->num_verts].y = y - half_h; uni->verts[uni->num_verts].z = z + f_mul(r, s); uni->num_verts++; obj->num_verts++; uni->v_normals[uni->num_verts].x = cs; uni->v_normals[uni->num_verts].y = 0; uni->v_normals[uni->num_verts].z = s; uni->verts[uni->num_verts].x = x + f_mul(r, cs); uni->verts[uni->num_verts].y = y + half_h; uni->verts[uni->num_verts].z = z + f_mul(r, s); uni->num_verts++; obj->num_verts++; } for (i = 0; i < det; i++) { int a = v_base + (i * 2); int b = v_base + ((i * 2 + 2) % (det * 2)); int cv = a + 1; int d = b + 1; push_face(uni, obj, a, cv, b, wire); push_face(uni, obj, cv, d, b, wire); } /* --- Fond bas --- */ cap_bot_center = uni->num_verts; uni->v_normals[uni->num_verts].x = 0; uni->v_normals[uni->num_verts].y = -int_to_f(1); uni->v_normals[uni->num_verts].z = 0; uni->verts[uni->num_verts].x = x; uni->verts[uni->num_verts].y = y - half_h; uni->verts[uni->num_verts].z = z; uni->num_verts++; obj->num_verts++; cap_bot_rim = uni->num_verts; for (i = 0; i < det; i++) { th = (i * 360 / det) % 360; s = sintab[th]; cs = costab[th]; uni->v_normals[uni->num_verts].x = 0; uni->v_normals[uni->num_verts].y = -int_to_f(1); uni->v_normals[uni->num_verts].z = 0; uni->verts[uni->num_verts].x = x + f_mul(r, cs); uni->verts[uni->num_verts].y = y - half_h; uni->verts[uni->num_verts].z = z + f_mul(r, s); uni->num_verts++; obj->num_verts++; } for (i = 0; i < det; i++) push_face(uni, obj, cap_bot_center, cap_bot_rim + i, cap_bot_rim + (i + 1) % det, wire); /* --- Fond haut --- */ cap_top_center = uni->num_verts; uni->v_normals[uni->num_verts].x = 0; uni->v_normals[uni->num_verts].y = int_to_f(1); uni->v_normals[uni->num_verts].z = 0; uni->verts[uni->num_verts].x = x; uni->verts[uni->num_verts].y = y + half_h; uni->verts[uni->num_verts].z = z; uni->num_verts++; obj->num_verts++; cap_top_rim = uni->num_verts; for (i = 0; i < det; i++) { th = (i * 360 / det) % 360; s = sintab[th]; cs = costab[th]; uni->v_normals[uni->num_verts].x = 0; uni->v_normals[uni->num_verts].y = int_to_f(1); uni->v_normals[uni->num_verts].z = 0; uni->verts[uni->num_verts].x = x + f_mul(r, cs); uni->verts[uni->num_verts].y = y + half_h; uni->verts[uni->num_verts].z = z + f_mul(r, s); uni->num_verts++; obj->num_verts++; } for (i = 0; i < det; i++) push_face(uni, obj, cap_top_center, cap_top_rim + (i + 1) % det, cap_top_rim + i, wire); return obj; } /* --- I/O sur Mesh dynamique (non utilisé dans le pipeline principal) --- */ void save_mesh(Mesh *m, const char *fn) { FILE *f = fopen(fn, "wb"); if (!f) return; fwrite(&m->num_verts, sizeof(int), 1, f); fwrite(&m->num_faces, sizeof(int), 1, f); fwrite(m->verts, sizeof(Vector3), m->num_verts, f); fwrite(m->v_normals,sizeof(Vector3), m->num_verts, f); fwrite(m->faces, sizeof(Face), m->num_faces, f); fclose(f); } Mesh *load_mesh(const char *fname) { Mesh *m; FILE *f = fopen(fname, "rb"); if (!f) return NULL; m = (Mesh*)malloc(sizeof(Mesh)); if (!m) return NULL; fread(&m->num_verts, sizeof(int), 1, f); fread(&m->num_faces, sizeof(int), 1, f); m->verts = (Vector3*)malloc(sizeof(Vector3) * m->num_verts); m->v_normals = (Vector3*)malloc(sizeof(Vector3) * m->num_verts); m->faces = (Face*) malloc(sizeof(Face) * m->num_faces); if (!m->verts || !m->v_normals || !m->faces) { free(m->verts); free(m->v_normals); free(m->faces); free(m); fclose(f); return NULL; } fread(m->verts, sizeof(Vector3), m->num_verts, f); fread(m->v_normals, sizeof(Vector3), m->num_verts, f); fread(m->faces, sizeof(Face), m->num_faces, f); fclose(f); return m; } void free_mesh(Mesh *m) { if (!m) return; free(m->verts); free(m->v_normals); free(m->faces); free(m); } void export_universe_to_c(Universe *uni, const char *filename) { int i; FILE *f = fopen(filename, "w"); if (!f) return; fprintf(f, "#ifndef EXPORTED_DATA_H\n#define EXPORTED_DATA_H\n\n#include \"defines.h\"\n\n"); // 1. Tables trigonométriques fprintf(f, "fixed sintab[360] = {"); for(i=0; i<360; i++) fprintf(f, "%d%s", sintab[i], i<359?", ":""); fprintf(f, "};\n\nfixed costab[360] = {"); for(i=0; i<360; i++) fprintf(f, "%d%s", costab[i], i<359?", ":""); fprintf(f, "};\n\n"); // 2. Vertices et Normales fprintf(f, "Vector3 uni_verts[%d] = {\n", uni->num_verts); for(i=0; inum_verts; i++) fprintf(f, " {%d, %d, %d}%s\n", uni->verts[i].x, uni->verts[i].y, uni->verts[i].z, inum_verts-1?",":""); fprintf(f, "};\n\n"); fprintf(f, "Vector3 uni_normals[%d] = {\n", uni->num_verts); for(i=0; inum_verts; i++) fprintf(f, " {%d, %d, %d}%s\n", uni->v_normals[i].x, uni->v_normals[i].y, uni->v_normals[i].z, inum_verts-1?",":""); fprintf(f, "};\n\n"); // 3. Faces fprintf(f, "Face uni_faces[%d] = {\n", uni->num_faces); for(i=0; inum_faces; i++) fprintf(f, " {%d, %d, %d, %d}%s\n", uni->faces[i].a, uni->faces[i].b, uni->faces[i].c, uni->faces[i].force_wire, inum_faces-1?",":""); fprintf(f, "};\n\n"); // 4. Objets fprintf(f, "Object3D uni_objects[%d] = {\n", uni->num_objects); for(i=0; inum_objects; i++) { Object3D *o = &uni->objects[i]; fprintf(f, " { %d, %d, %d, %d, ", o->vert_start, o->num_verts, o->face_start, o->num_faces); fprintf(f, "{%d,%d,%d}, {%d,%d,%d}, ", o->pos.x, o->pos.y, o->pos.z, o->base_pos.x, o->base_pos.y, o->base_pos.z); // Matrice identité par défaut ou état actuel fprintf(f, "{{{%d,%d,%d},{%d,%d,%d},{%d,%d,%d}}}, %d }%s\n", o->rot.m[0][0], o->rot.m[0][1], o->rot.m[0][2], o->rot.m[1][0], o->rot.m[1][1], o->rot.m[1][2], o->rot.m[2][0], o->rot.m[2][1], o->rot.m[2][2], o->color, inum_objects-1?",":""); } fprintf(f, "};\n\n"); // 5. Structure Universe globale fprintf(f, "Universe static_universe = {\n"); fprintf(f, " {0}, {0}, {0}, %d, %d, {0}, %d\n};\n\n", uni->num_verts, uni->num_faces, uni->num_objects); fprintf(f, "void load_static_universe(Universe *u) {\n"); fprintf(f, " memcpy(u->verts, uni_verts, sizeof(uni_verts));\n"); fprintf(f, " memcpy(u->v_normals, uni_normals, sizeof(uni_normals));\n"); fprintf(f, " memcpy(u->faces, uni_faces, sizeof(uni_faces));\n"); fprintf(f, " memcpy(u->objects, uni_objects, sizeof(uni_objects));\n"); fprintf(f, " u->num_verts = %d; u->num_faces = %d; u->num_objects = %d;\n", uni->num_verts, uni->num_faces, uni->num_objects); fprintf(f, "}\n\n"); fprintf(f, "#endif\n"); fclose(f); } #endif /* MINIMAL_PLAYER */