#include "face.h" #include "texture.h" #include "zbuffer.h" #include #include #define min(x,y) (xy?x:y) #define abs(x) (x>0?x:-x) static bool sens_horaire(FE_face const * face) { int area = 0; area+=face->s1->translated.x*face->s2->translated.y; area-=face->s2->translated.x*face->s1->translated.y; area+=face->s2->translated.x*face->s3->translated.y; area-=face->s3->translated.x*face->s2->translated.y; area+=face->s3->translated.x*face->s1->translated.y; area-=face->s1->translated.x*face->s3->translated.y; return (area < 0); } // gestion des lignes typedef struct line line; struct line { int x,y,z; int dx,dy,dz; bool no_line; // si les deux points sont confondus }; static void set_line(line* segment,FE_point const * s1, FE_point const * s2) { segment->x=s1->translated.x; segment->y=s1->translated.y; segment->z=s1->translated.z; segment->dx=s2->translated.x-s1->translated.x; segment->dy=s2->translated.y-s1->translated.y; segment->dz=s2->translated.z-s1->translated.z; segment->no_line=(segment->dx==0&&segment->dy==0); } static bool get_x(int y, line const * segment, int * x) { y-=segment->y; if (y<0 && segment->dy>0) return false; if (y>0 && segment->dy<0) return false; if (abs(y)>abs(segment->dy)) return false; if (segment->dy!=0) *x=segment->x+(y*segment->dx)/segment->dy; else if (y==0) *x=segment->x+segment->dx; else return false; return true; } void FE_draw_face(FE_face const * face) { if (sens_horaire(face)!=face->visible) return; if (face->s1->translated.x<0 && face->s2->translated.x<0 && face->s3->translated.x<0) return; if (face->s1->translated.x>127 && face->s2->translated.x>127 && face->s3->translated.x>127) return; if (face->s1->translated.y<0 && face->s2->translated.y<0 && face->s3->translated.y<0) return; if (face->s1->translated.y>63 && face->s2->translated.y>63 && face->s3->translated.y>63) return; if (face->s1->translated.z<=0 && face->s2->translated.z<=0 && face->s3->translated.z<=0) return; line cotes[3]; set_line(&cotes[0],face->s1,face->s2); set_line(&cotes[1],face->s1,face->s3); set_line(&cotes[2],face->s2,face->s3); if (cotes[0].no_line||cotes[1].no_line||cotes[2].no_line) return; const int ymin=max(min(face->s1->translated.y,min(face->s2->translated.y,face->s3->translated.y)),0); const int ymax=min(max(face->s1->translated.y,max(face->s2->translated.y,face->s3->translated.y)),63); const int xAB=face->s2->translated.x-face->s1->translated.x, yAB=face->s2->translated.y-face->s1->translated.y, zAB=face->s2->translated.z-face->s1->translated.z; const int xAC=face->s3->translated.x-face->s1->translated.x, yAC=face->s3->translated.y-face->s1->translated.y, zAC=face->s3->translated.z-face->s1->translated.z; const int diviseur_commun=(xAB*yAC-yAB*xAC); //(multiplier par 10000) const int fact_1=(10000*yAC)/diviseur_commun, fact_2=(10000*xAC)/diviseur_commun; const int fact_3=(10000*xAB)/diviseur_commun, fact_4=(10000*yAB)/diviseur_commun; const int r_xAB=face->s2->rotated.x-face->s1->rotated.x, r_yAB=face->s2->rotated.y-face->s1->rotated.y; const int r_xAC=face->s3->rotated.x-face->s1->rotated.x, r_yAC=face->s3->rotated.y-face->s1->rotated.y; const int r_diviseur_commun=(r_xAB*r_yAC-r_yAB*r_xAC); const int r_fact_1=(10000*r_yAC)/r_diviseur_commun, r_fact_2=(10000*r_xAC)/r_diviseur_commun; const int r_fact_3=(10000*r_xAB)/r_diviseur_commun, r_fact_4=(10000*r_yAB)/r_diviseur_commun; for (int y=ymin; y<=ymax; y++) { // détermination du xmin et du xmax de la ligne int tx1,tx2; for (int t=0;t<3;t++) {if (get_x(y,&cotes[t],&tx1)) break;} for (int t=0;t<3;t++) {if (get_x(y,&cotes[t],&tx2)&&tx1!=tx2) break;} const int txmin=max(min(tx1,tx2),0), txmax=min(max(tx1,tx2),127); for (int x=txmin; x<=txmax; x++) { int xcalc,ycalc,vx,vy,vz,z,rx,ry; // initialisation des variables temporaires au calcul de vx, vy xcalc=x-face->s1->translated.x; ycalc=y-face->s1->translated.y; // calcul de vx,vy, et vz sans la déformation vx=(xcalc*fact_1-ycalc*fact_2); // 0 s1->translated.z + (vx*zAB+vy*zAC)/10000; // transformation rx=x-63; // on determine le centre de l'écran comme le point X(63,31) ry=y-31; rx*=vz; // on annule la perspective ry*=vz; // deuxieme processus de calcul (avec déformation) xcalc=rx-face->s1->rotated.x; ycalc=ry-face->s1->rotated.y; vx=(xcalc*r_fact_1-ycalc*r_fact_2); vy=(ycalc*r_fact_3-xcalc*r_fact_4); z=face->s1->translated.z + (vx*zAB+vy*zAC)/10000; // Affichage du point if (FE_zbuffer_set_dist(x,y,z)) dpixel(x, y, 3*FE_get_pixel(face->texturenum,vx/1250,vy/1250)); // 3* means cast to black and white, and vx,and vy casted between 0 and 7 } } // x=Det(AM,AC)/det(AB,AC) // y=det(AM,AB)/det(AC,AB) // x=(xAM*yAC-yAM*xAC)/(xAB*yAC-yAB*xAC) // y=(xAM*yAB-yAM*xAB)/(xAC*yAB-yAC*xAB) // soit diviseur_commun = (xAB*yAC-yAB*xAC) // x=xAM*yAC/diviseur_commun-yAM*xAC/diviseur_commun // y=yAM*xAB/diviseur_commun-xAM*yAB/diciseur_commun }