From c6d6f787f7b41b9f21785287d5803c2349ef5f8c Mon Sep 17 00:00:00 2001 From: Frater <13979047+saintfrater@users.noreply.github.com> Date: Sun, 10 May 2026 02:29:00 +0200 Subject: [PATCH] fixed --- Makefile | 4 +- WORKDOC.md | 187 +++++++++++++++++++++++ src/main/main.c | 159 +++++++++++++------- src/part3D/defines.h | 116 +++++++-------- src/part3D/engine.c | 135 ++++++++--------- src/part3D/geometry.c | 149 +++++++++++-------- src/part3D/graph.c | 8 +- src/part3D/raster.c | 338 +++++++++++++++++------------------------- 8 files changed, 639 insertions(+), 457 deletions(-) create mode 100644 WORKDOC.md diff --git a/Makefile b/Makefile index 27ed13a..9b21116 100644 --- a/Makefile +++ b/Makefile @@ -84,5 +84,5 @@ clean: rm -f *.err src/**/*.err cleanall: - clean - all \ No newline at end of file + $(MAKE) clean + $(MAKE) all \ No newline at end of file diff --git a/WORKDOC.md b/WORKDOC.md new file mode 100644 index 0000000..17a5e7a --- /dev/null +++ b/WORKDOC.md @@ -0,0 +1,187 @@ +# WORKDOC — Moteur 3D DOS (TESTING) + +## Vue d'ensemble + +Moteur 3D software en C ciblant le DOS 32-bit via l'extender **CauseWay** (ou DOS/4GW). +Compilateur : **OpenWatcom wcc386** exécuté depuis WSL. +Affichage : **VGA Mode 13h** — 320×200, 256 couleurs, rendu Gouraud en virgule fixe 16.16. + +--- + +## Structure du projet + +``` +src/ + main/main.c Point d'entrée, scène, boucle principale + part3D/ + defines.h Types, macros fixed-point, prototypes, externs + engine.c Maths (sin/cos), matrices, pipeline de rendu + geometry.c Génération de meshes (sphère, cylindre) + I/O mesh + graph.c VGA init, palette, backbuffer/zbuffer + raster.c Rastériseur triangle Gouraud, tracé de ligne Z-buffered +build/ + app.exe Binaire DOS final (CauseWay) + link.lnk Script de link généré automatiquement +Makefile Build via WSL + wcc386 Windows natif +``` + +--- + +## Pipeline de rendu + +``` +init_engine_math() Précalcul sin/cos (tables entières 16.16) +add_sphere / add_cylinder Génération mesh en espace local (0,0,0) +─── Boucle principale ─── + kbhit / getch Gestion clavier + mat3_rotate_x/y Construction matrices de rotation + mat3_mul (orbite) Composition de la matrice d'orbite + → obj.rot = orbit Application uniforme à tous les objets + → obj.pos = orbit × base_pos + center Rotation des positions + clear_buffers Effacement backbuffer + zbuffer (0xFFFF) + render_universe Transformation + projection + Gouraud fill + flip memcpy backbuffer → 0xA0000 (VGA) +``` + +--- + +## Arithmétique virgule fixe 16.16 + +| Macro/fonction | Opération | +|---|---| +| `int_to_f(a)` | `a << 16` | +| `f_to_int(a)` | `a >> 16` | +| `f_mul(a,b)` | `(int64_t)a * b >> 16` | +| `f_div(a,b)` | `(int64_t)a << 16 / b` | + +--- + +## Palette VGA + +256 entrées organisées en **16 couleurs × 16 niveaux d'intensité**. +Index pixel = `(base_color << 4) | shade` avec shade ∈ [0..15]. +Les 16 couleurs de base sont dans `my_palette[]` (`graph.c`). +La palette est chargée dans le DAC VGA au démarrage via `setup_vga_palette()`. + +--- + +## Projection perspective + +```c +v_cache[i].x = 160 + f_to_int(f_div(rx << 8, pz)); +v_cache[i].y = 100 - f_to_int(f_div(ry << 8, pz)); +``` + +`<< 8` = distance focale implicite de 256 pixels. +`pz` est clampé à `int_to_f(20)` minimum pour éviter la division par zéro. + +--- + +## Back-face culling et convention de winding + +Le pipeline applique la **transposée** de la matrice de rotation aux sommets (convention colonne Watcom). Cette transposition inverse le handedness des triangles projetés. + +**Convention retenue :** winding CCW vu de l'extérieur → produit vectoriel 2D **> 0** en espace écran → face visible. + +```c +front = ((p2->x - p1->x) * (p3->y - p1->y) + - (p2->y - p1->y) * (p3->x - p1->x)) > 0; +``` + +Toutes les géométries (sphère, corps cylindre, fonds cylindre) respectent cette convention. + +--- + +## Shading Gouraud + +La lumière est assimilée à la direction de vue (−Z monde). Le dot product de la normale rotée avec (0,0,−1) est `−nz`. + +```c +nz = f_mul(n->x, rot.m[0][2]) + f_mul(n->y, rot.m[1][2]) + f_mul(n->z, rot.m[2][2]); +intensity = (nz >= 0) ? int_to_f(1) : ((-nz) * 14) + int_to_f(1); +``` + +| nz | Signification | Intensité (shade) | +|---|---|---| +| −1.0 | Face directement vers caméra | 15 (max) | +| 0 | Face tangentielle | 1 (ambiant) | +| > 0 | Face opposée à la caméra | 1 (ambiant, face culléé) | + +L'intensité est interpolée en virgule fixe 16.16 entre les sommets du triangle. + +--- + +## Génération des meshes + +### Sphère (`add_sphere`) + +Paramètres : centre local, rayon `r`, détail `det` (nombre de subdivisions). +Génère `(det+1) × det` sommets et `det × det × 2` faces. +Les normales sont les vecteurs de position unitaires (normales sphériques exactes). +Winding : `add_face(a, b, c)` et `add_face(b, d, c)` — CCW vu de l'extérieur. + +### Cylindre (`add_cylinder`) + +Paramètres : centre local, rayon `r`, hauteur `h`, détail `det`. + +**Corps (barrel) :** +`det` paires de sommets bas/haut. Normales radiales `(cos θ, 0, sin θ)`. +`2×det` faces. Winding : `(bas_i, haut_i, bas_{i+1})` et `(haut_i, haut_{i+1}, bas_{i+1})`. + +**Fond bas :** +1 sommet centre + `det` sommets de rebord. Normale `(0, −1, 0)`. +`det` faces en éventail depuis le centre. Winding : `(centre, rebord[i], rebord[i+1])`. + +**Fond haut :** +1 sommet centre + `det` sommets de rebord. Normale `(0, +1, 0)`. +`det` faces en éventail depuis le centre. Winding inversé (normale opposée) : `(centre, rebord[i+1], rebord[i])`. + +**Total par cylindre (det=16) :** 2+4×det = 66 sommets, 4×det = 64 faces. + +--- + +## Orbite de l'observateur (`main.c`) + +Les objets ont des positions de base fixes dans l'espace scène, définies par rapport au centre `(0, 0, 300)` : + +| Objet | Offset base | +|---|---| +| Sphère (universe[0]) | (+60, 0, 0) | +| Cylindre (universe[1]) | (−60, 0, 0) | + +Chaque frame, la matrice d'orbite `orbit = rotX(anglex) × rotY(angley)` est calculée et appliquée uniformément : + +```c +universe[o].rot = orbit; +universe[o].pos.x = f_mul(base_x, orbit.m[0][0]); +universe[o].pos.y = f_mul(base_x, orbit.m[0][1]); +universe[o].pos.z = int_to_f(300) + f_mul(base_x, orbit.m[0][2]); +``` + +La caméra reste à l'origine (+ translations clavier). L'effet visuel est celui d'un observateur qui orbite autour de la scène. + +--- + +## Contrôles clavier + +| Touche | Action | +|---|---| +| Z / S | Caméra avance / recule (axe Z) | +| Q / D | Caméra gauche / droite (axe X) | +| A / E | Caméra haut / bas (axe Y) | +| + / − | Orbite vertical (anglex ±3°) | +| / / * | Orbite horizontal (angley ±3°) | +| R | Reset caméra + angles | +| Esc | Quitter | + +--- + +## Points de vigilance + +| Sujet | Note | +|---|---| +| Winding | Toutes les géométries doivent respecter la convention CCW (cross > 0). Vérifier à chaque ajout de primitive. | +| Caméra sans rotation | La caméra n'a pas de matrice de vue — elle regarde toujours en +Z. L'orbite est simulée en faisant tourner la scène. Ajouter une matrice de vue si un vrai look-around est nécessaire. | +| Clamp pz | pz clampé à int_to_f(20). Si un objet passe derrière la caméra (pz < 0 avant clamp), il sera projeté incorrectement. | +| Modes fil-de-fer | MODE_WIRE, MODE_HIDDEN opérationnels. Le champ `face.force_wire` permet de forcer le fil-de-fer face par face en MODE_SOLID. | +| I/O mesh | `save_mesh` / `load_mesh` / `free_mesh` disponibles dans `geometry.c` mais non utilisées depuis `main.c`. | diff --git a/src/main/main.c b/src/main/main.c index e2267ed..a8e3753 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -1,76 +1,129 @@ #include "../part3D/defines.h" int main() { - // Allocation initiale large pour accumulation - Mesh scene; - Matrix3 rot, tmpX, tmpY; - int angX = 0, angY = 0; - int key = 0; + Mesh m_sphere, m_cyl; + Object3D universe[2]; + Camera cam; + Matrix3 rotX, rotY, orbit; + int anglex = 0, angley = 0, key = 0; - printf("STARTING\n"); + init_engine_math(); - init_engine_math(); + /* Allocation intégrale des Mesh */ + m_sphere.verts = (Vector3*)malloc(MAX_VERTEX * sizeof(Vector3)); + m_sphere.v_normals = (Vector3*)malloc(MAX_VERTEX * sizeof(Vector3)); + m_sphere.faces = (Face*)malloc(MAX_FACES * sizeof(Face)); + m_sphere.num_verts = m_sphere.num_faces = 0; - scene.verts = (Vector3*)malloc(MAX_VERTEX*sizeof(Vector3)); - scene.v_normals = (Vector3*)malloc(MAX_VERTEX*sizeof(Vector3)); - scene.faces = (Face*)malloc(MAX_FACES*sizeof(Face)); + m_cyl.verts = (Vector3*)malloc(MAX_VERTEX * sizeof(Vector3)); + m_cyl.v_normals = (Vector3*)malloc(MAX_VERTEX * sizeof(Vector3)); + m_cyl.faces = (Face*)malloc(MAX_FACES * sizeof(Face)); + m_cyl.num_verts = m_cyl.num_faces = 0; - if (!scene.verts || !scene.v_normals || !scene.faces) { - printf("Erreur : Memoire insuffisante pour le Mesh.\n"); - return 1; - } + if (!m_sphere.verts || !m_sphere.v_normals || !m_sphere.faces || + !m_cyl.verts || !m_cyl.v_normals || !m_cyl.faces) return 1; - scene.num_verts = 0; - scene.num_faces = 0; + /* Génération en 0,0,0 (Espace Local) */ + add_sphere(&m_sphere, 0, 0, 0, int_to_f(30), 12, COLOR5, 0); + add_cylinder(&m_cyl, 0, 0, 0, int_to_f(20), int_to_f(60), 16, COLOR14, 0); - // Création d'objets mixtes - add_cylinder(&scene, int_to_f(-50), 0, int_to_f(300), int_to_f(20), int_to_f(80), 16, 2, 0); // Plein - add_sphere(&scene, int_to_f(50), 0, int_to_f(300), int_to_f(30), 12, 4, 1); // Toujours filaire + /* Configuration des objets dans l'univers */ + universe[0].mesh = &m_sphere; + universe[0].pos.x = int_to_f(60); universe[0].pos.y = 0; universe[0].pos.z = int_to_f(300); + universe[0].color = 4; /* Jaune */ + mat3_identity(&universe[0].rot); - init_vga(); - mat3_identity(&rot); + universe[1].mesh = &m_cyl; + universe[1].pos.x = int_to_f(-60); universe[1].pos.y = 0; universe[1].pos.z = int_to_f(300); + universe[1].color = 2; /* Vert */ + mat3_identity(&universe[1].rot); - while (key != 27) { // 27 = Touche Echap pour quitter + /* Caméra initiale */ + cam.pos.x = 0; cam.pos.y = 0; cam.pos.z = 0; + + init_vga(); + + while (key != 27) { if (kbhit()) { key = getch(); - // Gestion ZQSD (Sensibilité de 5 degrés) - if (key == 'z' || key == 'Z') angX = (angX + 5) % 360; - if (key == 's' || key == 'S') angX = (angX + 355) % 360; - if (key == 'q' || key == 'Q') angY = (angY + 355) % 360; - if (key == 'd' || key == 'D') angY = (angY + 5) % 360; + switch (key) { + case 'Z': + case 'z': + cam.pos.z += int_to_f(10); + break; - // Reconstruction de la matrice de rotation combinée - mat3_rotate_x(&tmpX, angX); - mat3_rotate_y(&tmpY, angY); - mat3_mul(&rot, &tmpX, &tmpY); + case 'S': + case 's': + cam.pos.z -= int_to_f(10); + break; + + case 'Q': + case 'q': + cam.pos.x -= int_to_f(10); + break; + + case 'D': + case 'd': + cam.pos.x += int_to_f(10); + break; + + case 'A': + case 'a': + cam.pos.y -= int_to_f(10); + break; + + case 'E': + case 'e': + cam.pos.y += int_to_f(10); + break; + + case 'R': + case 'r': + cam.pos.x = cam.pos.y = cam.pos.z = 0; + anglex = angley = 0; + break; + + case '+': + anglex = (anglex + 3) % 360; + break; + + case '-': + anglex = ((anglex - 3) % 360 + 360) % 360; + break; + + case '/': + angley = (angley + 3) % 360; + break; + + case '*': + angley = ((angley - 3) % 360 + 360) % 360; + break; + + } } + /* Orbite : rotation de la scène entière autour du centre (0,0,300) */ + mat3_rotate_x(&rotX, anglex); + mat3_rotate_y(&rotY, angley); + mat3_mul(&orbit, &rotX, &rotY); + + universe[0].rot = orbit; + universe[0].pos.x = f_mul(int_to_f( 60), orbit.m[0][0]); + universe[0].pos.y = f_mul(int_to_f( 60), orbit.m[0][1]); + universe[0].pos.z = int_to_f(300) + f_mul(int_to_f( 60), orbit.m[0][2]); + + universe[1].rot = orbit; + universe[1].pos.x = f_mul(int_to_f(-60), orbit.m[0][0]); + universe[1].pos.y = f_mul(int_to_f(-60), orbit.m[0][1]); + universe[1].pos.z = int_to_f(300) + f_mul(int_to_f(-60), orbit.m[0][2]); + clear_buffers(0); - render_scene(&scene, &rot, MODE_WIRE); + render_universe(universe, 2, &cam, MODE_SOLID); flip(); } - close_vga(); - return 0; -} -/* -int main() { - init_engine_math(); - init_vga(); // On alloue les buffers ici - - // VÉRIFICATION MANUELLE ICI - if (backbuffer == NULL || zbuffer == NULL) { - printf("Erreur d'allocation des buffers video\n"); - return 1; - } - - while(!kbhit()) { - // Test ultra-basique : on remplit l'écran de rouge - // SANS utiliser le z-buffer pour l'instant - memset(backbuffer, 4, 64000); - flip(); - } close_vga(); + free(m_sphere.verts); free(m_sphere.v_normals); free(m_sphere.faces); + free(m_cyl.verts); free(m_cyl.v_normals); free(m_cyl.faces); return 0; } -*/ diff --git a/src/part3D/defines.h b/src/part3D/defines.h index a11395b..682b0b3 100644 --- a/src/part3D/defines.h +++ b/src/part3D/defines.h @@ -8,99 +8,89 @@ #include #include -#define MODE_WIRE 0 // Transparent totalv_cache -#define MODE_HIDDEN 1 // Fil de fer avec surfaces cachées -#define MODE_SOLID 2 // Plein (Gouraud) +#define MODE_WIRE 0 +#define MODE_HIDDEN 1 +#define MODE_SOLID 2 -#define MAX_VERTEX 5000 -#define MAX_FACES 8000 +#define MAX_VERTEX 5000 +#define MAX_FACES 8000 + +typedef struct { uint8_t r, g, b; } RGB; + +#define COLOR0 0 // 0: Noir +#define COLOR1 1 // 1: Rouge vif +#define COLOR2 2 // 2: Vert vif +#define COLOR3 3 // 3: Bleu vif +#define COLOR4 4 // 4: Jaune +#define COLOR5 5 // 5: Magenta +#define COLOR6 6 // 6: Cyan +#define COLOR7 7 // 7: Blanc +#define COLOR8 8 // 8: Rouge sombre +#define COLOR9 9 // 9: Vert sombre +#define COLOR10 10 // 10: Bleu sombre +#define COLOR11 11 // 11: Gris +#define COLOR12 12 // 12: Orange +#define COLOR13 13 // 13: Citron vert +#define COLOR14 14 // 14: Marron +#define COLOR15 15 // 15: Bleu nuit typedef int32_t fixed; #define f_to_int(a) ((a) >> 16) #define int_to_f(a) ((a) << 16) -// #define f_mul(a, b) ((fixed)(((int64_t)(a) * (b)) >> 16)) -// --- Remplacement des inlines --- static __inline fixed f_mul(fixed a, fixed b) { return (fixed)(((int64_t)a * b) >> 16); } static __inline fixed f_div(fixed a, fixed b) { if (b == 0) return 0; return (fixed)(((int64_t)a << 16) / b); } -// Matrice 3x3 pour la rotation des normales et des sommets -typedef struct { - fixed m[3][3]; -} Matrix3; +typedef struct { fixed m[3][3]; } Matrix3; +typedef struct { fixed x, y, z; } Vector3; +typedef struct { int a, b, c; uint8_t color; uint8_t force_wire; } Face; +typedef struct { int x, y; fixed z; int intensity; } Point2D; +typedef struct { Vector3 *verts; Vector3 *v_normals; Face *faces; int num_verts, num_faces; } Mesh; -typedef struct { - fixed x, y, z; -} Vector3; +/* Structure pour l'univers */ typedef struct { - int a, b, c; - uint8_t color; - uint8_t force_wire; -} Face; - -typedef struct { - int x, y; - fixed z; - int intensity; -} Point2D; - -typedef struct { - Vector3 *verts; - Vector3 *v_normals; - Face *faces; - int num_verts, num_faces; -} Mesh; - -typedef struct { - Mesh *mesh; // Pointeur vers le modèle 3D (partagé si plusieurs sphères) - Vector3 position; // Position dans le monde - Matrix3 rotation; // Rotation locale de l'objet + Mesh *mesh; + Vector3 pos; + Matrix3 rot; + uint8_t color; } Object3D; -typedef struct { uint8_t r, g, b; } RGB; +typedef struct { + Vector3 pos; +} Camera; -// --- Ajout des déclarations de tables --- -extern fixed sintab[360]; -extern fixed costab[360]; -extern fixed inv_table[321]; +/* Globales */ +extern fixed sintab[360], costab[360]; extern Point2D v_cache[MAX_VERTEX]; extern uint8_t *backbuffer; extern uint16_t *zbuffer; extern uint8_t *vga; -// Engine.C -void init_engine_math(); -void normalize(Vector3 *v); +/* Prototypes */ +void init_engine_math(void); +void mat3_identity(Matrix3 *mat); void mat3_rotate_x(Matrix3 *m, int angle); void mat3_rotate_y(Matrix3 *m, int angle); void mat3_mul(Matrix3 *res, Matrix3 *a, Matrix3 *b); -// geometry.c -void add_face(Mesh *m, int a, int b, int c, uint8_t col, uint8_t wire); void add_sphere(Mesh *m, fixed x, fixed y, fixed z, fixed r, int det, uint8_t col, uint8_t wire); void add_cylinder(Mesh *m, fixed x, fixed y, fixed z, fixed r, fixed h, int det, uint8_t col, uint8_t wire); -void save_mesh(Mesh *m, const char *fn); -Mesh* load_mesh(const char *fname); -void free_mesh(Mesh *m); -void render_scene(Mesh *m, Matrix3 *rot, int global_mode); -// Raster.c -void draw_line_z(Point2D *p1, Point2D *p2, uint8_t col, int z_test); -void swap_pt(Point2D **a, Point2D **b); -void fill_triangle_gouraud(Point2D *p1, Point2D *p2, Point2D *p3, uint8_t base_color); -void fill_triangle_zonly(Point2D *p1, Point2D *p2, Point2D *p3); +void render_universe(Object3D *objs, int num_objs, Camera *cam, int mode); -// Graph.c -void init_vga(); +void init_vga(void); void clear_buffers(uint8_t color); -void flip(); -void close_vga(); +void flip(void); +void close_vga(void); + +void fill_triangle_gouraud(Point2D *p1, Point2D *p2, Point2D *p3, uint8_t base_color); +void draw_line_z(Point2D *p1, Point2D *p2, uint8_t col, int z_test); -// Math.c -void mat3_identity(Matrix3 *mat); -void init_engine_math(); void normalize(Vector3 *v); +void save_mesh(Mesh *m, const char *fn); +Mesh *load_mesh(const char *fname); +void free_mesh(Mesh *m); -#endif // DEFINE_H +#endif diff --git a/src/part3D/engine.c b/src/part3D/engine.c index 1b87143..6462e9c 100644 --- a/src/part3D/engine.c +++ b/src/part3D/engine.c @@ -1,6 +1,6 @@ #include "defines.h" -fixed sintab[360], costab[360], inv_table[321]; +fixed sintab[360], costab[360]; Point2D v_cache[MAX_VERTEX]; void mat3_identity(Matrix3 *mat) { @@ -10,17 +10,13 @@ void mat3_identity(Matrix3 *mat) { void init_engine_math() { int i; - for (i = 0; i < 360; i++) { double r = (double)i * 3.14159265 / 180.0; sintab[i] = (fixed)(sin(r) * 65536.0); costab[i] = (fixed)(cos(r) * 65536.0); } - inv_table[0] = 0; - for (i = 1; i <= 320; i++) inv_table[i] = (int_to_f(1) / i); } -// Normalisation pour le Gouraud (à la création uniquement) void normalize(Vector3 *v) { double dx = (double)v->x, dy = (double)v->y, dz = (double)v->z; double d = sqrt(dx*dx + dy*dy + dz*dz); @@ -29,25 +25,6 @@ void normalize(Vector3 *v) { } } -// Génère une matrice de rotation sur l'axe X -void mat3_rotate_x(Matrix3 *m, int angle) { - fixed c = costab[angle % 360]; - fixed s = sintab[angle % 360]; - mat3_identity(m); - m->m[1][1] = c; m->m[1][2] = -s; - m->m[2][1] = s; m->m[2][2] = c; -} - -// Génère une matrice de rotation sur l'axe Y -void mat3_rotate_y(Matrix3 *m, int angle) { - fixed c = costab[angle % 360]; - fixed s = sintab[angle % 360]; - mat3_identity(m); - m->m[0][0] = c; m->m[0][2] = s; - m->m[2][0] = -s; m->m[2][2] = c; -} - -// Multiplie deux matrices 3x3 : res = a * b void mat3_mul(Matrix3 *res, Matrix3 *a, Matrix3 *b) { int i, j; for (i = 0; i < 3; i++) { @@ -59,61 +36,77 @@ void mat3_mul(Matrix3 *res, Matrix3 *a, Matrix3 *b) { } } -void render_scene(Mesh *m, Matrix3 *rot, int global_mode) { - int i; - fixed pz, rx, ry, rz; - Vector3 *v; - Vector3 *n; - fixed nz; - int intensity; +void mat3_rotate_x(Matrix3 *m, int angle) { + int a = ((angle % 360) + 360) % 360; + fixed c = costab[a], s = sintab[a]; + mat3_identity(m); + m->m[1][1] = c; m->m[1][2] = -s; m->m[2][1] = s; m->m[2][2] = c; +} +void mat3_rotate_y(Matrix3 *m, int angle) { + int a = ((angle % 360) + 360) % 360; + fixed c = costab[a], s = sintab[a]; + mat3_identity(m); + m->m[0][0] = c; m->m[0][2] = s; m->m[2][0] = -s; m->m[2][2] = c; +} - for (i = 0; i < m->num_verts; i++) { - v = &m->verts[i]; - n = &m->v_normals[i]; +void render_universe(Object3D *objs, int num_objs, Camera *cam, int mode) { + int o, i, front; + fixed rx, ry, rz, pz, nz; + uint8_t wire_col; - // --- 1. Rotation de la normale (pour la lumière) --- - nz = f_mul(n->x, rot->m[0][2]) + f_mul(n->y, rot->m[1][2]) + f_mul(n->z, rot->m[2][2]); - intensity = f_to_int(nz * 15); - if (intensity < 0) intensity = 0; + for (o = 0; o < num_objs; o++) { + Object3D *obj = &objs[o]; + Mesh *m = obj->mesh; - // --- 2. Rotation du sommet (LA PIÈCE MANQUANTE) --- - // On applique la multiplication Matrice * Vecteur - rx = f_mul(v->x, rot->m[0][0]) + f_mul(v->y, rot->m[1][0]) + f_mul(v->z, rot->m[2][0]); - ry = f_mul(v->x, rot->m[0][1]) + f_mul(v->y, rot->m[1][1]) + f_mul(v->z, rot->m[2][1]); - rz = f_mul(v->x, rot->m[0][2]) + f_mul(v->y, rot->m[1][2]) + f_mul(v->z, rot->m[2][2]); + for (i = 0; i < m->num_verts; i++) { + Vector3 *v = &m->verts[i], *n = &m->v_normals[i]; - // --- 3. Projection avec les coordonnées tournées --- - pz = rz; // On utilise le Z tourné - if (pz < int_to_f(10)) pz = int_to_f(10); + rx = f_mul(v->x, obj->rot.m[0][0]) + f_mul(v->y, obj->rot.m[1][0]) + f_mul(v->z, obj->rot.m[2][0]) + obj->pos.x - cam->pos.x; + ry = f_mul(v->x, obj->rot.m[0][1]) + f_mul(v->y, obj->rot.m[1][1]) + f_mul(v->z, obj->rot.m[2][1]) + obj->pos.y - cam->pos.y; + rz = f_mul(v->x, obj->rot.m[0][2]) + f_mul(v->y, obj->rot.m[1][2]) + f_mul(v->z, obj->rot.m[2][2]) + obj->pos.z - cam->pos.z; - v_cache[i].z = pz; - v_cache[i].intensity = intensity; - v_cache[i].x = 160 + f_to_int(f_div(rx << 8, pz)); // On utilise rx tourné - v_cache[i].y = 100 - f_to_int(f_div(ry << 8, pz)); // On utilise ry tourné - } + pz = (rz < int_to_f(20)) ? int_to_f(20) : rz; + v_cache[i].z = pz; + v_cache[i].x = 160 + f_to_int(f_div(rx << 8, pz)); + v_cache[i].y = 100 - f_to_int(f_div(ry << 8, pz)); - for (i = 0; i < m->num_faces; i++) { - Face *f = &m->faces[i]; - Point2D *p1 = &v_cache[f->a]; - Point2D *p2 = &v_cache[f->b]; - Point2D *p3 = &v_cache[f->c]; - int back = (p2->x - p1->x) * (p3->y - p1->y) - (p2->y - p1->y) * (p3->x - p1->x); + nz = f_mul(n->x, obj->rot.m[0][2]) + f_mul(n->y, obj->rot.m[1][2]) + f_mul(n->z, obj->rot.m[2][2]); + v_cache[i].intensity = (nz >= 0) ? int_to_f(1) : ((-nz) * 14) + int_to_f(1); + } - if (global_mode == MODE_WIRE) { - draw_line_z(p1, p2, f->color, 0); - draw_line_z(p2, p3, f->color, 0); - draw_line_z(p3, p1, f->color, 0); - } else { - if (back < 0) { - if (f->force_wire || global_mode == MODE_HIDDEN) { - fill_triangle_zonly(p1, p2, p3); - draw_line_z(p1, p2, f->color, 1); - draw_line_z(p2, p3, f->color, 1); - draw_line_z(p3, p1, f->color, 1); // Ajouté pour fermer le triangle - } else { - fill_triangle_gouraud(p1, p2, p3, f->color); - } + wire_col = (uint8_t)((obj->color << 4) | 15); + + for (i = 0; i < m->num_faces; i++) { + Face *f = &m->faces[i]; + Point2D *p1 = &v_cache[f->a], *p2 = &v_cache[f->b], *p3 = &v_cache[f->c]; + front = ((p2->x - p1->x) * (p3->y - p1->y) - (p2->y - p1->y) * (p3->x - p1->x)) > 0; + + switch (mode) { + case MODE_WIRE: + draw_line_z(p1, p2, wire_col, 0); + draw_line_z(p2, p3, wire_col, 0); + draw_line_z(p3, p1, wire_col, 0); + break; + case MODE_HIDDEN: + if (front) { + draw_line_z(p1, p2, wire_col, 1); + draw_line_z(p2, p3, wire_col, 1); + draw_line_z(p3, p1, wire_col, 1); + } + break; + case MODE_SOLID: + default: + if (front) { + if (f->force_wire) { + draw_line_z(p1, p2, wire_col, 1); + draw_line_z(p2, p3, wire_col, 1); + draw_line_z(p3, p1, wire_col, 1); + } else { + fill_triangle_gouraud(p1, p2, p3, obj->color); + } + } + break; } } } diff --git a/src/part3D/geometry.c b/src/part3D/geometry.c index 366c3a6..a30b33b 100644 --- a/src/part3D/geometry.c +++ b/src/part3D/geometry.c @@ -9,72 +9,106 @@ void add_face(Mesh *m, int a, int b, int c, uint8_t col, uint8_t wire) { f->force_wire = wire; } +/* Génère une sphère avec des normales unitaires */ void add_sphere(Mesh *m, fixed x, fixed y, fixed z, fixed r, int det, uint8_t col, uint8_t wire) { - int i, j, v_base; - v_base = m->num_verts; + int i, j, v_base = m->num_verts; + for (j = 0; j <= det; j++) { + fixed phi = (j * 180 / det) % 360; + for (i = 0; i < det; i++) { + fixed th = (i * 360 / det) % 360; + Vector3 *v = &m->verts[m->num_verts]; + Vector3 *n = &m->v_normals[m->num_verts]; - for (j = 0; j <= det; j++) { - fixed sin_phi = sintab[(j * 180 / det) % 360]; - fixed cos_phi = costab[(j * 180 / det) % 360]; - for (i = 0; i < det; i++) { - Vector3 *v = &m->verts[m->num_verts]; - Vector3 *n = &m->v_normals[m->num_verts]; - fixed sin_th = sintab[(i * 360 / det) % 360]; - fixed cos_th = costab[(i * 360 / det) % 360]; + 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, f_mul(sin_phi, cos_th)); - v->y = y + f_mul(r, cos_phi); - v->z = z + f_mul(r, f_mul(sin_phi, sin_th)); - - n->x = f_mul(sin_phi, cos_th); - n->y = cos_phi; - n->z = f_mul(sin_phi, sin_th); - - m->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; - add_face(m, a, b, c, col, wire); - add_face(m, b, d, c, col, wire); - } - } + v->x = x + f_mul(r, n->x); + v->y = y + f_mul(r, n->y); + v->z = z + f_mul(r, n->z); + m->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; + add_face(m, a, b, c, col, wire); + add_face(m, b, d, c, col, wire); + } + } } +/* Génère un cylindre fermé (corps + fonds) avec normales et winding corrects */ void add_cylinder(Mesh *m, fixed x, fixed y, fixed z, fixed r, fixed h, int det, uint8_t col, uint8_t wire) { - int i, v_base; - v_base = m->num_verts; + int i, v_base = m->num_verts; + int cap_bot_center, cap_bot_rim, cap_top_center, cap_top_rim; + fixed half_h = h / 2; + fixed th, s, c; - for (i = 0; i < det; i++) { - Vector3 *v1 = &m->verts[m->num_verts]; - Vector3 *n1 = &m->v_normals[m->num_verts]; - fixed s = sintab[(i * 360 / det) % 360]; - fixed c = costab[(i * 360 / det) % 360]; + /* --- Corps : paires bas/haut, normales radiales --- */ + for (i = 0; i < det; i++) { + th = (i * 360 / det) % 360; + s = sintab[th]; c = costab[th]; - v1->x = x + f_mul(r, c); v1->y = y - h / 2; v1->z = z + f_mul(r, s); - n1->x = c; n1->y = 0; n1->z = s; - m->num_verts++; + m->v_normals[m->num_verts].x = c; m->v_normals[m->num_verts].y = 0; m->v_normals[m->num_verts].z = s; + m->verts[m->num_verts].x = x + f_mul(r, c); m->verts[m->num_verts].y = y - half_h; m->verts[m->num_verts].z = z + f_mul(r, s); + m->num_verts++; - { // Bloc pour v2/n2 - Vector3 *v2 = &m->verts[m->num_verts]; - Vector3 *n2 = &m->v_normals[m->num_verts]; - v2->x = x + f_mul(r, c); v2->y = y + h / 2; v2->z = z + f_mul(r, s); - n2->x = c; n2->y = 0; n2->z = s; - m->num_verts++; - } - } - for (i = 0; i < det; i++) { - int a = v_base + i * 2; - int b = v_base + ((i * 2 + 2) % (det * 2)); - int c = a + 1; - int d = b + 1; - add_face(m, a, b, c, col, wire); - add_face(m, b, d, c, col, wire); - } + m->v_normals[m->num_verts].x = c; m->v_normals[m->num_verts].y = 0; m->v_normals[m->num_verts].z = s; + m->verts[m->num_verts].x = x + f_mul(r, c); m->verts[m->num_verts].y = y + half_h; m->verts[m->num_verts].z = z + f_mul(r, s); + m->num_verts++; + } + + /* Faces corps (winding CCW = cross > 0 pour la face avant) */ + for (i = 0; i < det; i++) { + int a = v_base + (i * 2); + int b = v_base + ((i * 2 + 2) % (det * 2)); + int c_v = a + 1; + int d = b + 1; + add_face(m, a, c_v, b, col, wire); /* bas_i, haut_i, bas_{i+1} */ + add_face(m, c_v, d, b, col, wire); /* haut_i, haut_{i+1}, bas_{i+1} */ + } + + /* --- Fond bas : centre + rebord, normale (0,-1,0) --- */ + cap_bot_center = m->num_verts; + m->v_normals[m->num_verts].x = 0; m->v_normals[m->num_verts].y = -int_to_f(1); m->v_normals[m->num_verts].z = 0; + m->verts[m->num_verts].x = x; m->verts[m->num_verts].y = y - half_h; m->verts[m->num_verts].z = z; + m->num_verts++; + + cap_bot_rim = m->num_verts; + for (i = 0; i < det; i++) { + th = (i * 360 / det) % 360; + s = sintab[th]; c = costab[th]; + m->v_normals[m->num_verts].x = 0; m->v_normals[m->num_verts].y = -int_to_f(1); m->v_normals[m->num_verts].z = 0; + m->verts[m->num_verts].x = x + f_mul(r, c); m->verts[m->num_verts].y = y - half_h; m->verts[m->num_verts].z = z + f_mul(r, s); + m->num_verts++; + } + + for (i = 0; i < det; i++) { + add_face(m, cap_bot_center, cap_bot_rim + i, cap_bot_rim + (i + 1) % det, col, wire); + } + + /* --- Fond haut : centre + rebord, normale (0,+1,0) --- */ + cap_top_center = m->num_verts; + m->v_normals[m->num_verts].x = 0; m->v_normals[m->num_verts].y = int_to_f(1); m->v_normals[m->num_verts].z = 0; + m->verts[m->num_verts].x = x; m->verts[m->num_verts].y = y + half_h; m->verts[m->num_verts].z = z; + m->num_verts++; + + cap_top_rim = m->num_verts; + for (i = 0; i < det; i++) { + th = (i * 360 / det) % 360; + s = sintab[th]; c = costab[th]; + m->v_normals[m->num_verts].x = 0; m->v_normals[m->num_verts].y = int_to_f(1); m->v_normals[m->num_verts].z = 0; + m->verts[m->num_verts].x = x + f_mul(r, c); m->verts[m->num_verts].y = y + half_h; m->verts[m->num_verts].z = z + f_mul(r, s); + m->num_verts++; + } + + for (i = 0; i < det; i++) { + add_face(m, cap_top_center, cap_top_rim + (i + 1) % det, cap_top_rim + i, col, wire); + } } void save_mesh(Mesh *m, const char *fn) { @@ -96,7 +130,6 @@ Mesh* load_mesh(const char *fname) { m = (Mesh*)malloc(sizeof(Mesh)); fread(&m->num_verts, sizeof(int), 1, f); fread(&m->num_faces, sizeof(int), 1, f); - // Suppression de is_wire_only car absent du .h m->verts = (Vector3*)malloc(sizeof(Vector3) * m->num_verts); m->v_normals = (Vector3*)malloc(sizeof(Vector3) * m->num_verts); diff --git a/src/part3D/graph.c b/src/part3D/graph.c index 4138ff1..7680a40 100644 --- a/src/part3D/graph.c +++ b/src/part3D/graph.c @@ -19,6 +19,8 @@ RGB my_palette[16] = { {20, 20, 40} // 15: Bleu nuit }; + + uint8_t *backbuffer = NULL; uint16_t *zbuffer = NULL; uint8_t *vga = (uint8_t *)0xA0000; @@ -74,7 +76,5 @@ void init_vga() { backbuffer = (uint8_t *)malloc(64000); zbuffer = (uint16_t *)malloc(64000 * sizeof(uint16_t)); - // Note : Pense à ajouter ici une boucle pour envoyer my_palette - // aux ports 0x3C8/0x3C9 si tu veux tes couleurs personnalisées. - // setup_vga_palette(my_palette); -} \ No newline at end of file + setup_vga_palette(my_palette); +} diff --git a/src/part3D/raster.c b/src/part3D/raster.c index 408d015..c2d11ec 100644 --- a/src/part3D/raster.c +++ b/src/part3D/raster.c @@ -1,33 +1,7 @@ #include "defines.h" -// Prototypes pour le compilateur C -// extern void scanline_gouraud_asm(int width, uint8_t *dest, uint16_t *zbuf, int z, int dz_step, int intensity, int di_step); - +/* Prototypes pour les fonctions assembleur externes */ extern void scanline_zonly_asm(int width, uint16_t *zbuf, int z, int dz_step); -/* -#pragma aux scanline_gouraud_asm = \ - "test ecx, ecx" \ - "jz done" \ -"loop_l:" \ - "mov eax, edx" \ - "shr eax, 16" /* EAX = Z entier * / \ - "cmp ax, [esi]" \ - "jae skip_p" \ - "mov [esi], ax" /* Z-Write * / \ - "mov eax, ebx" \ - "shr eax, 8" \ - "mov [edi], al" /* Color-Write * / \ -"skip_p:" \ - "add edx, ebp" /* + dz_step (EBP) * / \ - "add ebx, [esp+4]" /* + di_step (LU SUR LA PILE) * / \ - "inc edi" \ - "add esi, 2" \ - "dec ecx" \ - "jnz loop_l" \ -"done:" \ - parm [ecx] [edi] [esi] [edx] [ebp] [ebx] \ - modify [eax ecx edi esi edx ebx]; -*/ #pragma aux scanline_zonly_asm = \ "test ecx, ecx" \ @@ -47,25 +21,22 @@ extern void scanline_zonly_asm(int width, uint16_t *zbuf, int z, int dz_step); parm [ecx] [esi] [edx] [ebx] \ modify [eax ecx esi edx]; - -#include "defines.h" - -// Ajout de base_color en paramètre +/* Rendu d'une ligne avec interpolation Gouraud 16.16 */ void scanline_gouraud_c(int width, uint8_t *dest, uint16_t *zbuf, int z, int dz_step, int intensity, int di_step, uint8_t base_color) { int i; - uint8_t shade; + uint8_t color_offset; + uint8_t shade; + uint16_t zv; - // On calcule le décalage de bloc (ex: couleur 1 commence à l'index 16) - uint8_t color_offset = (uint8_t)(base_color << 4); + color_offset = (uint8_t)(base_color << 4); for (i = 0; i < width; i++) { - uint16_t zv = (uint16_t)(z >> 16); + zv = (uint16_t)(z >> 16); if (zv < zbuf[i]) { zbuf[i] = zv; - // On extrait l'intensité (on travaille en 16.16 pour la précision) + /* Extraction de l'intensité 0-15 depuis le format fixed 16.16 */ shade = (uint8_t)(intensity >> 16); - if (shade > 15) shade = 15; // Sécurité pour ne pas déborder sur la couleur suivante - + if (shade > 15) shade = 15; dest[i] = color_offset + shade; } z += dz_step; @@ -73,194 +44,149 @@ void scanline_gouraud_c(int width, uint8_t *dest, uint16_t *zbuf, int z, int dz_ } } -void draw_line_z(Point2D *p1, Point2D *p2, uint8_t col, int z_test) { - int dx, dy, sx, sy, err, steps, x, y, e2; - fixed z_step, cz; - uint16_t zv; - - dx = abs(p2->x - p1->x); dy = abs(p2->y - p1->y); - sx = (p1->x < p2->x) ? 1 : -1; sy = (p1->y < p2->y) ? 1 : -1; - err = dx - dy; - steps = (dx > dy) ? dx : dy; - z_step = (steps > 0) ? (p2->z - p1->z) / steps : 0; - cz = p1->z; - x = p1->x; y = p1->y; - - while (1) { - if (x >= 0 && x < 320 && y >= 0 && y < 200) { - zv = (uint16_t)f_to_int(cz); - if (!z_test || zv <= zbuffer[y * 320 + x]) { - backbuffer[y * 320 + x] = col; - if (z_test) zbuffer[y * 320 + x] = zv; - } - } - if (x == p2->x && y == p2->y) break; - e2 = 2 * err; - if (e2 > -dy) { err -= dy; x += sx; } - if (e2 < dx) { err += dx; y += sy; } - cz += z_step; - } -} - void swap_pt(Point2D **a, Point2D **b) { - Point2D *t = *a; *a = *b; *b = t; + Point2D *t = *a; *a = *b; *b = t; } void fill_triangle_gouraud(Point2D *p1, Point2D *p2, Point2D *p3, uint8_t base_color) { - int y, total_height, width, start_x, end_x, dz_step, intensity_1, intensity_2, di_step, clip_x, w, start_z, start_i, second_half; - fixed dx13, dz13, di13, xA, zA, iA, xB, zB, iB, dx12, dz12, di12, dx23, dz23, di23, cx1, cz1, ci1, cx2, cz2, ci2, tx, tz, ti; - uint8_t *dest; - uint16_t *zbuf; + /* TOUTES les variables déclarées ici pour le C89 */ + int y, width, start_x, end_x, dz_step, di_step, clip_x, w, start_z, start_i, second_half, total_height; + fixed dx13, dz13, di13, xA, zA, iA, xB, zB, iB, dx12, dz12, di12, dx23, dz23, di23; + fixed cx1, cz1, ci1, cx2, cz2, ci2, tx, tz, ti; + uint8_t *dest; + uint16_t *zbuf; - if (p1->y > p2->y) swap_pt(&p1, &p2); - if (p1->y > p3->y) swap_pt(&p1, &p3); - if (p2->y > p3->y) swap_pt(&p2, &p3); + /* Tri des points par ordonnée (Y) */ + if (p1->y > p2->y) swap_pt(&p1, &p2); + if (p1->y > p3->y) swap_pt(&p1, &p3); + if (p2->y > p3->y) swap_pt(&p2, &p3); - total_height = p3->y - p1->y; - if (total_height == 0) return; + total_height = p3->y - p1->y; + if (total_height == 0) return; - dx13 = ((p3->x - p1->x) << 16) / total_height; - dz13 = (p3->z - p1->z) / total_height; - di13 = ((p3->intensity - p1->intensity) << 16) / total_height; + /* Gradients pour le côté long (p1 vers p3) */ + dx13 = ((p3->x - p1->x) << 16) / total_height; + dz13 = (p3->z - p1->z) / total_height; + di13 = (p3->intensity - p1->intensity) / total_height; - xA = int_to_f(p1->x); zA = p1->z; iA = int_to_f(p1->intensity); - xB = xA; zB = zA; iB = iA; + xA = int_to_f(p1->x); zA = p1->z; iA = p1->intensity; + xB = xA; zB = zA; iB = iA; - dx12 = 0; dz12 = 0; di12 = 0; - dx23 = 0; dz23 = 0; di23 = 0; + /* Gradients pour les côtés courts (p1-p2 puis p2-p3) */ + dx12 = (p2->y > p1->y) ? ((p2->x - p1->x) << 16) / (p2->y - p1->y) : 0; + dz12 = (p2->y > p1->y) ? (p2->z - p1->z) / (p2->y - p1->y) : 0; + di12 = (p2->y > p1->y) ? (p2->intensity - p1->intensity) / (p2->y - p1->y) : 0; - if (p2->y > p1->y) { - dx12 = ((p2->x - p1->x) << 16) / (p2->y - p1->y); - dz12 = (p2->z - p1->z) / (p2->y - p1->y); - di12 = ((p2->intensity - p1->intensity) << 16) / (p2->y - p1->y); - } - if (p3->y > p2->y) { - dx23 = ((p3->x - p2->x) << 16) / (p3->y - p2->y); - dz23 = (p3->z - p2->z) / (p3->y - p2->y); - di23 = ((p3->intensity - p2->intensity) << 16) / (p3->y - p2->y); - } + dx23 = (p3->y > p2->y) ? ((p3->x - p2->x) << 16) / (p3->y - p2->y) : 0; + dz23 = (p3->y > p2->y) ? (p3->z - p2->z) / (p3->y - p2->y) : 0; + di23 = (p3->y > p2->y) ? (p3->intensity - p2->intensity) / (p3->y - p2->y) : 0; - for (y = p1->y; y < p3->y; y++) { - second_half = (y >= p2->y); - cx1 = xA; cz1 = zA; ci1 = iA; - cx2 = xB; cz2 = zB; ci2 = iB; + for (y = p1->y; y < p3->y; y++) { + second_half = (y >= p2->y); + cx1 = xA; cz1 = zA; ci1 = iA; + cx2 = xB; cz2 = zB; ci2 = iB; - if (cx1 > cx2) { - tx = cx1; cx1 = cx2; cx2 = tx; - tz = cz1; cz1 = cz2; cz2 = tz; - ti = ci1; ci1 = ci2; ci2 = ti; - } + /* Tri horizontal pour dessiner de gauche à droite */ + if (cx1 > cx2) { + tx = cx1; cx1 = cx2; cx2 = tx; + tz = cz1; cz1 = cz2; cz2 = tz; + ti = ci1; ci1 = ci2; ci2 = ti; + } - start_x = f_to_int(cx1); end_x = f_to_int(cx2); - width = end_x - start_x; + start_x = f_to_int(cx1); + end_x = f_to_int(cx2); + width = end_x - start_x; - if (y >= 0 && y < 200 && width > 0) { - dz_step = (cz2 - cz1) / width; - // intensity_1 = f_to_int(ci1); - // intensity_2 = f_to_int(ci2); + if (y >= 0 && y < 200 && width > 0) { + dz_step = (cz2 - cz1) / width; + di_step = (ci2 - ci1) / width; - intensity_1 = p1->intensity; - intensity_2 = p2->intensity; + clip_x = (start_x < 0) ? 0 : start_x; + w = width - (clip_x - start_x); + if (clip_x + w > 320) w = 320 - clip_x; - // di_step = ((intensity_2 - intensity_1) << 8) / width; - di_step = (ci2 - ci1) / width; + if (w > 0) { + start_z = cz1 + (clip_x - start_x) * dz_step; + start_i = ci1 + (clip_x - start_x) * di_step; + dest = backbuffer + (y * 320) + clip_x; + zbuf = zbuffer + (y * 320) + clip_x; - clip_x = start_x < 0 ? 0 : start_x; + scanline_gouraud_c(w, dest, zbuf, start_z, dz_step, start_i, di_step, base_color); + } + } - if (clip_x < 320) { - w = width - (clip_x - start_x); - if (clip_x + w > 320) w = 320 - clip_x; - - if (w > 0) { - start_z = cz1 + (clip_x - start_x) * dz_step; - /*start_i = ((base_color + intensity_1) << 8) + (clip_x - start_x) * di_step; - dest = backbuffer + (y * 320) + clip_x; - zbuf = zbuffer + (y * 320) + clip_x; - //scanline_gouraud_asm(w, dest, zbuf, start_z, dz_step, start_i, di_step); - scanline_gouraud_c(w, dest, zbuf, start_z, dz_step, start_i, di_step);*/ - - start_i = ci1 + (clip_x - start_x) * di_step; - - dest = backbuffer + (y * 320) + clip_x; - zbuf = zbuffer + (y * 320) + clip_x; - scanline_gouraud_c(w, dest, zbuf, start_z, dz_step, start_i, di_step, base_color); - } - } - } - - xA += dx13; zA += dz13; iA += di13; - if (!second_half) { - xB += dx12; zB += dz12; iB += di12; - } else { - if (y == p2->y) { xB = int_to_f(p2->x); zB = p2->z; iB = int_to_f(p2->intensity); } - xB += dx23; zB += dz23; iB += di23; - } - } + /* Mise à jour des bords pour la ligne suivante */ + xA += dx13; zA += dz13; iA += di13; + if (!second_half) { + xB += dx12; zB += dz12; iB += di12; + } else { + if (y == p2->y) { + xB = int_to_f(p2->x); zB = p2->z; iB = p2->intensity; + } + xB += dx23; zB += dz23; iB += di23; + } + } } -void fill_triangle_zonly(Point2D *p1, Point2D *p2, Point2D *p3) { - int y, total_height, width, start_x, end_x, dz_step, clip_x, w, start_z, second_half; - fixed dx13, dz13, xA, zA, xB, zB, dx12, dz12, dx23, dz23, cx1, cz1, cx2, cz2, tx, tz; - uint16_t *zbuf; +void draw_line_z(Point2D *p1, Point2D *p2, uint8_t col, int z_test) { + int dx, dy, sx, sy, err, steps, x, y, e2; + fixed z_step, cz; + uint16_t zv; - if (p1->y > p2->y) swap_pt(&p1, &p2); - if (p1->y > p3->y) swap_pt(&p1, &p3); - if (p2->y > p3->y) swap_pt(&p2, &p3); + dx = abs(p2->x - p1->x); dy = abs(p2->y - p1->y); + sx = (p1->x < p2->x) ? 1 : -1; sy = (p1->y < p2->y) ? 1 : -1; + err = dx - dy; + steps = (dx > dy) ? dx : dy; + z_step = (steps > 0) ? (p2->z - p1->z) / steps : 0; + cz = p1->z; + x = p1->x; y = p1->y; - total_height = p3->y - p1->y; - if (total_height == 0) return; - - dx13 = ((p3->x - p1->x) << 16) / total_height; - dz13 = (p3->z - p1->z) / total_height; - - xA = int_to_f(p1->x); zA = p1->z; - xB = xA; zB = zA; - - dx12 = 0; dz12 = 0; dx23 = 0; dz23 = 0; - - if (p2->y > p1->y) { - dx12 = ((p2->x - p1->x) << 16) / (p2->y - p1->y); - dz12 = (p2->z - p1->z) / (p2->y - p1->y); - } - if (p3->y > p2->y) { - dx23 = ((p3->x - p2->x) << 16) / (p3->y - p2->y); - dz23 = (p3->z - p2->z) / (p3->y - p2->y); - } - - for (y = p1->y; y < p3->y; y++) { - second_half = (y >= p2->y); - cx1 = xA; cz1 = zA; cx2 = xB; cz2 = zB; - - if (cx1 > cx2) { - tx = cx1; cx1 = cx2; cx2 = tx; - tz = cz1; cz1 = cz2; cz2 = tz; - } - - start_x = f_to_int(cx1); end_x = f_to_int(cx2); - width = end_x - start_x; - - if (y >= 0 && y < 200 && width > 0) { - dz_step = (cz2 - cz1) / width; - clip_x = start_x < 0 ? 0 : start_x; - - if (clip_x < 320) { - w = width - (clip_x - start_x); - if (clip_x + w > 320) w = 320 - clip_x; - - if (w > 0) { - start_z = cz1 + (clip_x - start_x) * dz_step; - zbuf = zbuffer + (y * 320) + clip_x; - scanline_zonly_asm(w, zbuf, start_z, dz_step); - } - } - } - - xA += dx13; zA += dz13; - if (!second_half) { - xB += dx12; zB += dz12; - } else { - if (y == p2->y) { xB = int_to_f(p2->x); zB = p2->z; } - xB += dx23; zB += dz23; - } - } + while (1) { + if (x >= 0 && x < 320 && y >= 0 && y < 200) { + zv = (uint16_t)f_to_int(cz); + if (!z_test || zv <= zbuffer[y * 320 + x]) { + backbuffer[y * 320 + x] = col; + if (z_test) zbuffer[y * 320 + x] = zv; + } + } + if (x == p2->x && y == p2->y) break; + e2 = 2 * err; + if (e2 > -dy) { err -= dy; x += sx; } + if (e2 < dx) { err += dx; y += sy; } + cz += z_step; + } } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +