dos-3D-Engine/src/part3D/raster.c
2026-05-10 11:49:01 +02:00

147 lines
5 KiB
C

#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;
}
}