fixed
This commit is contained in:
parent
eae91de89d
commit
c6d6f787f7
8 changed files with 667 additions and 485 deletions
4
Makefile
4
Makefile
|
|
@ -84,5 +84,5 @@ clean:
|
||||||
rm -f *.err src/**/*.err
|
rm -f *.err src/**/*.err
|
||||||
|
|
||||||
cleanall:
|
cleanall:
|
||||||
clean
|
$(MAKE) clean
|
||||||
all
|
$(MAKE) all
|
||||||
187
WORKDOC.md
Normal file
187
WORKDOC.md
Normal file
|
|
@ -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`. |
|
||||||
159
src/main/main.c
159
src/main/main.c
|
|
@ -1,76 +1,129 @@
|
||||||
#include "../part3D/defines.h"
|
#include "../part3D/defines.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Allocation initiale large pour accumulation
|
Mesh m_sphere, m_cyl;
|
||||||
Mesh scene;
|
Object3D universe[2];
|
||||||
Matrix3 rot, tmpX, tmpY;
|
Camera cam;
|
||||||
int angX = 0, angY = 0;
|
Matrix3 rotX, rotY, orbit;
|
||||||
int key = 0;
|
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));
|
m_cyl.verts = (Vector3*)malloc(MAX_VERTEX * sizeof(Vector3));
|
||||||
scene.v_normals = (Vector3*)malloc(MAX_VERTEX*sizeof(Vector3));
|
m_cyl.v_normals = (Vector3*)malloc(MAX_VERTEX * sizeof(Vector3));
|
||||||
scene.faces = (Face*)malloc(MAX_FACES*sizeof(Face));
|
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) {
|
if (!m_sphere.verts || !m_sphere.v_normals || !m_sphere.faces ||
|
||||||
printf("Erreur : Memoire insuffisante pour le Mesh.\n");
|
!m_cyl.verts || !m_cyl.v_normals || !m_cyl.faces) return 1;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
scene.num_verts = 0;
|
/* Génération en 0,0,0 (Espace Local) */
|
||||||
scene.num_faces = 0;
|
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
|
/* Configuration des objets dans l'univers */
|
||||||
add_cylinder(&scene, int_to_f(-50), 0, int_to_f(300), int_to_f(20), int_to_f(80), 16, 2, 0); // Plein
|
universe[0].mesh = &m_sphere;
|
||||||
add_sphere(&scene, int_to_f(50), 0, int_to_f(300), int_to_f(30), 12, 4, 1); // Toujours filaire
|
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();
|
universe[1].mesh = &m_cyl;
|
||||||
mat3_identity(&rot);
|
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()) {
|
if (kbhit()) {
|
||||||
key = getch();
|
key = getch();
|
||||||
// Gestion ZQSD (Sensibilité de 5 degrés)
|
switch (key) {
|
||||||
if (key == 'z' || key == 'Z') angX = (angX + 5) % 360;
|
case 'Z':
|
||||||
if (key == 's' || key == 'S') angX = (angX + 355) % 360;
|
case 'z':
|
||||||
if (key == 'q' || key == 'Q') angY = (angY + 355) % 360;
|
cam.pos.z += int_to_f(10);
|
||||||
if (key == 'd' || key == 'D') angY = (angY + 5) % 360;
|
break;
|
||||||
|
|
||||||
// Reconstruction de la matrice de rotation combinée
|
case 'S':
|
||||||
mat3_rotate_x(&tmpX, angX);
|
case 's':
|
||||||
mat3_rotate_y(&tmpY, angY);
|
cam.pos.z -= int_to_f(10);
|
||||||
mat3_mul(&rot, &tmpX, &tmpY);
|
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);
|
clear_buffers(0);
|
||||||
render_scene(&scene, &rot, MODE_WIRE);
|
render_universe(universe, 2, &cam, MODE_SOLID);
|
||||||
flip();
|
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();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -8,99 +8,89 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
|
|
||||||
#define MODE_WIRE 0 // Transparent totalv_cache
|
#define MODE_WIRE 0
|
||||||
#define MODE_HIDDEN 1 // Fil de fer avec surfaces cachées
|
#define MODE_HIDDEN 1
|
||||||
#define MODE_SOLID 2 // Plein (Gouraud)
|
#define MODE_SOLID 2
|
||||||
|
|
||||||
#define MAX_VERTEX 5000
|
#define MAX_VERTEX 5000
|
||||||
#define MAX_FACES 8000
|
#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;
|
typedef int32_t fixed;
|
||||||
|
|
||||||
#define f_to_int(a) ((a) >> 16)
|
#define f_to_int(a) ((a) >> 16)
|
||||||
#define int_to_f(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_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); }
|
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 {
|
typedef struct { fixed x, y, z; } Vector3;
|
||||||
fixed m[3][3];
|
typedef struct { int a, b, c; uint8_t color; uint8_t force_wire; } Face;
|
||||||
} Matrix3;
|
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 {
|
typedef struct {
|
||||||
int a, b, c;
|
Mesh *mesh;
|
||||||
uint8_t color;
|
Vector3 pos;
|
||||||
uint8_t force_wire;
|
Matrix3 rot;
|
||||||
} Face;
|
uint8_t color;
|
||||||
|
|
||||||
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
|
|
||||||
} Object3D;
|
} Object3D;
|
||||||
|
|
||||||
typedef struct { uint8_t r, g, b; } RGB;
|
typedef struct {
|
||||||
|
Vector3 pos;
|
||||||
|
} Camera;
|
||||||
|
|
||||||
// --- Ajout des déclarations de tables ---
|
/* Globales */
|
||||||
extern fixed sintab[360];
|
extern fixed sintab[360], costab[360];
|
||||||
extern fixed costab[360];
|
|
||||||
extern fixed inv_table[321];
|
|
||||||
extern Point2D v_cache[MAX_VERTEX];
|
extern Point2D v_cache[MAX_VERTEX];
|
||||||
extern uint8_t *backbuffer;
|
extern uint8_t *backbuffer;
|
||||||
extern uint16_t *zbuffer;
|
extern uint16_t *zbuffer;
|
||||||
extern uint8_t *vga;
|
extern uint8_t *vga;
|
||||||
|
|
||||||
// Engine.C
|
/* Prototypes */
|
||||||
void init_engine_math();
|
void init_engine_math(void);
|
||||||
void normalize(Vector3 *v);
|
void mat3_identity(Matrix3 *mat);
|
||||||
void mat3_rotate_x(Matrix3 *m, int angle);
|
void mat3_rotate_x(Matrix3 *m, int angle);
|
||||||
void mat3_rotate_y(Matrix3 *m, int angle);
|
void mat3_rotate_y(Matrix3 *m, int angle);
|
||||||
void mat3_mul(Matrix3 *res, Matrix3 *a, Matrix3 *b);
|
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_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 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 render_universe(Object3D *objs, int num_objs, Camera *cam, int mode);
|
||||||
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);
|
|
||||||
|
|
||||||
// Graph.c
|
void init_vga(void);
|
||||||
void init_vga();
|
|
||||||
void clear_buffers(uint8_t color);
|
void clear_buffers(uint8_t color);
|
||||||
void flip();
|
void flip(void);
|
||||||
void close_vga();
|
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 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
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
fixed sintab[360], costab[360], inv_table[321];
|
fixed sintab[360], costab[360];
|
||||||
Point2D v_cache[MAX_VERTEX];
|
Point2D v_cache[MAX_VERTEX];
|
||||||
|
|
||||||
void mat3_identity(Matrix3 *mat) {
|
void mat3_identity(Matrix3 *mat) {
|
||||||
|
|
@ -10,17 +10,13 @@ void mat3_identity(Matrix3 *mat) {
|
||||||
|
|
||||||
void init_engine_math() {
|
void init_engine_math() {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 360; i++) {
|
for (i = 0; i < 360; i++) {
|
||||||
double r = (double)i * 3.14159265 / 180.0;
|
double r = (double)i * 3.14159265 / 180.0;
|
||||||
sintab[i] = (fixed)(sin(r) * 65536.0);
|
sintab[i] = (fixed)(sin(r) * 65536.0);
|
||||||
costab[i] = (fixed)(cos(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) {
|
void normalize(Vector3 *v) {
|
||||||
double dx = (double)v->x, dy = (double)v->y, dz = (double)v->z;
|
double dx = (double)v->x, dy = (double)v->y, dz = (double)v->z;
|
||||||
double d = sqrt(dx*dx + dy*dy + dz*dz);
|
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) {
|
void mat3_mul(Matrix3 *res, Matrix3 *a, Matrix3 *b) {
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i < 3; i++) {
|
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) {
|
void mat3_rotate_x(Matrix3 *m, int angle) {
|
||||||
int i;
|
int a = ((angle % 360) + 360) % 360;
|
||||||
fixed pz, rx, ry, rz;
|
fixed c = costab[a], s = sintab[a];
|
||||||
Vector3 *v;
|
mat3_identity(m);
|
||||||
Vector3 *n;
|
m->m[1][1] = c; m->m[1][2] = -s; m->m[2][1] = s; m->m[2][2] = c;
|
||||||
fixed nz;
|
}
|
||||||
int intensity;
|
|
||||||
|
|
||||||
|
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++) {
|
void render_universe(Object3D *objs, int num_objs, Camera *cam, int mode) {
|
||||||
v = &m->verts[i];
|
int o, i, front;
|
||||||
n = &m->v_normals[i];
|
fixed rx, ry, rz, pz, nz;
|
||||||
|
uint8_t wire_col;
|
||||||
|
|
||||||
// --- 1. Rotation de la normale (pour la lumière) ---
|
for (o = 0; o < num_objs; o++) {
|
||||||
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]);
|
Object3D *obj = &objs[o];
|
||||||
intensity = f_to_int(nz * 15);
|
Mesh *m = obj->mesh;
|
||||||
if (intensity < 0) intensity = 0;
|
|
||||||
|
|
||||||
// --- 2. Rotation du sommet (LA PIÈCE MANQUANTE) ---
|
for (i = 0; i < m->num_verts; i++) {
|
||||||
// On applique la multiplication Matrice * Vecteur
|
Vector3 *v = &m->verts[i], *n = &m->v_normals[i];
|
||||||
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]);
|
|
||||||
|
|
||||||
// --- 3. Projection avec les coordonnées tournées ---
|
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;
|
||||||
pz = rz; // On utilise le Z tourné
|
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;
|
||||||
if (pz < int_to_f(10)) pz = int_to_f(10);
|
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;
|
pz = (rz < int_to_f(20)) ? int_to_f(20) : rz;
|
||||||
v_cache[i].intensity = intensity;
|
v_cache[i].z = pz;
|
||||||
v_cache[i].x = 160 + f_to_int(f_div(rx << 8, pz)); // On utilise rx tourné
|
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)); // On utilise ry tourné
|
v_cache[i].y = 100 - f_to_int(f_div(ry << 8, pz));
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < m->num_faces; i++) {
|
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]);
|
||||||
Face *f = &m->faces[i];
|
v_cache[i].intensity = (nz >= 0) ? int_to_f(1) : ((-nz) * 14) + int_to_f(1);
|
||||||
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);
|
|
||||||
|
|
||||||
if (global_mode == MODE_WIRE) {
|
wire_col = (uint8_t)((obj->color << 4) | 15);
|
||||||
draw_line_z(p1, p2, f->color, 0);
|
|
||||||
draw_line_z(p2, p3, f->color, 0);
|
for (i = 0; i < m->num_faces; i++) {
|
||||||
draw_line_z(p3, p1, f->color, 0);
|
Face *f = &m->faces[i];
|
||||||
} else {
|
Point2D *p1 = &v_cache[f->a], *p2 = &v_cache[f->b], *p3 = &v_cache[f->c];
|
||||||
if (back < 0) {
|
front = ((p2->x - p1->x) * (p3->y - p1->y) - (p2->y - p1->y) * (p3->x - p1->x)) > 0;
|
||||||
if (f->force_wire || global_mode == MODE_HIDDEN) {
|
|
||||||
fill_triangle_zonly(p1, p2, p3);
|
switch (mode) {
|
||||||
draw_line_z(p1, p2, f->color, 1);
|
case MODE_WIRE:
|
||||||
draw_line_z(p2, p3, f->color, 1);
|
draw_line_z(p1, p2, wire_col, 0);
|
||||||
draw_line_z(p3, p1, f->color, 1); // Ajouté pour fermer le triangle
|
draw_line_z(p2, p3, wire_col, 0);
|
||||||
} else {
|
draw_line_z(p3, p1, wire_col, 0);
|
||||||
fill_triangle_gouraud(p1, p2, p3, f->color);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
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) {
|
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;
|
int i, j, v_base = m->num_verts;
|
||||||
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++) {
|
n->x = f_mul(sintab[phi], costab[th]);
|
||||||
fixed sin_phi = sintab[(j * 180 / det) % 360];
|
n->y = costab[phi];
|
||||||
fixed cos_phi = costab[(j * 180 / det) % 360];
|
n->z = f_mul(sintab[phi], sintab[th]);
|
||||||
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];
|
|
||||||
|
|
||||||
v->x = x + f_mul(r, f_mul(sin_phi, cos_th));
|
v->x = x + f_mul(r, n->x);
|
||||||
v->y = y + f_mul(r, cos_phi);
|
v->y = y + f_mul(r, n->y);
|
||||||
v->z = z + f_mul(r, f_mul(sin_phi, sin_th));
|
v->z = z + f_mul(r, n->z);
|
||||||
|
m->num_verts++;
|
||||||
n->x = f_mul(sin_phi, cos_th);
|
}
|
||||||
n->y = cos_phi;
|
}
|
||||||
n->z = f_mul(sin_phi, sin_th);
|
for (j = 0; j < det; j++) {
|
||||||
|
for (i = 0; i < det; i++) {
|
||||||
m->num_verts++;
|
int a = v_base + j * det + i;
|
||||||
}
|
int b = v_base + j * det + (i + 1) % det;
|
||||||
}
|
int c = v_base + (j + 1) * det + i;
|
||||||
for (j = 0; j < det; j++) {
|
int d = v_base + (j + 1) * det + (i + 1) % det;
|
||||||
for (i = 0; i < det; i++) {
|
add_face(m, a, b, c, col, wire);
|
||||||
int a = v_base + j * det + i;
|
add_face(m, b, d, c, col, wire);
|
||||||
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) {
|
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;
|
int i, v_base = m->num_verts;
|
||||||
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++) {
|
/* --- Corps : paires bas/haut, normales radiales --- */
|
||||||
Vector3 *v1 = &m->verts[m->num_verts];
|
for (i = 0; i < det; i++) {
|
||||||
Vector3 *n1 = &m->v_normals[m->num_verts];
|
th = (i * 360 / det) % 360;
|
||||||
fixed s = sintab[(i * 360 / det) % 360];
|
s = sintab[th]; c = costab[th];
|
||||||
fixed c = costab[(i * 360 / det) % 360];
|
|
||||||
|
|
||||||
v1->x = x + f_mul(r, c); v1->y = y - h / 2; v1->z = z + f_mul(r, s);
|
m->v_normals[m->num_verts].x = c; m->v_normals[m->num_verts].y = 0; m->v_normals[m->num_verts].z = s;
|
||||||
n1->x = c; n1->y = 0; n1->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++;
|
m->num_verts++;
|
||||||
|
|
||||||
{ // Bloc pour v2/n2
|
m->v_normals[m->num_verts].x = c; m->v_normals[m->num_verts].y = 0; m->v_normals[m->num_verts].z = s;
|
||||||
Vector3 *v2 = &m->verts[m->num_verts];
|
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);
|
||||||
Vector3 *n2 = &m->v_normals[m->num_verts];
|
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++;
|
/* Faces corps (winding CCW = cross > 0 pour la face avant) */
|
||||||
}
|
for (i = 0; i < det; i++) {
|
||||||
}
|
int a = v_base + (i * 2);
|
||||||
for (i = 0; i < det; i++) {
|
int b = v_base + ((i * 2 + 2) % (det * 2));
|
||||||
int a = v_base + i * 2;
|
int c_v = a + 1;
|
||||||
int b = v_base + ((i * 2 + 2) % (det * 2));
|
int d = b + 1;
|
||||||
int c = a + 1;
|
add_face(m, a, c_v, b, col, wire); /* bas_i, haut_i, bas_{i+1} */
|
||||||
int d = b + 1;
|
add_face(m, c_v, d, b, col, wire); /* haut_i, haut_{i+1}, bas_{i+1} */
|
||||||
add_face(m, a, b, c, col, wire);
|
}
|
||||||
add_face(m, b, d, c, col, wire);
|
|
||||||
}
|
/* --- 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) {
|
void save_mesh(Mesh *m, const char *fn) {
|
||||||
|
|
@ -96,7 +130,6 @@ Mesh* load_mesh(const char *fname) {
|
||||||
m = (Mesh*)malloc(sizeof(Mesh));
|
m = (Mesh*)malloc(sizeof(Mesh));
|
||||||
fread(&m->num_verts, sizeof(int), 1, f);
|
fread(&m->num_verts, sizeof(int), 1, f);
|
||||||
fread(&m->num_faces, 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->verts = (Vector3*)malloc(sizeof(Vector3) * m->num_verts);
|
||||||
m->v_normals = (Vector3*)malloc(sizeof(Vector3) * m->num_verts);
|
m->v_normals = (Vector3*)malloc(sizeof(Vector3) * m->num_verts);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ RGB my_palette[16] = {
|
||||||
{20, 20, 40} // 15: Bleu nuit
|
{20, 20, 40} // 15: Bleu nuit
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t *backbuffer = NULL;
|
uint8_t *backbuffer = NULL;
|
||||||
uint16_t *zbuffer = NULL;
|
uint16_t *zbuffer = NULL;
|
||||||
uint8_t *vga = (uint8_t *)0xA0000;
|
uint8_t *vga = (uint8_t *)0xA0000;
|
||||||
|
|
@ -74,7 +76,5 @@ void init_vga() {
|
||||||
backbuffer = (uint8_t *)malloc(64000);
|
backbuffer = (uint8_t *)malloc(64000);
|
||||||
zbuffer = (uint16_t *)malloc(64000 * sizeof(uint16_t));
|
zbuffer = (uint16_t *)malloc(64000 * sizeof(uint16_t));
|
||||||
|
|
||||||
// Note : Pense à ajouter ici une boucle pour envoyer my_palette
|
setup_vga_palette(my_palette);
|
||||||
// aux ports 0x3C8/0x3C9 si tu veux tes couleurs personnalisées.
|
|
||||||
// setup_vga_palette(my_palette);
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,33 +1,7 @@
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
// Prototypes pour le compilateur C
|
/* Prototypes pour les fonctions assembleur externes */
|
||||||
// extern void scanline_gouraud_asm(int width, uint8_t *dest, uint16_t *zbuf, int z, int dz_step, int intensity, int di_step);
|
|
||||||
|
|
||||||
extern void scanline_zonly_asm(int width, uint16_t *zbuf, int z, int dz_step);
|
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 = \
|
#pragma aux scanline_zonly_asm = \
|
||||||
"test ecx, ecx" \
|
"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] \
|
parm [ecx] [esi] [edx] [ebx] \
|
||||||
modify [eax ecx esi edx];
|
modify [eax ecx esi edx];
|
||||||
|
|
||||||
|
/* Rendu d'une ligne avec interpolation Gouraud 16.16 */
|
||||||
#include "defines.h"
|
|
||||||
|
|
||||||
// Ajout de base_color en paramètre
|
|
||||||
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) {
|
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;
|
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)
|
color_offset = (uint8_t)(base_color << 4);
|
||||||
uint8_t color_offset = (uint8_t)(base_color << 4);
|
|
||||||
|
|
||||||
for (i = 0; i < width; i++) {
|
for (i = 0; i < width; i++) {
|
||||||
uint16_t zv = (uint16_t)(z >> 16);
|
zv = (uint16_t)(z >> 16);
|
||||||
if (zv < zbuf[i]) {
|
if (zv < zbuf[i]) {
|
||||||
zbuf[i] = zv;
|
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);
|
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;
|
dest[i] = color_offset + shade;
|
||||||
}
|
}
|
||||||
z += dz_step;
|
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) {
|
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) {
|
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;
|
/* TOUTES les variables déclarées ici pour le C89 */
|
||||||
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;
|
int y, width, start_x, end_x, dz_step, di_step, clip_x, w, start_z, start_i, second_half, total_height;
|
||||||
uint8_t *dest;
|
fixed dx13, dz13, di13, xA, zA, iA, xB, zB, iB, dx12, dz12, di12, dx23, dz23, di23;
|
||||||
uint16_t *zbuf;
|
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);
|
/* Tri des points par ordonnée (Y) */
|
||||||
if (p1->y > p3->y) swap_pt(&p1, &p3);
|
if (p1->y > p2->y) swap_pt(&p1, &p2);
|
||||||
if (p2->y > p3->y) swap_pt(&p2, &p3);
|
if (p1->y > p3->y) swap_pt(&p1, &p3);
|
||||||
|
if (p2->y > p3->y) swap_pt(&p2, &p3);
|
||||||
|
|
||||||
total_height = p3->y - p1->y;
|
total_height = p3->y - p1->y;
|
||||||
if (total_height == 0) return;
|
if (total_height == 0) return;
|
||||||
|
|
||||||
dx13 = ((p3->x - p1->x) << 16) / total_height;
|
/* Gradients pour le côté long (p1 vers p3) */
|
||||||
dz13 = (p3->z - p1->z) / total_height;
|
dx13 = ((p3->x - p1->x) << 16) / total_height;
|
||||||
di13 = ((p3->intensity - p1->intensity) << 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);
|
xA = int_to_f(p1->x); zA = p1->z; iA = p1->intensity;
|
||||||
xB = xA; zB = zA; iB = iA;
|
xB = xA; zB = zA; iB = iA;
|
||||||
|
|
||||||
dx12 = 0; dz12 = 0; di12 = 0;
|
/* Gradients pour les côtés courts (p1-p2 puis p2-p3) */
|
||||||
dx23 = 0; dz23 = 0; di23 = 0;
|
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) {
|
dx23 = (p3->y > p2->y) ? ((p3->x - p2->x) << 16) / (p3->y - p2->y) : 0;
|
||||||
dx12 = ((p2->x - p1->x) << 16) / (p2->y - p1->y);
|
dz23 = (p3->y > p2->y) ? (p3->z - p2->z) / (p3->y - p2->y) : 0;
|
||||||
dz12 = (p2->z - p1->z) / (p2->y - p1->y);
|
di23 = (p3->y > p2->y) ? (p3->intensity - p2->intensity) / (p3->y - p2->y) : 0;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (y = p1->y; y < p3->y; y++) {
|
for (y = p1->y; y < p3->y; y++) {
|
||||||
second_half = (y >= p2->y);
|
second_half = (y >= p2->y);
|
||||||
cx1 = xA; cz1 = zA; ci1 = iA;
|
cx1 = xA; cz1 = zA; ci1 = iA;
|
||||||
cx2 = xB; cz2 = zB; ci2 = iB;
|
cx2 = xB; cz2 = zB; ci2 = iB;
|
||||||
|
|
||||||
if (cx1 > cx2) {
|
/* Tri horizontal pour dessiner de gauche à droite */
|
||||||
tx = cx1; cx1 = cx2; cx2 = tx;
|
if (cx1 > cx2) {
|
||||||
tz = cz1; cz1 = cz2; cz2 = tz;
|
tx = cx1; cx1 = cx2; cx2 = tx;
|
||||||
ti = ci1; ci1 = ci2; ci2 = ti;
|
tz = cz1; cz1 = cz2; cz2 = tz;
|
||||||
}
|
ti = ci1; ci1 = ci2; ci2 = ti;
|
||||||
|
}
|
||||||
|
|
||||||
start_x = f_to_int(cx1); end_x = f_to_int(cx2);
|
start_x = f_to_int(cx1);
|
||||||
width = end_x - start_x;
|
end_x = f_to_int(cx2);
|
||||||
|
width = end_x - start_x;
|
||||||
|
|
||||||
if (y >= 0 && y < 200 && width > 0) {
|
if (y >= 0 && y < 200 && width > 0) {
|
||||||
dz_step = (cz2 - cz1) / width;
|
dz_step = (cz2 - cz1) / width;
|
||||||
// intensity_1 = f_to_int(ci1);
|
di_step = (ci2 - ci1) / width;
|
||||||
// intensity_2 = f_to_int(ci2);
|
|
||||||
|
|
||||||
intensity_1 = p1->intensity;
|
clip_x = (start_x < 0) ? 0 : start_x;
|
||||||
intensity_2 = p2->intensity;
|
w = width - (clip_x - start_x);
|
||||||
|
if (clip_x + w > 320) w = 320 - clip_x;
|
||||||
|
|
||||||
// di_step = ((intensity_2 - intensity_1) << 8) / width;
|
if (w > 0) {
|
||||||
di_step = (ci2 - ci1) / width;
|
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) {
|
/* Mise à jour des bords pour la ligne suivante */
|
||||||
w = width - (clip_x - start_x);
|
xA += dx13; zA += dz13; iA += di13;
|
||||||
if (clip_x + w > 320) w = 320 - clip_x;
|
if (!second_half) {
|
||||||
|
xB += dx12; zB += dz12; iB += di12;
|
||||||
if (w > 0) {
|
} else {
|
||||||
start_z = cz1 + (clip_x - start_x) * dz_step;
|
if (y == p2->y) {
|
||||||
/*start_i = ((base_color + intensity_1) << 8) + (clip_x - start_x) * di_step;
|
xB = int_to_f(p2->x); zB = p2->z; iB = p2->intensity;
|
||||||
dest = backbuffer + (y * 320) + clip_x;
|
}
|
||||||
zbuf = zbuffer + (y * 320) + clip_x;
|
xB += dx23; zB += dz23; iB += di23;
|
||||||
//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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_triangle_zonly(Point2D *p1, Point2D *p2, Point2D *p3) {
|
void draw_line_z(Point2D *p1, Point2D *p2, uint8_t col, int z_test) {
|
||||||
int y, total_height, width, start_x, end_x, dz_step, clip_x, w, start_z, second_half;
|
int dx, dy, sx, sy, err, steps, x, y, e2;
|
||||||
fixed dx13, dz13, xA, zA, xB, zB, dx12, dz12, dx23, dz23, cx1, cz1, cx2, cz2, tx, tz;
|
fixed z_step, cz;
|
||||||
uint16_t *zbuf;
|
uint16_t zv;
|
||||||
|
|
||||||
if (p1->y > p2->y) swap_pt(&p1, &p2);
|
dx = abs(p2->x - p1->x); dy = abs(p2->y - p1->y);
|
||||||
if (p1->y > p3->y) swap_pt(&p1, &p3);
|
sx = (p1->x < p2->x) ? 1 : -1; sy = (p1->y < p2->y) ? 1 : -1;
|
||||||
if (p2->y > p3->y) swap_pt(&p2, &p3);
|
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;
|
while (1) {
|
||||||
if (total_height == 0) return;
|
if (x >= 0 && x < 320 && y >= 0 && y < 200) {
|
||||||
|
zv = (uint16_t)f_to_int(cz);
|
||||||
dx13 = ((p3->x - p1->x) << 16) / total_height;
|
if (!z_test || zv <= zbuffer[y * 320 + x]) {
|
||||||
dz13 = (p3->z - p1->z) / total_height;
|
backbuffer[y * 320 + x] = col;
|
||||||
|
if (z_test) zbuffer[y * 320 + x] = zv;
|
||||||
xA = int_to_f(p1->x); zA = p1->z;
|
}
|
||||||
xB = xA; zB = zA;
|
}
|
||||||
|
if (x == p2->x && y == p2->y) break;
|
||||||
dx12 = 0; dz12 = 0; dx23 = 0; dz23 = 0;
|
e2 = 2 * err;
|
||||||
|
if (e2 > -dy) { err -= dy; x += sx; }
|
||||||
if (p2->y > p1->y) {
|
if (e2 < dx) { err += dx; y += sy; }
|
||||||
dx12 = ((p2->x - p1->x) << 16) / (p2->y - p1->y);
|
cz += z_step;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue