dos-3D-Engine/src/part3D/geometry.c
2026-05-10 13:37:52 +02:00

488 lines
17 KiB
C

#include "defines.h"
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};
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);
}