#include "defines.h" /* Rendu d'une scanline avec interpolation Gouraud 16.16 */ void scanline_gouraud_c(int width, uint8_t *dest, uint16_t *zbuf, fixed z, fixed dz_step, fixed intensity, fixed di_step, uint8_t base_color) { int i; int s; uint8_t shade; uint8_t color_offset; uint16_t zv; color_offset = (uint8_t)(base_color << 4); for (i = 0; i < width; i++) { zv = (uint16_t)(z >> 16); if (zv < zbuf[i]) { zbuf[i] = zv; s = intensity >> 16; if (s < 0) shade = 0; else if (s > 15) shade = 15; else shade = (uint8_t)s; dest[i] = color_offset + shade; } z += dz_step; intensity += di_step; } } void swap_pt(Point2D **a, Point2D **b) { Point2D *t = *a; *a = *b; *b = t; } void fill_triangle_gouraud(Point2D *p1, Point2D *p2, Point2D *p3, uint8_t base_color) { /* TOUTES les variables déclarées ici pour le C89 */ int y, width, start_x, end_x, clip_x, w, 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; fixed dz_step, di_step, start_z, start_i; uint8_t *dest; uint16_t *zbuf; /* 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; /* 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 = p1->intensity; /* Sommet plat en haut : xB part de p2, pas de p1 */ if (p1->y == p2->y) { xB = int_to_f(p2->x); zB = p2->z; iB = p2->intensity; } else { xB = xA; zB = zA; iB = iA; } /* 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; 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; /* 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) + 1; /* ceil : couvre le pixel de bord droit fractionnaire */ width = end_x - start_x; if (y >= 0 && y < SCREEN_H && width > 0) { dz_step = (cz2 - cz1) / width; di_step = (ci2 - ci1) / width; clip_x = (start_x < 0) ? 0 : start_x; w = width - (clip_x - start_x); if (clip_x + w > SCREEN_W) w = SCREEN_W - clip_x; if (w > 0) { start_z = cz1 + (clip_x - start_x) * dz_step; start_i = ci1 + (clip_x - start_x) * di_step; dest = backbuffer + (y * SCREEN_W) + clip_x; zbuf = zbuffer + (y * SCREEN_W) + clip_x; scanline_gouraud_c(w, dest, zbuf, start_z, dz_step, start_i, di_step, base_color); } } /* 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 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 < SCREEN_W && y >= 0 && y < SCREEN_H) { zv = (uint16_t)f_to_int(cz); if (!z_test || zv < zbuffer[y * SCREEN_W + x]) { backbuffer[y * SCREEN_W + x] = col; if (z_test) zbuffer[y * SCREEN_W + 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; } }