147 lines
5 KiB
C
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;
|
|
}
|
|
}
|