2019-07-25 13:23:41 +02:00
|
|
|
#include "face.h"
|
2019-07-25 18:13:22 +02:00
|
|
|
|
|
|
|
#define min(x,y) (x<y?x:y)
|
|
|
|
#define max(x,y) (x>y?x:y)
|
2019-07-27 16:12:08 +02:00
|
|
|
#define abs(x) (x>0?x:-x)
|
2019-07-25 13:23:41 +02:00
|
|
|
|
2019-08-17 17:28:27 +02:00
|
|
|
#include <stdbool.h>
|
2019-07-26 14:39:08 +02:00
|
|
|
static bool sens_horaire(FE_face const * face)
|
2019-07-25 15:32:36 +02:00
|
|
|
{
|
2019-07-26 14:39:08 +02:00
|
|
|
int area = 0;
|
|
|
|
|
2019-08-17 17:28:27 +02:00
|
|
|
area += face->s1->translated.x * face->s2->translated.y;
|
|
|
|
area -= face->s2->translated.x * face->s1->translated.y;
|
2019-07-26 14:39:08 +02:00
|
|
|
|
2019-08-17 17:28:27 +02:00
|
|
|
area += face->s2->translated.x * face->s3->translated.y;
|
|
|
|
area -= face->s3->translated.x * face->s2->translated.y;
|
2019-07-26 14:39:08 +02:00
|
|
|
|
2019-08-17 17:28:27 +02:00
|
|
|
area += face->s3->translated.x * face->s1->translated.y;
|
|
|
|
area -= face->s1->translated.x * face->s3->translated.y;
|
2019-07-26 14:39:08 +02:00
|
|
|
|
|
|
|
return (area < 0);
|
2019-07-25 15:32:36 +02:00
|
|
|
}
|
|
|
|
|
2019-07-27 16:12:08 +02:00
|
|
|
// 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
|
|
|
|
};
|
2019-08-17 14:30:18 +02:00
|
|
|
|
2019-07-27 16:12:08 +02:00
|
|
|
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);
|
|
|
|
}
|
2019-08-17 14:30:18 +02:00
|
|
|
|
2019-07-27 16:12:08 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-08-17 17:28:27 +02:00
|
|
|
#include "texture.h"
|
|
|
|
#include "zbuffer.h"
|
|
|
|
#include <gint/display.h>
|
2019-07-25 13:23:41 +02:00
|
|
|
void FE_draw_face(FE_face const * face)
|
|
|
|
{
|
2019-08-17 17:28:27 +02:00
|
|
|
// élimination des faces cachées
|
2019-07-27 16:12:08 +02:00
|
|
|
if (sens_horaire(face)!=face->visible)
|
2019-07-25 15:32:36 +02:00
|
|
|
return;
|
2019-08-17 17:28:27 +02:00
|
|
|
|
|
|
|
// cas particuliers où la face n'est pas dans l'écran
|
2019-07-25 18:13:22 +02:00
|
|
|
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)
|
2019-07-25 15:32:36 +02:00
|
|
|
return;
|
2019-07-25 18:13:22 +02:00
|
|
|
if (face->s1->translated.y>63 && face->s2->translated.y>63 && face->s3->translated.y>63)
|
|
|
|
return;
|
2019-07-27 16:12:08 +02:00
|
|
|
if (face->s1->translated.z<=0 && face->s2->translated.z<=0 && face->s3->translated.z<=0)
|
2019-07-26 14:39:08 +02:00
|
|
|
return;
|
2019-07-27 16:12:08 +02:00
|
|
|
|
2019-08-17 17:28:27 +02:00
|
|
|
// cas où un côté est nul
|
2019-07-27 16:12:08 +02:00
|
|
|
line cotes[3];
|
2019-08-17 14:30:18 +02:00
|
|
|
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)
|
2019-07-27 16:12:08 +02:00
|
|
|
return;
|
2019-07-25 18:13:22 +02:00
|
|
|
|
2019-08-17 17:28:27 +02:00
|
|
|
const int32_t y1 = max(min(face->s1->translated.y, min(face->s2->translated.y, face->s3->translated.y)), 0);
|
|
|
|
const int32_t y2 = min(max(face->s1->translated.y, max(face->s2->translated.y, face->s3->translated.y)), 63);
|
|
|
|
|
|
|
|
// ressources pour déformer les textures
|
|
|
|
const int32_t 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 int32_t 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 int32_t diviseur_commun=(xAB*yAC-yAB*xAC);
|
|
|
|
const int fact_1=(1024*yAC)/diviseur_commun, fact_2=(1024*xAC)/diviseur_commun;
|
|
|
|
const int fact_3=(1024*xAB)/diviseur_commun, fact_4=(1024*yAB)/diviseur_commun;
|
2019-07-27 16:12:08 +02:00
|
|
|
|
2019-08-17 17:28:27 +02:00
|
|
|
for (int y=y1; y<=y2; y++)
|
2019-07-25 18:13:22 +02:00
|
|
|
{
|
2019-08-02 10:18:29 +02:00
|
|
|
// détermination du xmin et du xmax de la ligne
|
2019-08-17 17:28:27 +02:00
|
|
|
int tx1, tx2;
|
2019-07-27 16:12:08 +02:00
|
|
|
for (int t=0;t<3;t++)
|
2019-08-17 17:28:27 +02:00
|
|
|
if (get_x(y,&cotes[t],&tx1))
|
|
|
|
break;
|
2019-07-27 16:12:08 +02:00
|
|
|
for (int t=0;t<3;t++)
|
2019-08-17 17:28:27 +02:00
|
|
|
if (get_x(y,&cotes[t],&tx2)&&tx1!=tx2)
|
|
|
|
break;
|
2019-07-27 16:12:08 +02:00
|
|
|
const int txmin=max(min(tx1,tx2),0), txmax=min(max(tx1,tx2),127);
|
2019-08-02 10:18:29 +02:00
|
|
|
|
|
|
|
for (int x=txmin; x<=txmax; x++)
|
2019-07-25 18:13:22 +02:00
|
|
|
{
|
2019-08-17 14:30:18 +02:00
|
|
|
// vx et vy coordonnées transformées pour l'accès à la texture
|
|
|
|
// z distance du point visible (distance non transformée)
|
2019-08-17 14:09:45 +02:00
|
|
|
int32_t vx, vy, z;
|
2019-08-16 17:35:32 +02:00
|
|
|
// calcul de vx, vy
|
2019-08-17 14:30:18 +02:00
|
|
|
const int32_t xcalc = x-face->s1->translated.x, ycalc = y-face->s1->translated.y;
|
|
|
|
vx=(xcalc*fact_1-ycalc*fact_2); // 0 <vx< 10_000
|
2019-08-02 10:18:29 +02:00
|
|
|
vy=(ycalc*fact_3-xcalc*fact_4); // idem
|
|
|
|
|
2019-08-17 17:28:27 +02:00
|
|
|
z=face->s1->translated.z + (vx*zAB+vy*zAC)/1024; // calcul de z non corrigé >> fonctionnel
|
|
|
|
if (z>0)
|
|
|
|
{
|
|
|
|
vx = (8 * vx * face->s1->translated.z)
|
|
|
|
/
|
|
|
|
(1024 * face->s1->translated.z + (1024 - vx) * face->s2->translated.z);
|
2019-08-17 14:30:18 +02:00
|
|
|
|
2019-08-17 17:28:27 +02:00
|
|
|
vy = (8 * vy * face->s1->translated.z)
|
|
|
|
/
|
|
|
|
(1024 * face->s1->translated.z + (1024 - vy) * face->s3->translated.z);
|
|
|
|
|
|
|
|
// Affichage du point
|
|
|
|
if (FE_zbuffer_set_dist(x,y,z))
|
|
|
|
dpixel(x, y, 3*FE_get_pixel(face->texturenum, vx, vy)); // 3* means cast to black and white, and vx,and vy casted between 0 and 7
|
|
|
|
}
|
2019-07-25 18:13:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2019-08-17 14:09:45 +02:00
|
|
|
}
|